面试题:vue实现双向数据绑定的原理(附源代码)
此面试题浅层次的解释在:前端面试题:vue 的双向数据绑定原理,v-model的源码深层次,其实就是问你vue数据绑定的原理:1、使用Object.defineProperty进行数据劫持,把data对象,computed等里的所有属性进行数据劫持。数据劫持的意思可以看:JavaScript中的Object.defineProperty()函数2、使用观察者模式,完成发布订阅。发布订阅...
·
原文连接: https://blog.csdn.net/jiang7701037/article/details/104419524
此面试题浅层次的解释在:前端面试题:vue 的双向数据绑定原理,v-model的源码
深层次,其实就是问你vue数据绑定的原理:
1、使用Object.defineProperty进行数据劫持,把data对象,computed等里的所有属性进行数据劫持。数据劫持的意思可以看:JavaScript中的Object.defineProperty()函数
2、使用观察者模式,完成发布订阅。发布订阅者模式可以看:观察者模式
1)模板里使用data对象属性的dom对象都订阅。
2)当data对象里的属性的值发生变化时,就会发布,发布时,就改变了dom里的内容。
以下为源码:
这个代码只是模拟数据绑定的原理,并没有考虑vue的虚拟dom和异步更新队列等问题。
1、模拟vue.js的代码(文件名:vue.js)
class Vue{
constructor(obj){
//2、数据挂载
//2.1) 、把obj对象的每个属性,作为vue对象的属性(属性名前面加上 $)
for(let key in obj){
this["$"+key] = obj[key];
}
//2.2)、把obj.data对象的属性,作为vue对象的属性,并且要有数据劫持的功能和发布订阅的功能
let myObserver = {};
observer.make(myObserver);
for(let key in obj.data){
this["_"+key] = obj.data[key];
Object.defineProperty(this,key,{
//数据劫持
set:function(newValue){
//数据劫持的目的是,当key发生变化时,需要渲染页面
this["_"+key] = newValue;
//数据变了,就得渲染页面,发布订阅功能
myObserver.publish(newValue);
},
get:function(){
return this["_"+key];
}
});
}
//2.3)、订阅(模板里的标签需要订阅data中的数据)
let box = document.getElementById(obj.el.substring(1));//"box"
//2.3.1)查找使用msg属性的dom元素,放在数组msgDom里
let msgDom = [];
for(let i=0;i<box.children.length;i++){
if(box.children[i].innerHTML.includes("{{msg}}")){
//放到数组里,为了订阅服务
msgDom.push({
"dom":box.children[i],
"vinnerHTML":box.children[i].innerHTML// 原始的html,即:没有进行模板渲染的html
});
//把里面的{{msg}}的内容得替换掉
box.children[i].innerHTML = box.children[i].innerHTML.replace(/\{\{msg\}\}/g,obj.data.msg)
}
}
//2.3.2) 让数组数组msgDom里的每个元素订阅msg的值。
for(let i=0;i<msgDom.length;i++){
myObserver.addSubscriber(function(msg){
msgDom[i].dom.innerHTML = msgDom[i].vinnerHTML.replace(/\{\{msg\}\}/g,msg)
});
}
}
}
//观察者模式的代码
var observer={
//订阅:给数组里添加函数
addSubscriber:function(cb){
this.subscribers.push(cb);
},
//退订:删除数组里的函数
removeSubscriber:function(cb){
let index = this.subscribers.indexOf(cb);
this.subscribers.splice(index,1);
},
//发布
publish:function(what){
this.subscribers.forEach(element => {
if(typeof element =="function"){
element(what);
}
});
},
//让某个对象具备发布订阅功能
make:function(obj){
for(let key in this){
obj[key] = this[key];
}
obj.subscribers = [];
}
}
2、使用模拟的vue的html文件的代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="box">
<span>信息:{{msg}}</span>
</div>
<input id="txt" type="text" />
<input type="button" value="修改" onclick="fn()" />
</body>
</html>
<!--这个vue.js是我们自己写的,不是尤玉溪的-->
<script src="js/vue.js"></script>
<script>
let vm = new Vue({
el:"#box",
data:{
msg:"hello"
}
});
function fn(){
// vm.msg = "你好";
vm.msg = document.getElementById("txt").value;
}
</script>
更多推荐
已为社区贡献2条内容
所有评论(0)