时间:2022-08-09 08:33:29 | 栏目:vue | 点击:次
- 首先要了解
v-model
就是vue帮我们封装的语法糖,真正实现靠的还是:- v-bind:绑定响应式数据 触发 input 事件 并传递数据
例如下面示例:
<template> // 这两种写法等价 <input v-bind:name="name" v-on:input="name=$event.target.value"/> <input v-model="name"/> </template>
1、使用v-model
经典例子
textarea
元素select
下拉框input type='radio'
单选框input type='checkbox'
多选框2、使用v-model
的副作用
绑定的响应式对象某个不存在的属性,那么vue会悄悄增加这个属性,并设置为响应式
// template中: <el-input v-model="user.tel"></el-input> // script中: export default { data() { return { user: { name: 'xxx', } } } }
3、自己开发的组件如何支持v-model
model属性的默认值为
// 默认的 model 属性 export default { model: { prop: 'value', event: 'input' }, data() {...}, methods: {...}, }
简单一句话理解就是:通过重写数据的get和set属性方法,让数据在被渲染时通过get属性方法把所有用到自己的观察者watcher放入自己的观察者列表subs中,当数据发生变化之后,通过set属性方法将该变化通知给所有的观察者watcher,达到重新渲染。
Object.defineProperty()
,给所有的数据都添加getter
和setter
方法Dep
:被观察者类,每个data都有一个Dep实例对象,用于Observer的data触发getter时执行dep.depend
收集依赖的watcherWatcher
:观察者类,依赖收集以后Watcher对象会被保存在Dep的subs中,数据变动的时候Dep会通知Watcher实例,然后由Watcher实例回调cb进行视图的更新。Observer
:将普通数据转化为响应式数据实现响应式的主要流程:
1、Observer
类的构造方法
2、收集依赖
视图被渲染时,触发get属性方法,调用dep的一个方法dep.depend
进行依赖收集
举个?
当前正在渲染componentA时,组件用到了数据 data () { return { a: b + 1} }
,那么此时就会触发b
的get属性方法,将当前的watcher添加到b的订阅者列表subs中
3、派发更新
修改data属性上的某一个值时,会它的触发set属性方法,根据自身的dep.notify
(subs保存着所有的观察者,在 notify 方法中首先对 subs 这个观察者列表按照其 id 进行了排序)开始派发更新
为什么要进行排序?
- 组件的更新由父到子;因为父组件的创建过程是先于子的,所以 watcher 的创建也是先父后子,执行顺序也应该保持先父后子。
- 用户的自定义 watcher 要优先于渲染 watcher 执行;因为用户自定义 watcher 是在渲染 watcher 之前创建的。
- 如果一个组件在父组件的 watcher 执行期间被销毁,那么它对应的 watcher 执行都可以被跳过,所以父组件的 watcher 应该先执行。
排序结束以后,会对这个队列进行遍历,执行watcher.run()方法实现数据更新通知
run的逻辑是:
- 新的值与老的值不同时会触发通知;
- 但是当值是对象或者 deep 为 true 时无论如何都会进行通知
这也就是为什么可以解释watch数据的时候可以拿到新旧两个值了watch: { num(new, old) {...} }
自己实现一个响应式
根据以上分析,自己实现一个简易版的数据双向绑定
借鉴文章