MVVM基本理解
- MVVM(Model-View-ViewModel)是一种设计思想,主要实现的效果是数据改变视图会跟着变,视图改变数据也会修改。
- MVVM将数据、视图、业务逻辑抽离出来;数据(M)定义页面需要展示的内容,视图(V)负责渲染页面,业务逻辑(VM)是核心用来处理视图和数据(属于视图和数据之间的桥梁)。
MVVM模式实现(Object.defineProperty())
通过一个例子解释
- 现在需要实现一个功能,一个输入框和一个p标签,输入框输入什么内容,p标签就实时的展示什么内容。
//首先想到的实现方式
//缺点:只有input事件中修改了data.value属性,页面会重新渲染;当在其他事件中修改了data.value属性就不会重新渲染页面,需要重新调用update方法才行
<body>
<input id="input" type="text" value="">
<p id="show"></p>
<script>
let data = {
value: '123'
}
let inputDom = document.getElementById('input')
let showDom = document.getElementById('show')
function update() {
show.innerHTML = data.value
inputDom.value = data.value
}
update()
inputDom.addEventListener('input', () => {
data.value = inputDom.value
update()
})
</script>
</body>
//使用Object.defineProperty对data的value属性进行劫持,定义get和set属性,当对data.value进行设置时,会走set方法,可以在此方法中调用update()更新页面
//
<script>
let data = {
value: '123'
}
let inputDom = document.getElementById('input')
let showDom = document.getElementById('show')
function update() {
show.innerHTML = data.value
inputDom.value = data.value
}
update()
inputDom.addEventListener('input', () => {
data.value = inputDom.value
})
let dataVal=data.value
Object.defineProperty(data, 'value', {
get() {
return dataVal
},
set(newVal) {
dataVal = newVal
update()
}
})
</script>
//将整个data定义成响应式数据(对定义响应式数据方法进行简单封装)
//如果数据中嵌套对象,需要递归处理嵌套数据
<body>
<input id="input" type="text" value="">
<p id="show"></p>
<p>用户名:<span id='userName'></span></p>
<p>年龄:<span id='userAge'></span></p>
<script>
let data = {
value: '123',
user:{
name:"zhangsan",
age:18
}
}
let inputDom = document.getElementById('input')
let showDom = document.getElementById('show')
function update() {
show.innerHTML = data.value
inputDom.value = data.value
userName.innerHTML=data.user.name
userAge.innerHTML=data.user.age
}
update()
inputDom.addEventListener('input', () => {
data.value = inputDom.value
})
function _toString(obj) {
return Object.prototype.toString.call(obj).slice(8, -1)
}
function observer(data) {
for (let key in data) {
let oldVal = data[key]
if (_toString(oldVal) === 'Object') {
//当数据中嵌套对象时需要递归处理
observer(oldVal)
}
defineReactive(data, key, oldVal)
}
}
function defineReactive(data, prop, oldVal) {
Object.defineProperty(data, prop, {
get() {
return oldVal
},
set(newVal) {
if (oldVal !== newVal) {
oldVal = newVal
update()
}
}
})
}
observer(data)
setTimeout(() => {
data.user.name='lisi',
data.user.age=20
//一秒钟之后将看到页面数据会重新渲染
}, 1000);
</script>
</body>