自各个mvvm框架出现和流行以来,他们都实现了两个新的概念及功能:数据双向绑定和虚拟dom。网上对于这两个概念的阐述很多很全面,这里仅对它们的原理和应用场景进行探究和记录,希望更接地气的理解和应用这两个新概念。
1.数据双向绑定
先说说数据双向绑定的应用场景.借之前的文章《从web技术的发展探索mvvm模式的形成》来看,前端数据渲染从前端模板技术发展到viewModel以后,拿到数据后往页面的渲染,不再需要我们始终按照流程来操作dom,更好的方式是搭建好数据和视图的关系,通过数据去驱动视图的渲染。
当然用户对视图的操作也驱动了数据的变更。viewModel绑定了来自视图方面和来自数据方面的两方面驱动,这就可以理解为数据双向绑定的核心。先来看一个实时显示数据的autoComplete效果:
//通过触发input的change事件来发出jsonp请求,请求数据并发送回调函数名
function ck(){
var script = document.createElement("script");
var word = oInput.value;
var src = 'http://suggestion.baidu.com/su?wd='+word+'&cb=succ';
script.setAttribute('src',src);
script.id = "aa";
if(document.getElementById("aa")){
document.getElementsByTagName('body')[0].removeChild(document.getElementById("aa"));
}
document.getElementsByTagName('body')[0].appendChild(script);
}
if(ie){
oInput.onpropertychange = function(){ //IE
ck()
}
}
else{
oInput.addEventListener("input",ck,false)
}
//在jsonp的回调函数中执行后续视图操作
function succ(json){ ///... }
通过input的input事件,监听value值的变化,然后驱动数据,数据返回后通过jsonp的回调函数执行视图渲染。此时数据是通过input事件单方面驱动的。同样的我们可以双向绑定的方式实现类似效果。通过Object.defineProperty方法的存取器setter和getter,来监听某个对象属性的变更,并触发变更后的回调函数,如下:
<input type="text" id="input1"> <p id="p1"></p> function viewRender(val){ document.getElementById('p1').innerHTML = val; } function viewModel(){ var list = ''; Object.defineProperty(this,"list",{ get:function(){return list;}, set:function(val){ list = val; oInput.value = val; //修改视图 viewRender(val); //回调 } }); } var ie = !-[1,]; var oInput = document.getElementById('input1'); var oData = new viewModel(); if(ie){ oInput.onpropertychange = function(){ //IE oData.list = oInput.value; } } else{ oInput.addEventListener("input",function(){ oData.list = oInput.value; },false) }
-----实现数据双向绑定,从数据方向驱动
2.虚拟dom
前端请求到数据然后渲染或更新页面视图时,需要操作大量的dom.以往修改dom的方式,一种是appendChild,一种是innerHTML,它们相比性能相差不大,innerHTML略胜一些.修改时都对dom做了的大量操作,引发浏览器的重构和重绘,非常影响页面性能。
虚拟dom方案是在页面渲染dom树时,先在内存中模拟一个dom树,然后比较两颗dom树的不同,再将不同的地方渲染进dom,控制页面重构重绘的范围.这里我们对比下两种方案在渲染dom时,dom树的重构范围。
//将数据oData渲染进下面的视图 var oData = {"o_name":"xiaoming","o_age":19,"o_sex":"男","o_email":"222@qq.com","o_address":"北大街"} <div id="box"> <div class="o_tit">个人中心</div> <div class="o_name"> 您好:<span>admin</span> </div> <div class="o_info"> <p class="o_age">20</p> <p class="o_sex">男</p> <p class="o_email">111@qq.com</p> <p class="o_address">南大街</p> </div> </div>
-----点击测试
当我们点击渲染新数据后,可以发现页面渲染时dom的修改范围很大,有些数据一样的地方和不需要刷新的地方都被重构了,并且重复点击渲染时dom也在重复渲染:
接着我们利用vue来渲染同样的结构:点击测试
此时我们可以清楚的看到,用户中心和性别这两处没有被重构.并且当我们重复点击渲染按钮时也不会重复重构。当我们渲染大量数据,且数据复杂不规律时,虚拟dom更能显示出其优势: