Vue 源码学习

Vue 源码学习

资料
熟悉设计模式
AST 抽象语法树
htmlParse 解析器
wue 仿Vue实现
Vue.js 源码学习笔记
Virtual DOM patching algorithm based on Snabbdom

以下是个人学习vue 源码的先后学习过程:(以下面顺序学习会轻松很多,循序渐进)

  1. 学习正则表达式

  2. 学习js 设计模式,重点观察者模式 50行代码的MVVM,感受闭包的艺术

  3. 了解AST 抽象语法树的概念,并通过博文开头的资料 htmlParse解析器 中分析parse 原理

  4. 参看githut 上的开源仿 Vue 实现项目 wue 仿Vue实现Vue 源码注释版

  5. 查看调试vue.js 2.1.3 版本单文件脚本 https://cdn.bootcss.com/vue/2.1.3/vue.js

步骤5 举例:单步调试如下代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <!-- 版本:vue 2.1.3 -->
  <script type="text/javascript" src="./vue.js"></script>
</head>
<body>
  
  <div id="app">
    <div><span v-text="reverse"></span></div>
    <div><span v-text="tip"></span></div>
    <div><bar :age="info.age"></bar></div>
  </div>
  
  <script>
      let bar = {
        name: 'Bar',
        template: '<div><span>name: {{name}}</span><br/><span>age: {{age}}</span></div>',
        props: [ 'age' ],
        created() {
          console.log('child created.')
        },
        data() {
          return {
            name: 11
          }
        }
      }

      var app = new Vue({
        el: "#app",
        components: {
          bar: bar
        },
        created() {
          console.log('created.')
        },
        data() {
          return {
            message: "hello.",
            info: {
              age: 12
            }
          }
        },
        computed: {
          reverse() {
            return this.message.split("").reverse().join("")
          },
          tip() {
            return `${this.message} world.`
          }
        }
      })

      setTimeout(()=>{
        app.info.age = 23
      }, 400)
  </script>
  
</body>
</html>

编译过程中会生成render code 如下:

_h(
   'div',
   {attrs:{"id":"app"}},
   [
    _h(
       'div',
       [
        _h('span',{domProps:{"textContent":_s(reverse)}})]),
        " ",
        _h(
           'div',
           [_h('span',{domProps:{"textContent":_s(tip)}})]
          ),
        " ",
        _h('div',[_h('bar',{attrs:{"age":info.age}})]
      )
   ]
)

其中_h_s 方法分别对应:

// shorthands used in render functions
Vue.prototype._h = createElement;
// toString for mustaches
Vue.prototype._s = _toString;
function createElement (
  tag,
  data,
  children
) {
  if (data && (Array.isArray(data) || typeof data !== 'object')) {
    children = data;
    data = undefined;
  }
  // make sure to use real instance instead of proxy as context
  return _createElement(this._self, tag, data, children)
}

function _createElement (
  context,
  tag,
  data,
  children
) {
  if (data && data.__ob__) {
    "development" !== 'production' && warn(
      "Avoid using observed data object as vnode data: " + (JSON.stringify(data)) + "\n" +
      'Always create fresh vnode data objects in each render!',
      context
    );
    return
  }
  if (!tag) {
    // in case of component :is set to falsy value
    return emptyVNode()
  }
  // support single function children as default scoped slot
  if (Array.isArray(children) &&
      typeof children[0] === 'function') {
    data = data || {};
    data.scopedSlots = { default: children[0] };
    children.length = 0;
  }
  if (typeof tag === 'string') {
    var Ctor;
    var ns = config.getTagNamespace(tag);
    if (config.isReservedTag(tag)) {
      // platform built-in elements
      return new VNode(
        tag, data, normalizeChildren(children, ns),
        undefined, undefined, ns, context
      )
    } else if ((Ctor = resolveAsset(context.$options, 'components', tag))) {
      // component
      return createComponent(Ctor, data, context, children, tag)
    } else {
      // unknown or unlisted namespaced elements
      // check at runtime because it may get assigned a namespace when its
      // parent normalizes children
      var childNs = tag === 'foreignObject' ? 'xhtml' : ns;
      return new VNode(
        tag, data, normalizeChildren(children, childNs),
        undefined, undefined, ns, context
      )
    }
  } else {
    // direct component options / constructor
    return createComponent(tag, data, context, children)
  }
}
/**
 * Convert a value to a string that is actually rendered.
 */
function _toString (val) {
  return val == null
    ? ''
    : typeof val === 'object'
      ? JSON.stringify(val, null, 2)
      : String(val)
}

(未完,待续)

猜你喜欢

转载自blog.csdn.net/Jacoh/article/details/89135214