ms-if是属于流程绑定的一种,如果表达式为真值那么就将当前元素输出页面,不是就将它移出DOM树。它的效果与上一章节的ms-visible效果看起来相似的,但它会影响到:empty伪类,并能更节约性能。ms-if还有一个分支,叫ms-if-loop,它是配合ms-repeat绑定使用,因此以后再说。
我们可以通过以下例子比较一下两者:
<!DOCTYPE HTML> <html> <head> <title>ms-if</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="avalon.js" ></script> <script> var vmodel = avalon.define({ $id: "test", object: {} }) setTimeout(function() { vmodel.object = {id: "132", message: "显示!!"} }, 3000) setTimeout(function() { vmodel.object = {} }, 5000) </script> </head> <body> <div ms-controller="test" > 这是比较输出结果:{{object.id != null}} <div ms-visible="object.id != null"> 这是visible的: <span>{{object.message}}</span> </div> <div ms-if="object.id != null"> 这是if的: <span>{{object.message}}</span> </div> </div> </body> </html>
ms-if的实现比ms-visible复杂多了,如果一开始扫描到此元素,计算其值为false,它就不会再扫描里面的元素,并且立即移除此元素。这正是它比ms-visible性能更优的关键。为了能在重新插入DOM时找到正确的位置,avalon还得创建一个注释节点做路标。而被移除的元素是放在一个叫ifSanctuary的DIV中,方便统一管理。
"if": function(data, vmodels) {//这里是第一次扫描时的执行函数 var elem = data.element elem.removeAttribute(data.name) if (!data.placehoder) { data.msInDocument = data.placehoder = DOC.createComment("ms-if") } data.vmodels = vmodels parseExprProxy(data.value, vmodels, data) }, "if": function(val, elem, data) {//这是每次改变ViewModel对应属性时的执行函数 var placehoder = data.placehoder if (val) { //插回DOM树 if (!data.msInDocument) { data.msInDocument = true if(placehoder.parentNode) placehoder.parentNode.replaceChild(elem, placehoder) } } if (rbind.test(elem.outerHTML.replace(rlt, "<").replace(rgt, ">"))) { scanAttr(elem, data.vmodels) } } else { //移出DOM树,放进ifSanctuary DIV中,并用注释节点占据原位置 if (data.msInDocument) { data.msInDocument = false if(elem.parentNode) elem.parentNode.replaceChild(placehoder, elem) } placehoder.elem = elem ifSanctuary.appendChild(elem) } } },
最后,我们还是用切换卡例子结束本章吧。
<!DOCTYPE html> <html> <head> <title>TODO supply a title</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width"> <script src="avalon.js"></script> <script > var model = avalon.define({ $id: "test", currentIndex: 0, toggle: function(index) { model.currentIndex = index } }) </script> <style> button{ 150px; height:30px; line-height: 30px; text-align: center; } .ms-tabs{ border:1px solid violet; 430px; padding:5px; height: 200px; } </style> </head> <body ms-controller="test" > <button ms-click="toggle(0)">触发器1</button> <button ms-click="toggle(1)">触发器2</button> <button ms-click="toggle(2)" >触发器3</button> <div class="ms-tabs" ms-if="currentIndex === 0">切换卡1<br/>其他内容</div> <div class="ms-tabs" ms-if="currentIndex === 1">切换卡2<br/>及司徒正美</div> <div class="ms-tabs" ms-if="currentIndex === 2">切换卡3<br/>最后一个了</div> </body> </html>