读vue源码笔记

gobal-api/index.js

initMixin(Vue) 对Vue.mixin方法进行定义,参数为要混入到Vue.options对象的对象。

Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }

gobal-api/use.js
这段源码简单,global-api/use.js中,this._installedPlugins储存插件的数组。

export function initUse (Vue: GlobalAPI) {
  Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
   // 已经执行过了插件暴露的方法就不需要执行了
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }
    // additional parameters,数组中的参数后移一位。
    const args = toArray(arguments, 1)
    args.unshift(this)
    // 第一个参数是vue本身了
    if (typeof plugin.install === 'function') {
    // 插件要实现install函数,或者本身就是函数,
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }
使用的过程中:vue.use(vue-router); vue-router 是个函数,在window下执行plugin.apply(null, args)。第一个参数就是Vue。然后把函数推入installedPlugins数组中。
mergeOptions是utils/options.js
export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {
  if (process.env.NODE_ENV !== 'production') {
    //核实子对象中components的名字合法
    checkComponents(child)
  }

  if (typeof child === 'function') {
    child = child.options
  }
  // 对options中的props、inject、 directive格式化对象
  normalizeProps(child, vm)
  normalizeInject(child, vm)
  normalizeDirectives(child)
  // extends、mixins 格式化变成对象
  const extendsFrom = child.extends
  if (extendsFrom) {
    parent = mergeOptions(parent, extendsFrom, vm)
  }
  if (child.mixins) {
    for (let i = 0, l = child.mixins.length; i < l; i++) {
      parent = mergeOptions(parent, child.mixins[i], vm)
    }
  }
  const options = {}
  // 对 vm.constructor的成员和目前options成员的key进行自定义化处理,一般不会自定义化处理的。
  let key
  for (key in parent) {
    mergeField(key)
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key)
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key)
  }
  return options
}

 initState

// 对vm实例的props,method、data、computed、watch初始化。
在beforeCreated 和created 钩子函数之间执行
export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}
export function pluckModuleFunction<F: Function> (
  modules: ?Array<Object>,
  key: string
): Array<F> {
  return modules
    ? modules.map(m => m[key]).filter(_ => _)
    : []
}
//看看下面的例子就明白了,map返回经过每个数组成员函数处理的的值的数组,filter返回每个成员经过函数处理返回为true的数组。
function A (modules, key) {
  return modules
        ? modules.map(m => m[key]).filter(_ => _)
        : []
 }
// map 处理返回[undefind, ['33']], filter返回['33'] let a
= [{ '1': '11', '2': '22' },{ '1': '11', '3': '33' }] console.log(A(a, '3')) //['33']

/compiler/helpers

// 改变AST树的数据,如果removeFromMap为true, 则把AST树的attrsMap元素删除。最终返回name属性值。
export function getAndRemoveAttr (
  el: ASTElement,
  name: string,
  removeFromMap?: boolean
): ?string {
  let val
  if ((val = el.attrsMap[name]) != null) {
    const list = el.attrsList
    for (let i = 0, l = list.length; i < l; i++) {
      if (list[i].name === name) {
        list.splice(i, 1)
        break
      }
    }
  }
  if (removeFromMap) {
    delete el.attrsMap[name]
  }
  return val
}

 /parser/html-parser.js

const start = html.match(startTagOpen) 
// match匹配,/^<((?:[a-zA-Z_][\w\-\.]*\:)?[a-zA-Z_][\w\-\.]*)/ 
// ?:忽略分组
if (start) {
  const match = {
    tagName: start[1], 
    attrs: [],
    start: index
  }
  advance(start[0].length)
  let end, attr
  // /^\s*(\/?)>/ 匹配 空格> 或者 空格/>
  while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
    advance(attr[0].length)
    match.attrs.push(attr)
  }
  // 可能是"/"
  if (end) {
    match.unarySlash = end[1]
    advance(end[0].length)
    match.end = index
    return match
  }
}

options.start 

start (tag, attrs, unary, start, end) {
      // check namespace.
      // inherit parent ns if there is one
      const ns = (currentParent && currentParent.ns) || platformGetTagNamespace(tag)

      // handle IE svg bug
      /* istanbul ignore if */
      if (isIE && ns === 'svg') {
        attrs = guardIESVGBug(attrs)
      }

      let element: ASTElement = createASTElement(tag, attrs, currentParent)
      if (ns) {
        element.ns = ns
      }

      if (process.env.NODE_ENV !== 'production') {
        if (options.outputSourceRange) {
          element.start = start
          element.end = end
          element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
            cumulated[attr.name] = attr
            return cumulated
          }, {})
        }
        attrs.forEach(attr => {
          if (invalidAttributeRE.test(attr.name)) {
            warn(
              `Invalid dynamic argument expression: attribute names cannot contain ` +
              `spaces, quotes, <, >, / or =.`,
              {
                start: attr.start + attr.name.indexOf(`[`),
                end: attr.start + attr.name.length
              }
            )
          }
        })
      }

      if (isForbiddenTag(element) && !isServerRendering()) {
        element.forbidden = true
        process.env.NODE_ENV !== 'production' && warn(
          'Templates should only be responsible for mapping the state to the ' +
          'UI. Avoid placing tags with side-effects in your templates, such as ' +
          `<${tag}>` + ', as they will not be parsed.',
          { start: element.start }
        )
      }

      // apply pre-transforms
      for (let i = 0; i < preTransforms.length; i++) {
        element = preTransforms[i](element, options) || element
      }

      if (!inVPre) {
        processPre(element)  //处理v-pre,不参与编译。
        if (element.pre) {
          inVPre = true
        }
      }
      // 特定平台设置的不需要编译标签,默认没有。
      if (platformIsPreTag(element.tag)) {
        inPre = true
      }
      //  如果是不需要参与编译的element
      if (inVPre) {
        // ele得到一个数组,ele.attrs = []
        processRawAttrs(element)
      } else if (!element.processed) {
        // structural directives
        processFor(element)
        processIf(element)
        processOnce(element)
      }

      if (!root) {
        root = element
        if (process.env.NODE_ENV !== 'production') {
          //根节点不能有v-for,template,slot
          checkRootConstraints(root)
        }
      }
      //不是自闭标签
      if (!unary) {
         // 类似指针,形成链表,start 的核心代码
        currentParent = element
        stack.push(element)
      } else {
        closeElement(element)
      }
    },

 

 

 

 


posted @ 2019-02-28 10:31  anthonyliu  阅读(278)  评论(0编辑  收藏  举报