[vue源码笔记09]vue2.x的模板编译之optimize

218 阅读2分钟

function optimize

function optimize (root: ?ASTElement, options: CompilerOptions) {
  if (!root) return
  // 函数,用于判断传入参数val是否包含在'type,tag,attrsList,attrsMap,plain,parent,children,attrs,staticClass,staticStyle'
  isStaticKey = genStaticKeysCached(options.staticKeys || '')
  // 函数,用于判断传入参数val是否是原生html标签或者svg标签
  isPlatformReservedTag = options.isReservedTag || no
  // first pass: mark all non-static nodes.
  markStatic(root)
  // second pass: mark static roots.
  markStaticRoots(root, false)
}

genStaticKeysCached

function cached<F: Function> (fn: F): F {
  // 闭包变量cached用于缓存
  const cache = Object.create(null)
  return (function cachedFn (str: string) {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }: any)
}
// 传入str转为map对象'a,b,c' --> {a: true, b: true, c: true}
// 返回一个方法,用来在map对象中查找是否包含传入属性
function makeMap (
  str: string,
  expectsLowerCase?: boolean // 是否需要先转化为小写再查找
): (key: string) => true | void {
  const map = Object.create(null)
  const list: Array<string> = str.split(',')
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true
  }
  return expectsLowerCase
    ? val => map[val.toLowerCase()]
    : val => map[val]
}
// 生成一个方法,传入一个参数val,查看val是否包含在'type,tag,attrsList,attrsMap,plain,parent,children,attrs,staticClass,staticStyle'
genStaticKeysCached = cached(function genStaticKeys (keys: string): Function {
  return makeMap(
    'type,tag,attrsList,attrsMap,plain,parent,children,attrs' +
    (keys ? ',' + keys : '')
  )
})

markStatic

function markStatic (node: ASTNode) {
  // 判断是否是静态节点
  node.static = isStatic(node)
  if (node.type === 1) {
    if (
      !isPlatformReservedTag(node.tag) &&
      node.tag !== 'slot' &&
      node.attrsMap['inline-template'] == null
    ) {
      return
    }
    // 遍历children,并标记其是否是静态节点
    for (let i = 0, l = node.children.length; i < l; i++) {
      const child = node.children[i]
      markStatic(child)
      // 如果发现子节点非static,则node也是非static
      if (!child.static) {
        node.static = false
      }
    }
    // 如果包含if表达式,则判断其是否是静态的
    if (node.ifConditions) {
      for (let i = 1, l = node.ifConditions.length; i < l; i++) {
        const block = node.ifConditions[i].block
        markStatic(block)
        // 如果有一个表达式非static,则node非static
        if (!block.static) {
          node.static = false
        }
      }
    }
  }
}

isStatic

// 文本节点、pre、无动态属性标签和指令的非内建标签将被标记为静态
function isStatic (node: ASTNode): boolean {
  // 表达式节点(如插值表达式)
  if (node.type === 2) {
    return false
  }
  // 静态文本节点
  if (node.type === 3) {
    return true
  }
  return !!(node.pre || (
    !node.hasBindings && // 无动态绑定
    !node.if && !node.for && // 无 v-if or v-for or v-else
    !isBuiltInTag(node.tag) && // 非内建标签,如slot component
    isPlatformReservedTag(node.tag) && // 为原生标签,非自定义组件标签
    !isDirectChildOfTemplateFor(node) && // 非这种情况:template标签,且该标签包含v-for指令
    // node的所有属性都是static的:"type、tag、attrsList、attrsMap、plain、parent、children、attrs、staticClass、staticStyle"
    Object.keys(node).every(isStaticKey)
  ))
}

markStaticRoots

// 标签节点是否为staticRoot
function markStaticRoots (node: ASTNode, isInFor: boolean) {
  // 标签节点
  if (node.type === 1) {
    if (node.static || node.once) {
      node.staticInFor = isInFor
    }
    // 如果node为静态节点,且不只包含一个静态文本节点,则将其标记为staticRoot
    if (node.static && node.children.length && !(
      node.children.length === 1 &&
      node.children[0].type === 3
    )) {
      node.staticRoot = true
      return
    } else {
      node.staticRoot = false
    }
    // 遍历node.children,标记其是否为staticRoot
    if (node.children) {
      for (let i = 0, l = node.children.length; i < l; i++) {
        markStaticRoots(node.children[i], isInFor || !!node.for)
      }
    }
    // 遍历if表达式节点,标记其是否为staticRoot
    if (node.ifConditions) {
      for (let i = 1, l = node.ifConditions.length; i < l; i++) {
        markStaticRoots(node.ifConditions[i].block, isInFor)
      }
    }
  }
}

对astElement做了哪些optimize

遍历astElement

  1. 检测每个element是否是static,并标记element.static
  2. 检测每个element是否为staticRoot,并标记element.staticRoot