模板字符串替换

这是 vue 代码阅读笔记的第一篇,希望从今天开始能够通读 vue 的源码,从大神的代码中学习代码风格,以及编程技巧,提高自己的编码能力。

概述

今天分析的是 vue 的第二个commit,提交于2013年7月29号。这部分代码的功能是实现模板字符串的替换。

假设我们有这样的一个DOM解构

1
2
3
4
5
6
7
<div id="test">
<p>{{msg}}</p>
<p>{{msg}}</p>
<p>{{msg}}</p>
<p>{{what}}</p>
<p>{{hey}}</p>
</div>

需要将其中的占位字符串包裹的部分替换成对应变量的值。

代码逻辑

首先通过正则表达式将占位字符串替换成 <span data-element-binding="variable"></span>

  • 第一步是得到这个 div
  • 第二布是将里面的所有占位字符串进行正则替换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
el = document.getElementById(id);

var content = el.innerHTML.replace(/\{\{(.*)\}\}/g, markToken);

function markToken(match, variable) {
var mark = '<span data-element-binding='+variable+'></span>';
}

el.innerHTML = content;

```

经过上面这一步,DOM就会变成:

```HTML

<div id="test">
<p><span data-element-binding="msg"></span></p>
<p><span data-element-binding="msg"></span></p>
<p><span data-element-binding="msg"></span></p>
<p><span data-element-binding="what"></span></p>
<p><span data-element-binding="hey"></span></p>
</div>

接下来我们要将数据绑定到对应的 span 上。思路就是获取对应的 span ,然后将值插入。

这里会用到 msg, what, hey 变量,所以我们要先将这些变量存起来。修改 markToken 函数:

var bindings = {}
function markToken(match, variable) {
    bindings[variable] = {};
    var mark = '<span data-element-binding='+variable+'></span>';
};

有了上面的 bingdings 对象,我们可以遍历这个对象,进行绑定操作。


for(var variable in bindings){
    bind(variable);
}

如何就行绑定呢?

这里使用 [Object.defineProperty](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) 方法,该方法允许精确添加或者修改对象的属性。

可以通过设置对象属性的 getset, 来控制属性在取值或者设值的时候进行所需的操作。

  • 第一步,首先将 ‘DOM’ 节点存起来,存到 bindings[variable] 当中,并且将这些节点的 data-element-binding 属性去掉
  • 第二步,新建一个对象 data ,将 data 对象的 variable 变量设置一个 set 函数。这个函数将上一步保存的DOM节点进行赋值,并且将值保存在 bindings[variable].value 属性中,之后可以用
  • 第三步, 将 data 对象的 variable 变量设置一个 get 函数。这个函数返回的 bindings[variable].value 属性。

    ``` Javascript
    var data = {};
    function bind(variable){
    bindings[varible].els = el.querySelectorAll(‘[ data-element-binding =’+variable+’]);
    [].forEach.call(bindings[variable].els, function(e){

        e.removeAttribute("data-element-binding");
    });
    

    Object.defineProperty(data, variable, {

    set: function(newValue){
        [].forEach.call(bindings[variable].els, function(e){
            bindings[variable].value = newValue;
            e.textContent = newValue;
        })
    },
    get : function(){
        return bindings[variable].value;
    }
    

    })
    }

```

最后只要对 data[variable] 进行赋值,就能将参数绑定。

总结

模板替换功能的逻辑:

  1. 对DOM节点的内容进行正则替换
  2. 根据模板字符串将这些DOM节点分类存储到数组中
  3. 对这些DOM节点赋值

代码的逻辑:

  1. 创建对象bindings, 用来存储variable属性所对应的DOM节点和值。
  2. 创建data对象,对data对象variable属性赋值会调用set函数将bingdings对象中的variable属性中村的DOM节点赋值
  3. 将需要绑定的DOM节点的innerHTML进行正则替换
  4. 对bindings对象进行赋值,以及设置data对象对应属性的 set和 get函数。
  5. 对data对象对应属性进行赋值。

最后附上代码的地址简单的模板字符串替换