目录 § ⇧
- 1. 进阶属性概览 §
- 2. 复习响应式原理 §
- 3.
Computed
计算属性(数据) § - 4.
Watch
监听属性(数据) § - 5.
Directive
指令(资源) § - 6.
Mixin
混入(组合) § - 7.
Extends
继承、扩展(组合) § - 8.
Provide
和Inject
(组合) § - 9.
Vue3.x
响应式系统 APIwatchEffect
§ - 10. $3 §
- 11. $3 §
1. 进阶属性概览 §
computed
计算属性- 不需要加括号
- 会根据依赖是否变化来缓存
watch
监听- 一旦
data
变化,就执行的函数 options.watch
用法this.$watch
用法deep
,immediate
含义
- 一旦
directives
指令- 内置指令
v-if / v-for / v-bind /v-on
- 自定义指令,如
v-focus
- 指令是为了减少重复的
DOM
操作
- 内置指令
mixin
混入- 重复三次之后的出路
- 混入
V.S.
全局混入 - 选项自动合并
- 混入就是为了减少重复的构造选项
extends
继承Vue.extend
- 觉得用了
mixin
还是重复,自己写了View
,继承Vue
- 还可以预先定义其他构造选项
- 继承就是为了减少重复的构造选项
- 不用
ES6
的extends
的原因
provide/inject
- 祖孙组件通信
- 后代组件通信
- 全局变量,局部的全局变量
2. 复习响应式原理 § ⇧
- 当传入
options.data
给Vue
之后data
会被Vue
监听,对象被Vue
篡改setter
getter
- 会被
Vue
实例vm
代理 - 每次对
data
的读写会被Vue
监控 Vue
会在data
变化时更新UI
data
变化时除了更新UI
外,其他的操作
3. Computed 计算属性(数据) § ⇧
用途 ⇧
- 根据其他属性计算出来的属性就是计算属性
- 语法是函数,当做属性使用,默认读取方法返回值
- 计算属性文档
computed
文档- 示例代码1:用户名展示
main.js
|
|
- 用户可能没有填昵称,优先展示昵称,没有昵称其次展示邮箱,再次展示手机
- 页面中多处展示昵称、邮箱和手机
DRY
原则,灵活面对需求变化:先展示手机,最后是邮箱- 将所有的数据的可能变化,写在一个函数中(
displayName() {return ...}
必须有返回值),按需调用(当做属性,不用写括号){{displayName}}
- 需要多处展示,多处写入计算属性即可
- 好处就是可以让一些事根据其他属性计算而来的属性变成一个属性,形式是一个方法,但必须当做属性来用,默认去读取方法的返回值
可读可写
main.js
|
|
- 示例代码2:列表展示
- 需求 点击性别展示符合的内容;点击全部,展示全部
如何给三个按钮添加事件处理函数
- 思路一:点击后改
userList
,不可改变原始数据 - 复制一份数据用来展示
displayUsers: []
- 思路二:使用
computed
思路一:点击后改userList
⇧
|
|
思路二:使用computed
⇧
- 根据
user
和gender
筛选结果result
- 封装函数
result = f(users, gender){...}
,通过计算得到结果 - 在
methods
的方法中判断this.gender
- 在
template
点击事件中,直接赋值gender
,自动计算显示内容 - 用 computed 筛选男女
|
|
- 根据
gender
返回userList
的不同部分 computed
使得button
的逻辑更加清晰,按钮直接改变gender
,而不用通过绑定函数,计算对应的值,全部在computed
中计算
Computed 缓存原理 ⇧
- 如果依赖的属性没有变化,计算属性就不会重新计算
getter/setter
默认不会做缓存,Vue
做了特殊处理- 示例代码3 非
Vue
源码
|
|
- 勿重复在
data
中声明数据,否则报错The computed property "xxx" is already defined in data
4. Watch 监听属性(数据)§ ⇧
用途 ⇧
- 当数据变化时,执行一个函数
- 又称“侦听器”
- 当需要在数据变化时执行异步或开销较大的操作时,来响应数据的变化
示例代码4:撤销
|
|
- 官方描述:每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把 “接触”过的数据 property 记录为依赖
- 之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染
- 即所有
methods
中操作数据的改变都会被watch
监听到
异步
watch.n
的函数是异步的,异步更新队列- 搜索
vue.js set data without watch
:just do a conditional check inside the watcher callback
- 异步接口
this.$nextTick(() => {}, 0)
相当于ES2017 async/await
语法糖
示例代码5:模拟
computed
不建议使用,优先使用computed
|
|
immediate
:是否在第一次渲染时运行watch
函数监听数据初始值- 注意
watch
监听data
第二层数据user.email
的写法 watch
一般不监听初始的值:从无到有,即第一次数据是空值- 除非设置
watch
内部对象的属性immediate: true
使得第一次渲染也触发watch
- 都是在数据变化的时候执行一个函数
computed
着重依赖之间的变化和缓存watch
着重变化后执行函数,而不是得到的结果
数据变化 ⇧
- 示例代码6
obj
原本是{a: 'a'}
,变为obj = {a: 'a'}
,地址变了,而obj.a
的值没变- 简单类型看值,复杂类型(对象看地址)
- 对象的属性变了,但对象的地址没变,
Vue
认为对象没变 - 和
===
的规则相同
watch
类型语法
watch: { [key: string]: string | Function | Object | Array }
- 常用
watch: {fn(new, old) {...}}
语法1 文档
|
|
Vue
实例将会在实例化时调用$watch()
,遍历watch
对象的每一个property
|
|
语法3 钩子函数中写
this.$watch(...)
|
|
深入监听deep: true
⇧
- 如果
object.a
变了,deep: true
控制object
变了 - 如果
object.a
变了,deep: false
控制object
不变 deep
即监听object
深入监听- 不仅比较地址,任何一层的值变了,都判定数据变化,都受到监听
- 即不需要再监听对象里面的属性变化,只要监听外层,同时监听了内部数据变化
deep
默认值是false
|
|
- 写在外面太丑,可写在生命周期的钩子中
- 和
DOM
无关,放在created
中,创建完立即监听数据
简述 computed 和 watch 的区别 ⇧
- 翻译成中文
- 各自描述(可用代码例子)
标准答案
- 把
computed
翻译为计算属性 - 把
watch
翻译为监听/观察/侦听 - 描述
computed
的功能:用于计算一个新的属性,并提及「依赖」和「缓存」 - 描述了
watch
的功能:在数据变化时执行一个函数 - 其他正确的描述:
computed
计算出的值不需要加括号,在template
中,直接当做属性来用computed
根据「依赖」会自动「缓存」,依赖不变,不会重新计算值watch
监听某个属性变化了,就执行一个函数watch
中的immediate
表示是否在第一次渲染中监听属性watch
中的deep
是否监听对象内部属性的变化
详细描述 计算属性
computed
:
- 用来计算一个值,这个值使用时不需要加函数执行的括号,直接当属性来用;值会根据所依赖的数据动态显示新的计算结果,并自动缓存,即依赖不变,不会重新计算
- 支持缓存,只有依赖数据发生改变,才会重新进行计算
- 不支持异步,当
computed
内有异步操作时无效,无法监听数据的变化 - 可用
Vue
提供的异步函数nextTick
computed
属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的- 即基于
data
中声明过的数据或者父组件传递的props
中的数据通过计算得到的值 - 如果一个属性是由其他属性计算而来的,即这个属性(数据)依赖其他属性(数据),是多对一或者一对一,可用
computed
- 如果
computed
属性值是函数,那么默认会走get
方法;函数的返回值就是属性的属性值;在computed
中的,属性都有一个get
和一个set
方法,当数据变化时,调用set
方法。
详细描述 监听属性
watch
:
- 对
data
的监听回调,即当依赖的data
数据变化,执行回调函数 - 监听某个属性变化了,就执行一个函数
- 不支持缓存,数据被监,数据不变就不触发回调;
watch
支持异步;- 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
- 当一个属性发生变化时,需要执行对应的操作;一对多;
- 监听数据必须是
data
中声明过的数据或者父组件传递过来的props
中的数据,当数据变化时,触发其他操作 immediate
组件加载立即触发回调函数执行,即第一次渲染时就会执行这个函数deep
监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器- 监听某个数据的变化时用
watch
- 不可使用箭头函数来定义 watcher 回调函数,箭头函数绑定了父级作用域的上下文,this 将不会按照期望指向 Vue 实例
小结 ⇧
区别 | computed | watch | watchEffect |
---|---|---|---|
作用简述 | 动态显示计算值 | 监听数据变化,执行回调函数 | — |
初始数据 | 属性值 | immediate 属性可监听初始值,否则为空 |
— |
缓存 | 支持 | 不支持 | — |
异步 | 不支持 | 支持 | — |
特点1 | 不需要加括号,可以当一个属性来用,依赖于其他数据的变化 | 仅当数据变化才执行回调函数 | — |
特点2 | 多对一、一对一 | 一对多 | — |
目的 | 动态显示计算值 | 响应数据的变化,执行相应操作 | — |
5. Directive 指令 § ⇧
通过学习自定义指令来掌握
Vue
的指令,再使用内置指令除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令
在
Vue2.0
中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通DOM
元素进行底层操作,这时候就会用到自定义指令
Vue2.x
自定义指令 文档Vue3.x
自定义指令 文档- 自定义指令
v-x
,点击出现一个x
两种写法
- 全局声明一个指令
Vue.directive('directiveName', directiveOptions)
- 局部声明多个指令,在
options
中声明directives: {'directiveName': directiveOptions}
对象
main.js
|
|
目标:造出
v-y
,点击即出现一个y
main.js
|
|
- 声明的局部指令只能用在该实例中
directiveOptions
⇧
directiveOptions
的五个属性(钩子)Vue2.x
bind(el, info, vnode, oldVnode)
类似created
inserted(el, info, vnode, oldVnode)
类似mounted
updated(el, info, vnode, oldVnode)
类似updated
componentUpdated(el, info, vnode, oldVnode)
,文档unbind(el, info, vnode, oldVnode)
类似destroyed
自定义指令的生命周期钩子更名了
directiveOptions
的六个属性(钩子)Vue3.x
仿
v-on
指令 ⇧
v-on2
(省略事件委托)
main.js
|
|
inserted
时添加事件监听unbind
时解除事件监听- 简化了在
created
和beforeDestroy
时原本的DOM
操作
缩写
directiveOptions
在某些条件下可以缩写为函数,文档
指令的作用 ⇧
用于
DOM
操作
Vue
的实例/组件用于数据绑定、事件监听、DOM
更新Vue
的指令主要目的就是原生DOM
操作
减少重复
- 封装为自定义指令,复用
DOM
操作 - 封装为自定义指令,简化
DOM
操作
6. Mixin
混入 § ⇧
Mixin
减少重复
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能
就是复制
Directive
指令的作用是减少DOM
操作的重复Mixin
混入的作用是减少data
、methods
、钩子的重复
场景描述
Mixin.vue
|
|
- 假设需要在多个组件上添加
name
和time
- 在
created
、~~destroyed
~~时,打出提示,并报出存活时间 - 一共有五个组件
- 给每个组件添加
data
和钩子,共五次? - 使用
mixin
减少重复
- 给每个组件添加
- 示例链接
./mixins/log.js
|
|
|
|
mixins
用法
mixins
选项接收一个混入对象的数组mixins: [obj1, ...]
- 这些混入对象可以像正常的实例对象一样包含实例选项
options
- 当组件使用混入对象时,这些选项将会被合并到该组件本的选项形成身最终的选项,使用的是和
Vue.extend()
一样的选项合并逻辑 - 比如混入包含一个
created
钩子,而创建组件本身也有一个,那么两个函数都会被调用 Mixin
钩子按照传入顺序依次调用,并在调用组件自身的钩子之前被调用
|
|
mixin
技巧
选项智能合并
- 文档 选项合并
- 当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”
- 可以添加相应操作,同名覆盖
- 数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
- 同名钩子函数将合并为一个数组,因此都将被调用
- 混入对象的钩子将在组件自身钩子之前调用
- 值为对象的选项,例如
methods
、components
和directives
,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对
|
|
Vue.extend()
也使用同样的策略进行合并
全局混入
Vue.mixin
- 全局注册一个混入,影响注册之后所有创建的每个 Vue 实例
- 文档 不推荐使用
- 注意所有组件的
data
中需要相应的数据是否声明完整 - 范围过大,插件作者可以使用混入,向组件注入自定义的行为,以避免重复应用混入。不推荐在应用代码中使用
Vue3.x
混入(mixin) 将不再作为推荐使用,Composition
API
可以实现更灵活且无副作用的复用代码
Vue3.x
中Mixin
合并行为变更Vue3.x
中,冲突合并的结果是组件中键值对完全替代mixins
的,浅层次执行合并,并不深入比对每一项- 对于依赖对象声明的用户,建议
- 将共享数据提取到外部对象并将其用作
data
中的每个property
- 重写对共享数据的引用以指向新的共享对象
- 对于依赖
mixin
的深度合并行为的用户,建议重构代码以完全避免这种依赖,因为mixin
的深度合并非常隐式,让代码逻辑更难理解和调试 - 或使用
Composition
代替
- 将共享数据提取到外部对象并将其用作
7. Extend
继承、扩展 § ⇧
Extend
减少Mixin
的重复
- 不每次都写一个
mixins
- 使用
Vue.extend
或options.extends
MyVue.js
|
|
在组件
Child1
中使用或者new MyVue(options)
|
|
extend
是比mixin
更抽象的封装
- 写一次
extend
代替写多次mixin
,较少用到
8. Provide
和 Inject
§ ⇧
提供和注入,需求描述
- 一键换肤功能:默认蓝色,切换为红色
- 文字大小:默认正常,切换大小
- 示例链接
Provide-Inject.vue
- Provide
|
|
Child1.vue
|
|
ChangeThemeButton.vue
- Inject
|
|
.app.fontSize-normal
是同一个选择器,同时满足两种类["normal", "big", "small"].indexOf(name) >= 0
代替短路判断fontSize
默认不继承
Provide
和Inject
小结
- 在提供数据的地方写
Provide
,Provide
为函数形式,返回提供的数据的拷贝(比如字符串)- 如果在注入的地方修改,就需要再提供一个修改的函数到
Provide
,让注入拿到函数的引用 - 或者用复杂类型的引用
- 如果在注入的地方修改,就需要再提供一个修改的函数到
- 在需要数据的地方写
Inject
,Inject
为数组['InjectData1', 'InjectData2', ...]
Provide
和Inject
作用是大范围的 数据data
和 方法methods
共用,Provide
把东西提供给所有人去引用,让Inject
去调用- 注意点:示例中不可只传
themeName
而不传changeTheme
,因为themeName
的值是被复制给provide
- 不推荐传引用,变量容易失控,示例
总结 ⇧
computed
计算属性(数据)- 全局用
Vue.
- 局部用
options.
- 作用是``
- 全局用
watch
监听属性(数据)- 全局用
Vue.
- 局部用
$watch()
- 作用是``
- 全局用
directive
指令(资源)- 全局用
Vue.directive({...})
- 局部用
options.directives
- 作用是减少
DOM
操作相关的代码重复
- 全局用
mixin
混入(组合)- 全局用
Vue.mixin({...})
- 局部用
options.mixins: [mixin1, mixin2]
- 作用是减少
options
里的代码重复
- 全局用
extend
继承、扩展(组合)- 全局用
Vue.extend({...})
- 局部用
options.extends: {...}
- 作用是类似
mixin
,只是形式不同
- 全局用
provide
和inject
(组合)- 祖先组件不需要知道哪些后代组件使用它提供的 property
- 后代组件不需要知道被注入的 property 来自哪里
- 祖代提供东西,后代注入使用
- 作用是祖代提供,隔
N
代共享信息,反过来不行
参考文章
相关文章
- 无
- 作者: Joel
- 文章链接:
- 版权声明
- 非自由转载-非商用-非衍生-保持署名
- 河 掘 思 知 简