Vue双向绑定实现原理(二)数据代理和编译模板

2.1.2 模板编译

此时,便可通过vm.属性名获得vm._data.属性名,要实现的功能就是视图和数据连接在一起,数据需要显示在网页上,进行交互,这一步应该就是“数据驱动组件”。

说个题外话,思路到这里,MVVM的架构就非常清晰。

Model VM View

利用VM去连接Model 和 View,VM拥有Model 和 View的实例,也就是匿名对象上的data 和 传递过来的el变量字符串"#app","#app"是一个字符串,它怎么会是View的实例?

 vm.$el = document.querySelector("#app")

此时vm拥有了一颗DOM树,只要递归这棵DOM树,就可拥有树下View的节点,便可以操作View。

View 和 Model分离,他们只通过vm去操控对方,而vm在此中扮演的角色就成了一位主持人。

一场表演就是一个作品,一个产品也是一个作品,节目制作的过程中,主持人会去推进整个流程,同时也隔离观众和嘉宾,降低观众和嘉宾的耦合性,毕竟,距离产生美。

当观众需要向嘉宾述说喜欢时,观众会告诉主持人,我很喜欢这个嘉宾,主持人接受到这个信息,告诉嘉宾,嘉宾接受到观众的信息,他很高兴,于是跳了一只舞,这可以理解为视图接受到vm传过来的data数据,展示在页面上。

嘉宾很感谢这位观众的喜欢,但他不知道传递喜欢信息(数据)给他的观众到底是谁,他也不需要知道,他的任务是表演,就像视图的任务是展示数据,与用户交互,而不是获取数据,对数据做一些处理。

同时表演者的观众千千万万,他也不需要关心观众这个实例本身。

表演者只需要通过主持人,主持人去告诉这位观众,表演者很感谢你的喜爱。

观众也得到了来自表演者的信息。

这段废话也是另外一个模式,MVP。

Model View Presenter

Presenter在英文中就是主持的意思,MVP 和 MV VM 意义上是相同的,至少目前小的(微笑)还没发现二者的区别在哪里。

Mustache语法

Vue在进行进行插值处理和 绑定表达式时使用了一种叫Mustache模版引擎,利用双大括号去识别变量,有人称为Mustache语法,双大括号的语法。

不管叫什么,在双大括号里可进行一些语法操作,比如放入变量,也可加入表达式if for之类的,识别这些字符串,做出一些操作,实际上就是编译原理里的词法分析和语法分析。

获取文本节点

在Vue的函数内,添加

// 识别大括号,将文本节点替换
new Compile(this.$options.el, this);

遍历app里的所有节点,事实上需要递归所有节点

function Compile(el, vm) {
        vm.$el = document.querySelector(el);
        //documentFragment是文档碎片
        let fragment = document.createDocumentFragment();
        // 这一步是遍历app根节点下的所有节点,因为是DOM树的形式,将节点拆分,挂在新的空白文档上,也就是孩子节点的父节点指向改变了,让fragment作为他们的根节点
        while ((child = vm.$el.firstChild)) {
          fragment.appendChild(child);
        }
        // app下的孩子节点挂在fragment下,app下就没有节点,无法显示了了,所以需要显示回来
    	//replace(fragment);
    …………//对fragment进行操作后,重新插回去
      vm.$el.appendChild(fragment);
}

createDocumentFragment会创建一个空白文档碎片,

appendChild() 方法可向节点的子节点列表的末尾添加新的子节点。

提示:如果文档树中已经存在了 newchild,它将从文档树中删除,然后重新插入它的新位置。如果 newchild 是 DocumentFragment 节点,则不会直接插入它,而是把它的子节点按序插入当前节点的 childNodes[] 数组的末尾

创建一个fragment节点,将app下的所有节点断掉,插入fragment节点下,又将fragment插回去,这一步不会多一个fragment节点,因为

newchild 是 DocumentFragment 节点,则不会直接插入它,而是把它的子节点按序插入当前节点的 childNodes[] 数组的末尾

识别双大括号

 function replace(fragment) {
          Array.from(fragment.childNodes).forEach(function(node) {
            let text = node.textContent;
            text = text.trim();

            let reg = /\{\{(.*)\}\}/;

            // 是文本节点 又匹配双大括号语法
            if (node.nodeType === 3 && reg.test(text)) {
              //打印匹配到的第一个 name.firstName age name
              let key = RegExp.$1;
              key = key.trim();//去掉首尾空格
              let arr = key.split("."); // [name,firstName]
              let val = vm; //从vm中去拿
              arr.forEach(function(k) {
                val = val[k];
              });
              console.log(val);
              // 如果给的就是个对象,那么就序列化显示一下,不然显示【Object object】
              if (typeof val === "object") val = JSON.stringify(val);
              // 如果不是就直接显示基本数据类型
              node.textContent = text.replace(reg, val);
            }
            // 如果不是文本节点,是标签,则需要遍历标签下面的孩子节点是否有文本节点
            if (node.childNodes) {
              replace(node);
            }
          });
        }

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值