我是靠谱客的博主 尊敬音响,这篇文章主要介绍手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理,现在分享给大家,希望可以做个参考。

最近学习vue,网上的手写双向绑定原理都是极简版的,读了很多源码解析,决定手写个复杂版的双向绑定!
html部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src="双向绑定原理.js" ></script> <div class="test"> <div h-html='a'></div> <div @click='test'>{{a}}</div> <input type="text" h-model='a'> </div> <script> new he({ el:'.test', data: { a: 1, b: 2 }, methods:{ test(){ alert('test') } } }) </script> </body> </html>

js部分

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
//用es6写的,这样感觉更便于理解,这个he就相当于Vue啦! class he { constructor(options={}){//这里就是你new Vue()的时候传的对象 this.$options = options; if (options.el) //vue里一大堆$开头的玩意都是这样挂上去的,不一一列举,重点说一下$data this.$el = document.querySelector(options.el); if (options.data) //有没有奇怪为什么vue开发时,this.xxx就可以访问data下的xxx属性?就是因为接下来这一坨代码! this.$data = options.data; const arr = Object.keys(this.$data);//遍历$data生成一个包含所有data属性的数组 let len = arr.length; while(len--){//这里遍历数组给每个属性添加代理 let key = arr[len]; Object.defineProperty(this, key, { get(){ return this.$data[key]; }, set(v){ this.$data[key] = v; } }) } if (options.methods) this.$methods = options.methods; this.observer = {};//订阅中心:{str: []}属性为this.$data中被订阅的属性,值为订阅者形成的数组 this.createObServer();//创建订阅中心 this.compile(this.$el);//编译dom元素到浏览器 } createObServer(){ let _this = this//set时this指向不对,这里先保存一下 for(let key in this.$data){ //为this.$data中每一个属性生成发布者 this.observer[key] = []; let value = this.$data[key] Object.defineProperty(this.$data, key, { get(){ return value; }, set(v){ value = v; //当数据被改变时,通知所有订阅者更新数据 _this.observer[key].forEach(v=>{ v.update(); }) } }) } } //编译器 compile(el){ const nodes = el.children; for(let i = 0;i<nodes.length;i++){ const node = nodes[i]; this.compile(node);//这里递归遍历出所有节点 if (node.hasAttribute('@click')) {//添加事件都这样 const attrValue = node.getAttribute('@click'); node.addEventListener('click', this.$methods[attrValue]); } if(node.hasAttribute('h-html')){//添加指令都这样 const attrValue = node.getAttribute("h-html"); this.observer[attrValue].push(new Watcher(node, 'innerHTML', this.$data, attrValue)) } if(node.hasAttribute(':value')){ const attrValue = node.getAttribute(":value"); this.observer[attrValue].push(new Watcher(node, 'value', this.$data, attrValue)) } if(node.hasAttribute('h-model')){//特殊指令,v-model const attrValue = node.getAttribute('h-model'); node.addEventListener('input', (e)=>{ this.$data[attrValue] = e.target.value }) this.observer[attrValue].push(new Watcher(node, 'value', this.$data, attrValue)) } if(/{{(.*)}}/.test(node.textContent)){//这里是双大括号{{}}的特殊指令,不要吐槽我没有把正则保存成变量,懒得改了! this.observer[/{{(.*)}}/.exec(node.textContent)[1]].push(new Watcher(node, 'innerText', this.$data, /{{(.*)}}/.exec(node.textContent)[1])) } } } } //订阅者 class Watcher{ constructor(el, props, data, key){ this.el = el; this. props = props; this.data = data; this.key = key; this.update() } update(){//订阅者更新数据 this.el[this.props] = this.data[this.key]; } }

最后

以上就是尊敬音响最近收集整理的关于手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理的全部内容,更多相关手写vue源码,包括双向绑定原理(基于发布订阅模式内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部