xwjie/VueStudyNote

08 支持指令2

xwjie opened this issue · 0 comments

xwjie commented

这里的实现和vue不太一样

修改生成的渲染函数的value为表达式

生成渲染函数的时候,使指令的value改成一个表达式(如 value:(count>1) ),指令的update回调函数里面,就可以直接拿到指令的value来计算。

需要注意没有表达式的场景(就是没有=,如 x-red 指令)的场景。这个时候直接赋值一个true即可。

D:\OutPut\VUE\VueStudyNote\Xiao\src\compiler\ast2render.js

/**
 * 解析指令
 * @param {*} node
 */
function getDirectiveStr(node: any) {
  let dirs = node.directives

  let str = '';

  if (dirs && dirs.length > 0) {
    str += 'directives:['

    // why not use for..in, see eslint `no-restricted-syntax`
    dirs.forEach(dir => {
      str += '{'
      for (let key in dir) {
        str += JSON.stringify(key) + ':'

        const val = dir[key]

        // 把value的值修改为表达式,render的时候就可以计算
        if (key == 'value') {
          // 如果有value(表达式)
          if (val) {
            str += `(${val}),`
          }
          else {
            str += 'true,'
          }
        } else {
          str += JSON.stringify(val) + ','
        }
      }
      str += '},'
    })

    str += '],'
  }

  return str;
}

最终生成的render函数

注意value为 "value":(see)"value":(count>1),这样直接 snabbdom.h函数之后,函数返回的虚拟节点上的 value 就是计算后的值。

(function() {
with(this){return 
h("div",{attrs:{},},[h("h1",{attrs:{},},["show指令",]),
h("div",{attrs:{},directives:[{"name":"x-show","rawName":"x-show","value":(see),"arg":null,"modifiers":undefined,},],},["当see不为false的时候,这个元素会显示",]),
h("h1",{attrs:{},},["show指令 count大于1",]),
h("div",{attrs:{},directives:[{"name":"x-show","rawName":"x-show","value":(count>1),"arg":null,"modifiers":undefined,},],},["当see不为false的时候,这个元素会显示",]),])}
})

当有指令的时候,设置实例到虚拟节点的context

D:\OutPut\VUE\VueStudyNote\Xiao\src\lifecycle.js

/**
 * [递归设置] 如果当前节点有指令,增设置context到当前节点
 * 注意: vue不是这样实现的,vue只有根节点有context
 * @param {*} vnode
 * @param {*} vm
 */
function setContext(vnode: any, vm: Xiao) {
  // 如果当前节点有指令,设置context
  if (!vnode.context) {
    if (vnode.data && vnode.data.directives) {
      vnode.context = vm
    }
  }

  if (vnode.children) {
    vnode.children.forEach(function (e) {
      setContext(e, vm)
    }, this)
  }
}

默认的show指令

Xiao.directive('show', function (el, binding) {
    const originalDisplay = el.__vOriginalDisplay =
      el.style.display === 'none' ? '' : el.style.display

    el.style.display = binding.value ? originalDisplay : 'none'
  })