什么是mvvm?
m:model 数据层;
v:view 视图层;
vm:viewModel 视图层跟数据层的连接桥梁
解释:m是后端传过来的数据,v是前端渲染后端数据所看见的页面;
vm通过数据绑定来实现数据->视图,视图->数据,vm通过Dom事件监听数据跟视图的变化来实现数据跟视图的更新;
当监听到数据变化的时候,视图层自动更新,当用户操 作视图层的时候,vm监听到视图的变化通知数据更新.实际上就实现了数据的双向绑定.
除此之外,vm层还能跟v层进行相互通信.
如上图所示;
我们可以模拟一下mvvm的基本实现:
html:
<input type="text" id="input1"/> <span id="span1"></span>
js:
var m={a:''};
var v={};
var vm={
init(){
input1.onkeyup=function(){
m.a=this.value;
vm.observer(m,"a");
}
},
observer(obj,attr){
var val=obj[attr];
Object.defineProperty(obj,attr,{
get(){
return val;
},
set(v){
input1.value=span1.innerHML=val=v;
}
})
}
};
vm.init();
什么是mvc?
m:model 数据层(模型)
v:view 视图层
c:controller 控制器
解释:
M和V指的意思和MVVM中的M和V意思一样。C即Controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。‘MVC是单向通信。也就是View跟Model,必须通过Controller来承上启下,
将用户界面和业务逻辑合理的组织在一起,起粘合剂的效果。所以Controller中的内容能少则少,这样才能提供最大的灵活性。
如上图所示,我们也可以模拟一下mvc的基本实现;
html:
<input type="text" id="input1"/> <span id="span1"></span>
js:
var m={
a:'',
Set(val){
m.a=val;
v.render();
},
Get(){
return m.a;
}
};
var v={
init(){
input1.onkeyup=c.Keyup;
},
render(){
span1.innerHTML=m.Get();
}
};
var c={
Keyup(){
m.Set(this.value)
}
}
v.init();
vue的基本实现原理
关于Object.defineProperty();
Object.defineProperty()可以在对象中再定义或者修改属性,可以对该属性的读写性,可行性等进行操作;
三个必须参数:
obj(目标对象),attr(属性),desc(描述)
- obj: 需要进行定义或修改属性的对象;
- attr: 需要进行定义或者修改的属性; desc: 该属性的描述符(包含存取描述符和数据描述符),该参数以一个对象的形式传入,该参数有六个选项:
- value: 设定该属性的值;
- writable: 布尔,该属性是否可写入(是否可改变其value);
- enumerable: 布尔,该属性是否可被遍历得到(for...in, Object.keys等);
- configurable: 布尔,设定该属性是否可被删除,且除writable外的其他描述符是否可被修改;
- get: 函数,该属性的值被获取时执行的回调函数(例如console.log(prop)),默认为undefined;
- set: 函数,该属性的值被设置时执行的回调函数,默认为undefined;
话不多说,上代码:
<!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>v-model | v-text 基本实现</title> </head> <body> <input type="text" v-model="a"> <span v-text="a"></span> <br> {{a}} <script> // console.log(Object.defineProperty) var m={ a:'' }; var v={ }; var vm={ nodeList:{}, init(){ var nodes=document.body.childNodes; // console.log(nodes) for(var i=0;i<nodes.length;i++){ var node=nodes[i]; vm.compile(node) } // console.log(vm.nodeList) // vm.observer() }, compile(node){ var name=""; // console.log(node+" --"+node.attributes) // console.log(node+": "+node.nodeType) if(node.nodeType===1){ //元素节点 var attrs=node.attributes; for(var i=0;i<attrs.length;i++){ // console.log(attrs[i]) var nodeName=attrs[i].nodeName; var nodeValue=attrs[i].nodeValue; // console.log(nodeName,nodeValue) if(nodeName==='v-model'){ name=nodeValue; node.addEventListener('keyup',function(){ m[name]=this.value; }) vm.observer(m,name); } if(nodeName==='v-text'){ name=nodeValue; } } }; if(node.nodeType===3){ //文本节点 // console.log(node.nodeValue) var arr=node.nodeValue.match(/{{(.+)}}/); if(arr){ // console.log(arr) name=arr[1]; } } // console.log(name,node) if(name){ if(vm.nodeList[name]==undefined){ vm.nodeList[name]=[]; } vm.nodeList[name].push(node); } }, observer(obj,attr){ var val=obj[attr]; Object.defineProperty(obj,attr,{ get(){ return val; }, set(v){ val=v; var arr=vm.nodeList[attr]; // console.log(arr) for(var i=0;i<arr.length;i++){ var node=arr[i]; if(node.nodeType===1){ if(node instanceof HTMLInputElement){ node.value=v; }else{ node.innerHTML=v; } } if(node.nodeType===3){ node.nodeValue=v; } } } }) } } vm.init(); </script> </body> </html>