当前位置: 代码迷 >> 综合 >> 【Vue高级】MVVM实现原理(三)—— 编译模板【Compile】
  详细解决方案

【Vue高级】MVVM实现原理(三)—— 编译模板【Compile】

热度:36   发布时间:2023-11-29 13:18:35.0

Compile

Compile主要做的事情是解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head><body id="app"><div>a的值:{
   {a.a}}</div><p>b的值 {
   {b}}</p>
</body>
<script src="./mvvm.js"></script>
<script>let vue = new Vue({el:'#app',data:{a:{a:"是a啊"},b:'是b啊'}})console.log(vue)
</script>
</html>

new Vue的时候,会调用  指令解析器,

指令解析器中的方法会把"#app"里面的内容递归处理成文档碎片,放到内存中去,

在内存中,递归文档碎片(虚拟节点),利用正则把“{ {}}”替换成data中对应的数据,

【 此处只是简单实现,没有patch】

然后把内存中被处理后的文档碎片,放回页面,展示出来

function Vue(options={}){this.$options = options;//将所有属性挂载在optionsvar data = this._data = this.$options.data;//观察者observe(data)//观察完之后,this代理了this._data  数据代理for(let key in data){Object.defineProperty(this,key,{enumerable:true,get(){return this._data[key];//获取到新值},set(newVal){this._data[key] = newVal//这里触发观察者【再次执行Observe(data)中的set方法】}})}//编译模板【指令解析器】new Compile(options.el,this)
}function Compile(el,vm){//el代表替换的范围vm.$el = document.querySelector(el);/*获取到元素以后,把里面的子元素都拿到,需要移动到内存中操作,所以需要创建文档碎片*///创建一个虚拟的节点对象,或者说,是用来创建文档碎片节点。它可以包含各种类型的节点,在创建之初是空的。let fragment = document.createDocumentFragment();//把app里面的内容都放到内存中,此时页面上为空白while(child  = vm.$el.firstChild){fragment.appendChild(child)}//递归 替换虚拟节点中的 {
   {}}replace(fragment)function replace(fragment){Array.from(fragment.childNodes).forEach((node)=>{//循环每一层let text = node.textContent;let reg = /\{\{(.*)\}\}///nodeType为3时,是文本内容if(node.nodeType === 3 && reg.test(text)){//console.log(RegExp.$1) // a.a vm.blet arr = RegExp.$1.split('.') //[a,a]let val = vm;arr.forEach((k)=>{val = val[k]})node.textContent = text.replace(/\{\{(.*)\}\}/,val)}if(node.childNodes){replace(node)}})}//把内存中的文档碎片放回到页面上,此时页面上的东西显示回来vm.$el.appendChild(fragment)}//vm.$options
function Observe(data){//这里写我们的主要逻辑for(let key in data){//把data属性通过object.defineProperty的方式定义let val = data[key]observe(val)//递归 使data的中的每个属性都被Object.defineProperty处理Object.defineProperty(data,key,{enumerable:true,get(){return val;},set(newVal){//更改值得时候if(newVal===val){//设置的值和以前是一样的东西return;}val = newVal;//如果以后在获取值得时候,将刚才设置的值丢回去observe(newVal)}})}
}
function observe(data){if (typeof data !== 'object'){return }return new Observe(data)
}

  相关解决方案