xwjie / VueStudyNote

vue学习笔记

Home Page:https://xwjie.github.io/VueStudyNote/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

15 实现if/else指令

xwjie opened this issue · comments

测试代码

<!DOCTYPE html>
<html>
<head>
	<title>Xiao框架之helloworld</title>
	<script src="../dist/xiao.js"></script>
</head>
<body>
<h1>if, else指令测试</h1>
<div id="demo1">
<h1 x-if="ok">Yes</h1>
<h1 x-else>No</h1>
<h1 x-if="ok">只有if</h1>
</div>
<script>
var app = new Xiao({
	data:{
		ok:true
	}
});

app.$mount("#demo1");

setTimeout(function(){
	app.ok = false;
}, 2000);

</script>

</body>
</html>

实现

if指令和show指令不一样,我们最终需要把渲染函数修改为类似这样的?三元表达式。注意:这里不用用if-else,必须用?表达式。

要注意处理只有if没有else的场景。

(function() {
with(this){return h("div",{props:{"id":"demo1",},},
[(ok)?h("h1",{props:{"x-if":"ok",},directives:[],},["Yes"]):h("h1",{props:{"x-else":"",},directives:[],},["No"]),
(ok)?h("h1",{props:{"x-if":"ok",},directives:[],},["只有if"]):"",])}
})

修改render生成函数

function createRenderStrElemnet(node: any): string {
  log('createRenderStrElemnet', node)

  // snabbdom 的语法,类名放在tag上。'div#container.two.classes'
  let tag = getTagAndClassName(node)

  let str: string = `h(${tag},{`

  // 解析属性
  str += genAttrStr(node)

  // 解析指令
  str += getDirectiveStr(node)

  str += "}"

  if (node.children) {
    str += ',['

    // 保存上一次if指令,处理只有if没有else的场景
    let lastDir

    node.children.forEach(child => {
      // 如果这里节点有if指令
      let dir = getIfElseDirective(child)

      console.log('dir:', dir)

      if (dir) {
        if (dir.name == 'if') {
          str += `(${dir.exp})?`
          lastDir = dir
        } else if (dir.name == 'else') {
          str += `:`
        }
      }

      str += createRenderStr(child)

      if (dir) {
        if (dir.name == 'else') {
          str += `,`
          lastDir = null
        }
      }
      else if (lastDir) {
        str += `:"",`
        lastDir = null
      }
    })

    if (lastDir) {
      str += `:"",`
    }

    str += ']'
  }

  str += ')'

  return str
}


/**
 * 得到该节点的if/else指令
 * @param {*} node
 */
function getIfElseDirective(node: any): ?Object {
  let attrs = node.attrsMap

  if (!attrs) {
    return
  }

  let dir

  // why not use for..in, see eslint `no-restricted-syntax`
  Object.keys(attrs).some(attrname => {
    // 如果是数据绑定,则后面的是表达式
    if (attrname == 'x-if') {
      dir = {
        name: 'if',
        exp: attrs[attrname].trim()
      }
      return true
    } else if (attrname == 'x-else') {
      dir = {
        name: 'else'
      }
      return true
    }

    return false
  })

  return dir
}