数据驱动
-
数据响应式:数据指的是数据模型,数据模型仅仅是普通的JavaScript对象。当我们修改数据的时候,视图会进行更新,避免繁琐的DOM操作,提高开发效率。
-
双向绑定:
- 数据改变,视图改变,视图改变,数据也随之变化
- 我们可以使用v-model进行数据的双向绑定
-
数据驱动是VU独特的特性之一
- 开发过程中仅仅需要关注数据本身,不需要关心数据是如何渲染到视图的
数据响应式的核心原理
VUE 2.x
当把一个普通的javaScript对象传入Vue实例作为data选项,vue将遍历此对象所有属性,并使用Object.defineProperty把这些属性全部转为getter/setter。 Object.defineProperty是ES5中一个无法被shim(降级)的属性,所以Vue不支持IE8以下的版本。
<body>
<div id="app">hello</div>
<script>
//模拟Vue中的data选项
let data = {
msg:'hello',
count:0
}
//模拟vue实例
let vm = {}
proxyData(data)
function proxyData(data){
//遍历data对象中的所有属性
Object.keys(data).forEach(key => {
//把data中的属性,转换成vm的 setter/getter
//数据劫持:当访问或者设置VM中的成员的时候,做一些干预
Object.defineProperty(vm,key,{
//可枚举(可遍历)
enumerable:truem,
//可配置(可以使用delete删除,可以通过defineProperty重新定义)
configurable:true,
//当获取值的时候执行
get(){
console.log('get:',data[key]);
return ddata[key]
},
//当设置值的时执行
set(newValue){
console.log('set:',key,newValue);
if(newValue === data[key]){
return
}
data[key] = newValue
//数据更改,更新DOM的值
document.querySelector('#app').textContent = data[key]
}
})
})
}
//测试
vm.msg = 'hello world'
console.log(vm.msg);
</script>
</body>
复制代码
Vue 3.x
vue 3中使用Proxy进行对象监听,直接监听对象本身,而非属性。是ES6中新增的是属性,性能由浏览器优化。
//模拟vue实例
let vm = new Proxy(data,{
//执行代理行为的函数
//当访问vm的成员时会执行
get(target,key){
console.log('get,key:',key,target[key]);
return target[key]
},
//当设置vm成员的时候会执行
set(target,key,newValue){
console.log('set,key:',key,newValue);
if(target[key] === newValue){
return
}
target[key] = newValue
document.querySelector('#app').textContent = target[key]
}
})
复制代码
发布订阅模式
我们假定,存在一个信号中心,某个任务执行完成,就像信号中心“发布”一个信号,其他任务可以向中心“订阅”这个信号,从而知道什么时候自己可以开始执行。这就叫“发布订阅模式”
//发布者,订阅者和消息中心都是vm
let vm = new Vue()
vm.$on('dataChange',()=>{
console.log('data---change---')
})
vm.$emit('dataChange')
复制代码
- 兄弟组件之间通信
//eventBus.js
//事件中心
let eventHub = new Vue()
//ComponentA.vue
//发布者
addTodo:function(){
//发布消息(事件)
eventHub.$emit('add-todo',{text:this.newText})
}
//ComponentB.vue
//订阅者
created:function(){
eventHub.$on('add-todo',this.addTodo)
}
复制代码
- 自定义发布订阅模式
//html
<script>
//发布订阅模式
class EventEmitter {
constructor () {
//{'click':[fn1,fn2],'change':[fn1,fn2]}
this.subs = Object.create(null)
}
//注册事件
$on (eventType,handler) {
this.subs[eventType] = this.subs[eventType] || []
this.subs[eventType].push(handler)
}
//触发事件
$emit (eventType) {
if(this.subs[eventType]){
this.subs[eventType].forEach(handler => handler()
}
}
}
//测试
let em = new EventEmitter
em.$on('click',()=>{
console.log('click1');
})
em.$on('click',()=>{
console.log('click2');
})
em.$emit('click')
</script>
复制代码
观察者模式
- 观察者模式中没有事件中心,只有发布者和订阅者
<script>
//发布者
class Dep {
constructor () {
//记录所有的订阅者
this.subs = []
}
//把传递的订阅者添加到数组中
addSub (sub) {
if(sub && sub.update){
this.subs.push(sub)
}
}
notify () {
this.subs.forEach(sub => {
sub.update()
})
}
}
//订阅者
class Watcher {
update () {
console.log('update');
}
}
//测试
let dep = new Dep()
let watcher = new Watcher()
dep.addSub(watcher)
dep.notify()
</script>
复制代码
观察者模式和发布订阅模式的区别
- 观察者模式是由具体的目标调度,比如当事件触发,Dep就会去调用观察者的方法,所以,观察者模式的订阅者和发布者之间是存在依赖的。
- 发布/订阅模式:由统一调度中心调度,因此发布者和订阅者不需要知道对方的存在。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END