MVVM模型
MVVM -Model View ViewModelM:模型(Model) :对应 data 中的数据V:视图(View) :模板VM:视图模型(ViewModel) : Vue 实例对象最核心的就是 ViewModel 。ViewModel 包含 DOM Listeners 和 Data Bindings。Data Bindings 用于将数据绑定到 View 上显示,DOM Listeners
MVVM -Model View ViewModel
-
M:模型(Model) :对应 data 中的数据
-
V:视图(View) :模板
-
VM:视图模型(ViewModel) : Vue 实例对象
最核心的就是 ViewModel
。ViewModel
包含 DOM Listeners
和 Data Bindings
。
Data Bindings
用于将数据绑定到 View
上显示,DOM Listeners
用于监听操作。
-
从
Model
到View
的映射,也就是Data Bindings
。这样可以大量省略我们手动update View
的代码和时间。 -
从
View
到Model
的事件监听,也就是DOM Listeners
。这样我们的Model
就会随着View
触发事件而改变。
在Vue中的mvvm:
-
data中所有的属性、computed的计算属性、methods中的方法等,最后都出现在了vue实例vm身上。
-
vue实例vm身上所有的属性 及 Vue原型上所有属性,在Vue模板{{}}中都可以直接使用。
<div id="app"> {{num}} </div> <script> let vm = new Vue({ el:'#app', data:{ num: 10, } }); </script>
MVVM思想有两个方向
一是将模型转换成视图,即将后端传递的数据转换成看到的页面。实现方式是:数据绑定。
二是将视图转换成模型,即将看到的页面转换成后端的数据。实现的方式是:DOM 事件监听。
这两个方向都实现的,就称为数据的双向绑定。
MVC 和 MVVM 的区别(关系)
MVC - Model View Controller( controller: 控制器 ),M 和 V 和 MVVM 中的 M 和 V 意思一样,C 指页面业务逻辑。使用 MVC 的目的就是将 M 和 V 的代码分离,但 MVC 是单向通信,也就是将 Model 渲染到 View 上,必须通过 Controller 来承上启下。
MVC 和 MVVM 的区别(关系)并不是 ViewModel 完全取代了 Controller 。
ViewModel 目的在于抽离 Controller 中的数据渲染功能,而不是替代。其他操作业务等还是应该放在 Controller 中实现,这样就实现了业务逻辑组件的复用。
常见关于Vue的面试题
什么是MVVM思想?
MVVM -
Model View ViewModel
,它包括 DOM Listenters 和 Data bindings,前者实现了页面与数据的绑定,当页面操作数据的时候 DOM 和 Model 也会发生相应的变化。后者实现了数据与页面的绑定,当数据发生变化的时候会自动渲染页面。
MVVM相对于MVC的优势?
MVVM 实现了数据与页面的双向绑定,MVC 只实现了 Model 和 View 的单向绑定。
MVVM 实现了页面业务逻辑和渲染之间的解耦,也实现了数据与视图的解耦,并且可以组件化开发。
VUE是如何体现MVVM思想的?
胡子语法(
Mustache
语法, {{}} 长的比较像胡子,命名为胡子语法),实现了数据与视图的绑定。v-on 事件绑定,通过事件操作数据时,v-model 会发生相应的变化。
响应式原理
数据代理
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
let o1 = {x: 100}; let o2 = {y: 200}; Object.defineProperty(o2, 'x', { get(){ return o1.x; }, set(value){ o1.x = value; } });
o2对象代理了o1对象的属性x,当修改o1.x会影响o2.x,修改o2.x也会影响o1.x
响应式 reactive
响应式原理:在改变数据的时候,视图会跟着更新。
<input type="text"> <p class="text"></p> <script> let input = document.querySelector('input'); let text = document.querySelector('p'); let obj = {}; Object.defineProperty(obj, 'message', { set (val) { // 当修改obj.mesage值时 同时设置给 input/p 设置对应的值 input.value = val text.innerText = val }, get(){ return input.value; } }); input.oninput = function (ev){ obj.message = ev.target.value; } </script>
Vue给data里所有的属性加上set,get这个过程就叫做响应式。
Vue中的数据代理
Vue中的数据代理:通过vue实例来代理data对象中属性的操作(读/写)
Vue中数据代理的好处:更加方便的操作data中的数据
响应式原理
-
vue在实例化时,将data中的所有属性都通过Object.defineProperty添加到vue实例上
-
为每一个添加到vue实例上的属性都指定setter和getter,在getter/setter内部去操作(读/写)data中对应的属性
-
每个vue实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据记录为依赖。之后当依赖属性的 setter 触发时,会通知 watcher,从而使页面中绑定这个属性的部分重新渲染。
总结
第一步:组件初始化的时候,先给每一个Data属性都注册getter,setter,也就是reactive化。然后再new 一个自己的Watcher对象,此时watcher会立即调用组件的render函数去生成虚拟DOM。在调用render的时候,就会需要用到data的属性值,此时会触发getter函数,将当前的Watcher函数注册进sub里。
第二步:当data属性发生改变之后,就会遍历sub里所有的watcher对象,通知它们去重新渲染组件。
响应式属性
vue的响应式属性
由于 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式属性,哪怕只是一个空值。
var vm = new Vue({ data:{ // 声明 message 为一个空值字符串 message: '' } }) // 之后设置 `message` 是响应式的 vm.message = 'Hello!'
由于 Vue 会在初始化实例时对data中的属性执行 getter/setter 转化,所以属性必须在 data
对象上存在才能让 Vue 将它转换为响应式的。
var vm = new Vue({ data:{ a:1, zhangsan: { name: '张三' }, items: [1, 2, 3], } }) // `vm.a` 是响应式的 vm.b = 2 // `vm.b` 是非响应式的
给已有对象添加属性
对于已经创建的实例,Vue 不允许动态添加根级别的响应式属性。但是,可以使用 Vue.set(object, propertyName, value)
方法向嵌套对象添加响应式 property。例如:
Vue.set(vm.someObject, 'b', 2); // 或者 this.$set(this.someObject,'b',2);
添加多个属性
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
Vue.set(app.zhangsan, 'age', 18);//age是响应式的 vm.zhangsan = Object.assign({}, app.zhangsan, {weight:100, height:180});
数组的响应式
Vue 不能检测以下数组的变动:
-
当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
-
当你修改数组的长度时,例如:
vm.items.length = newLength
vm.items[1] = 'x' // 不是响应性的 vm.items.length = 2 // 不是响应性的
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue
相同的效果,同时也将在响应式系统内触发状态更新:
// Vue.set Vue.set(vm.items, indexOfItem, newValue) //或者 vm.$set(vm.items, indexOfItem, newValue) // Array.prototype.splice vm.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题vm.items.length = newLength
,你可以使用 splice
:
vm.items.splice(newLength)
nextTick
Vue 在更新 DOM 时是异步执行的:当data中数据变化是通过异步操作渲染更新DOM
<p ref="p">num:{{num}} </p> <button @click="btnClick">按钮</button> <script> var vm = new Vue({ data:{ num: 6, }, methods: { btnClick () { this.num = 666; // Vue 在更新 DOM 时是异步执行的:当data中数据变化是通过异步操作渲染更新DOM console.log(this.$refs.p.innerHTML);// num:6 // 为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成后被调用 this.$nextTick(function(){ console.log(this.$refs.p.innerHTML);// num:666 }); } }, }) </script>
更多推荐
所有评论(0)