Vue源码阅读记-Second Commit

为什么要从 Second Commit 开始阅读呢? 答案来自我看过我的一篇博客,但是关于 First Commit,基本是关于 Grunt 的配置,现代前端开发中,多以使用 Webpack 为主,所以粗略看了一下之后并无记录的打算。 不罗嗦,直接看代码 在这段代码我们已经触及了 Vue 的核心:data bind,实际上也跟我们现在写的 Vue 差不多(当然,这里不是指 SFC ) 首先在 HTML 部分,我们看到了文档中的“Mustache”语法,接下来我们看看最初的 data bind 是如何实现的。 在第 23 行,var content = el.innerHTML.replace(/\{\{(.*)\}\}/g, markToken),用正则表达式匹配{{...}}, 关于 String.prototype.replace() 你可以指定一个函数作为第二个参数。在这种情况下,当匹配执行后,该函数就会执行。 函数的返回值作为替换字符串。 (注意:上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是,如果第一个参数是正则表达式,并且其为全局匹配模式,那么这个方法将被多次调用,每次匹配都会被调用。 当第二个参数是一个函数时,函数接收多个参数,第一个参数match,表示匹配的子串,比如:{{msg}}、{{what}}等,第二个参数用于匹配正则表达式中括号匹配到的字符串,就是匹配正则表达式的这一部分:(.*),并且这里可以接收多个参数:p1,p2,p3...,他们分别是括号对应的索引,具体参见 MDN。 ok,我们继续回到 23 行,每次匹配执行后都会执行这个函数,这个函数首先会往bindings内填充key:value,key 是{{}}内的值,value 则是一个空对象,然后 return 一个字符串 return '<span ' + bindingMark + '="' + variable +'"></span>' 接着遍历 bindings 执行 bind 方法 function bind (variable) { bindings[variable].els = el.querySelectorAll('[' + bindingMark + '="' + variable + '"]') ;[].forEach.call(bindings[variable].els, function (e) { e.removeAttribute(bindingMark) }) Object.defineProperty(data, variable, { set: function (newVal) { [].forEach.call(bindings[variable].els, function (e) { bindings[variable].value = e.textContent = newVal }) }, get: function () { return bindings[variable].value } }) } 首先会找到含有bindingMark=... Attribute的 Element,并在bindings对应的key中记录它,接着再删除元素中的bindingMark Attribute,最后使用Object.defineProperty来做到 data bind,这也是 Vue 数据响应的核心。 ...

December 23, 2021 · 1 min · Zink