You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<body><divid="app"><inputtype="text"v-model="man.name"><div>{{man.name }}</div><div>{{man.age }}</div></div><scriptsrc="vue.js"></script><script>
let vm = new Vue({el: '#app',data: {man: {name: 'chenying',age: '23',}}})
</script></body>
我们可以发现, Vue内部会把{{ xx }}和v-xx等语法进行编译, 最后使用data中对应的数据填充过去,这个就是我们模板编译的大致思路.
【源码】手写mvvm 之 Compiler类
前言
本文是我们模仿源码手写一款MVVM的上篇 - 手写
Compiler
, 也就是我们说的模板编译, 但是和源码不一样的是源码中使用了ast
而我们为了方便使用的是fragment
来对节点进行操作。好啦我们直接进入正题手写Compiler
.手撸Vue中的模板编译
我们先来看一个简单的Vue用法, 然后根据这个用法一步一步的写出我们想要的效果
我们可以发现, Vue内部会把
{{ xx }}
和v-xx
等语法进行编译, 最后使用data中对应的数据填充过去,这个就是我们模板编译的大致思路.Vue类
我们在使用Vue的时候往往会这样初始化
不难看出Vue是一个类,接受一个
options
, 也就是钩子的集合,我们来实现一下这个类我们会将
options
中的钩子挂载到Vue的实例上, 这里只挂载了我们需要的$el
和$data
供后序流程使用, 然后通过new Compiler(this.$el, this)
来进行编译。我们接下来重点看下Compiler
是什么Compiler类
首先会判断当前
$el
上面的值是节点还是字符串, 如果是字符串的话使用document.querySelector
获取真实的DOM然后调用
noToFragment()
方法递归遍历这个DOM节点, 将它存在文档碎片, 也就是内存中。::: tip
这里需要注意的是, 最新源码中并不是使用文档碎片的形式, 而是使用AST的形式
:::
最后调用
complie()
方法对文档碎片进行编译,然后将编译后的文档随便追加到页面中。我们可以很容易的猜到
complie()
方法的作用就是用options中的数据替换掉Vue语法中的{ {xx} }
和v-xx
等值或者逻辑接下来我们重点看下
complie()
方法内部做了什么complie方法
我们可以发现
complie()
方法的作用是遍历我们的模板得到一个个的节点, 然后判断当前是节点还是文档,调用对应的编译方法进行编译编译节点
我们首先开看下是如何编译节点的
我们拿到node节点之后, 会是如下的格式
所以我们首先需要调用
complie()
方法进行递归,保证节点的子节点也可以编译。然后我们拿到每个节点的属性
attrs
,通过正则判断是不是Vue中的指令格式v-xxx
, 如果是的话调用对应模块的方法,如
v-modal
调用的是CompilerUnit.model()
方法我们再将重心放到
CompilerUnit.model()
方法, 这里出现了一个很神奇的用法, 这也是我在源码当中看到的挺好玩的地方,假设我们的代码是这样的
v-modal="man.name"
, 也就是我们拿到的表达式是man.name
,在源码中是通过reduce
的用法将这类表达式解析然后获取到vm.$data.man.name
的值最后就是将这个值通过js渲染到页面的元素上
编译文本
在看完编译节点之后,我们最后来看下是如何编译文本的
编译文本的原理是找到模板中
{ { xxx } }
格式的数据, 并且用vm.$data
中的数据替换掉格式中的xxx
就好了.总结
其实Vue中的
Compiler
不难,核心就是通过正则等手段将Vue中特定的语法用options
的值替换,但是也有很多我们可以学习的地方,如匹配的正则表达式/\{\{(.+?)\}\}/
、如何通过reduce
来获取深层次的数据、如果判断节点的类型等等。那么下一篇我们将在上述写好模板编译功能代码的基础上实现我们MVVM中缺少的那部分 -- Vue是如何实现数据劫持,双向绑定的
源码
点击查看源码
The text was updated successfully, but these errors were encountered: