MVVM是一种双向数据绑定的构架模式,是现在前端非常主流的模式,vue的底层就是通过此实现的
M : model,数据模型,提供数据
V : view,视图,页面展示
VM : viewmodel,试图模型,相当于是M和V之间的桥梁
M到V : 是用到了Object.defineProperty()来挟持data中的数据,把数据转到get和set中操作,每次只要触发set操作修改数据就会更新dom
V到M : 通过事件来监听数据变化,当数据变化时将数据赋给原有数据
后面是示例为准讲一下其中细节:
1.M:声明一个对象,其中一个属性名为params,这给对象obj就相当于model数据模型
// M ==> 数据模型
let obj = {
params : 123
};
2.V:我们获取id名为main的div节点,使用innerHTML在其中创建一个input输入框,将上述的数据params利用模板字符串拼接到innerHTML中,让其渲染到input的value属性中,顺便在input上绑定一个input事件后面要使用,将其封装为函数fn,调用一次实现试图
// V ==> 视图
function fn(){
mainNode.innerHTML = `
<input type="text" value="${obj.params}" oninput="inputNum()">
<p>${obj.params}</p>
`
}
fn()
3.M ==> V:先实现数据变化时产生渲染效果:
这里利用到Object上的一个方法Object.defineProperty()来挟持数据,其中有三个参数,第一个为所在对象,第二个为挟持属性,第三个为配置项一般为对象,其中包含get和set两个方法,当挟持数据被调用时就会触发get,当数据发生修改时触发set,这里我们将obj.params赋给一个变量num,后再get中返回这个变量,因为如果直接使用obj.params作为返回值的话,一返回就会被当作再次调用obj.params就会进入死循环。
set中有个val为触发set时obj.params变化的值,我们将这个val赋值给变量num后再调用fn函数,注意,这里调用fn函数时函数中会调用obj.params就会再次触发get,后obj.params就将被自动附上返回的变量num的值,前面在set中就给num附上了新值所以现在的obj.params就是最新的值
创建一个按钮,点击触发函数changeNum,其中是将obj.params的值改变,当其一变化就会触发前面的set,执行上述行为
<button onclick="changeNum()">点击修改</button>
<script>
let num = obj.params;
// VM ==> 试图模型 -- M和V的桥梁
// M ==>V
Object.defineProperty(obj , 'params' , {
get(){
return num;
},
set(val){
num = val;
fn();
},
})
function changeNum(){
obj.params="我改变了"
}
</script>
4.V==> M:实现试图数据改变原有数据:
前面在input输入框上绑定input输入事件,让其被触发时就会调用函数inputNum,其是将输入内容赋值给obj.params,所以只要已输入就会触发set,执行set中的赋值渲染操作,实现双向数据绑定
// V ==> M
function inputNum(){
obj.params = event.target.value;
}
以下为完整代码:
<body>
<div id="main"></div>
<button onclick="changeNum()">点击修改</button>
<script>
const mainNode = document.querySelector('#main');
// M ==> 数据模型
let obj = {
params : 123
};
// V ==> 视图
function fn(){
mainNode.innerHTML = `
<input type="text" value="${obj.params}" oninput="inputNum()">
<p>${obj.params}</p>
`
}
fn()
let num = obj.params;
// VM ==> 试图模型 -- M和V的桥梁
// M ==>V
Object.defineProperty(obj , 'params' , {
get(){
return num;
},
set(val){
num = val;
fn();
},
})
function changeNum(){
obj.params="我改变了"
}
// V ==> M
function inputNum(){
obj.params = event.target.value;
}
</script>
</body>