我是靠谱客的博主 尊敬音响,最近开发中收集的这篇文章主要介绍手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
最近学习vue,网上的手写双向绑定原理都是极简版的,读了很多源码解析,决定手写个复杂版的双向绑定!
html部分
<!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部分
//用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源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复