目录
13.vue2中v-model是一个语法糖,那具体是怎么实现的?
vue
1.vue生命周期
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程
初始化
在beforeCreate生命周期函数执行的时候,data和method 还没有初始化
在created 生命周期函数执行的时候,data和method已经初始化完成
挂载
在beforeMount 生命周期函数执行的时候,已经编译好了模版字符串、但还没有真正渲染到页面中去
在mounted 生命周期函数执行的时候,已经渲染完,在视图中可以看到页面
更新
在beforeUpdate生命周期函数执行的时候,已经可以拿到最新的数据,但还没渲染到视图中去。
在updated生命周期函数执行的时候,已经把更新后的数据渲染到视图中去了。
销毁
在beforeDestroy 生命周期函数执行的时候,实例进入准备销毁的阶段、此时data 、methods 、指令等还是可用状态
在destroyed生命周期函数执行的时候,实例已经完成销毁、此时data 、methods 、指令等都不可用
三个不常用
keep-alive 主要用于保留组件状态或避免重新渲染。
activated只有在keep-alive 组件激活时调用。
deactivated只有在keep-alive 组件停用时调用。
errorCapured 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false
以阻止该错误继续向上传播
2.vue.use()
在 install 里我们可以拿到 Vue 那么和 Vue 相关的周边工作都可以考虑放在 Vue.use()
方法里,比如:
- directive注册
- mixin注册
- filters注册
- components注册
- prototype挂载
- ...
通过全局方法 Vue.use()
使用插件;也可以将使用理解成注册
Vue.use(js对象/function,参数)
js对象:{
install(Vue,options){
// 在Vue.use后,该方法会执行
}
}
function:function(Vue,options){
// 在Vue.use后,该方法会执行
}
常见的注册场景
import Router from 'vue-router'
Vue.use(Router)
import Vuex from 'vuex'
Vue.use(Vuex)
import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts
echarts 用 Vue.use() 来注册
main.js
import Vue from 'vue'
import echarts from './echarts.js'
Vue.use(echarts)
new Vue({
...
})
echarts.js
import Echarts from 'echarts'
export default {
install(Vue){
Vue.prototype.$echarts = Echarts
}
}
3.自定义指令
可以看这个 8个非常实用的vue自定义指令
除了默认的内置指令 (v-model
和 v-show
)等之外,Vue 也允许注册自定义指令。当我们需要对普通 DOM 元素进行底层操作时,这时候就会用到自定义指令。
指令定义函数提供了几个钩子函数(可选):
-
bind
: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。 -
inserted
: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。 -
update
: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。 -
componentUpdated
: 被绑定元素所在模板完成一次更新周期时调用。 -
unbind
: 只调用一次, 指令与元素解绑时调用。
接下来我们来看一下钩子函数的参数 (包括 el
,binding
,vnode
,oldVnode
) 。
-
el: 指令所绑定的元素,可以用来直接操作 DOM 。
-
binding 一个对象,包含以下属性 (具体的vue.js文档查看)
-
vnode: Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。
-
oldVnode: 上一个虚拟节点,仅在
update
和componentUpdated
钩子中可用。
除了 el
之外,其它参数都应该是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行
添加一个自定义指令,有两种方式:
-
通过 Vue.directive() 函数注册一个全局的指令。
-
通过组件的 directives 属性,对该组件添加一个局部的指令。
创建全局指令:
需要传入指令名称以及一个包含指令钩子函数的对象,该对象的键即钩子函数的函数名,值即函数体,钩子函数可以有多个。
Vue.directive('指令名',{
自定义指令的生命周期
bind:绑定时,自定义指令绑定于相应dom时执行(类似于vue生命周期的beforeMount)
bind(dom,obj,vnode){
dom:指令所在dom
obj:{
属性名
修饰符
值
}
vnode:虚拟dom节点信息
context:能获取指令所在组件的实例对象
}
inserted:指令所在dom添加到父节点时执行,渲染时(类似于以前的mounted)
inserted(dom,obj,vnode){
},
update:更新时,不保证更新完成(指令所在组件有更新时执行),不保证该更新和当前指令所在dom有关
update(dom,obj,vnode){
dom:当前指令所在dom
obj:{
属性名
修饰符
值
}
vnode:context:获取指令所在组件的实例对象
}
componentUpdated:更新完成时,指令所在组件更新完成(类似于以前vue生命周期的updated)
unbind:解除绑定,类似于beforeDestroy
})
局部自定义指令
directieves:{
指令名:{
bind,
inserted,
update,
componentUpdated,
unbind
}
}
应用场景
图片出错的自定义指令。在做过的一个项目中,有一个上传头像的部分,上传了一张图片后,它的地址有错误,就需要自己给定一个默认的图片,有正确的图片就放正确的图片,图片地址错误就放默认的图片。就用到了自定义指令,v-images 当地址是错误的时候,就需要用到自己自定义的一个默认的图片
批量注册指令,新建 directives/index.js
文件
import copy from './copy'
import longpress from './longpress'
// 自定义指令
const directives = {
copy,
longpress,
}
export default {
install(Vue) {
Object.keys(directives).forEach((key) => {
Vue.directive(key, directives[key])
})
},
}
在 main.js
引入并调用
import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)
4.computed和watch有何区别?
计算属性computed :
1.computed
是依赖已有的变量来计算一个目标变量,大多数情况都是多个变量
凑在一起计算出一个变量
2.
并且computed
具有缓存机制
,依赖值不变的情况下其会直接读取缓存进行复用
3.computed
不能进行异步操作,
当computed内有异步操作时无效,无法监听数据的变化
4.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的属性都有一个get和一个set方法,当数据变化时,调用set方法。
5.使用 给计算属性的变量赋值时使用全写 需要进行计算求和的时候使用到
computed: {
属性名: {
set(值) { // set()接收要赋予的值
},
get() {
return "值" // get()里要返回给这个计算属性具体值
}
}
}
侦听属性watch:
1.watch
是监听某一个变量的变化,并执行相应的回调函数,通常是一个变量
的变化决定多个变量
的变化
2.不支持缓存,数据变,直接会触发相应的操作
3.watch
可以进行异步操作
4.
监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值; immediate:组件加载立即触发回调函数执行
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用
5.使用: 当进行全选与饭选的时候用到
监听一个基本数据时:
watch: {
value () {
// do something
}
}
监听一个引用数据类型时:
watch: {
需要监听的属性名 obj: {
handler (newVal,oldVal) { // 执行回调
// do something
},
deep: true, // 是否进行深度监听 复杂数据类型
immediate: true // 是否初始执行handler函数, 立即执行
}
}
总结:
当目的是进⾏数值计算,且依赖于其他数据,那么推荐使用 computed
当需要在某个数据发生变化的, 同时做⼀些稍复杂的逻辑操作,那么推荐使⽤ watch
5.过滤器的使用filters
过滤器就是一个函数, 传入值返回处理后的值,被用于转换格式,常见的文本格式化,将值转换为另一种形式
Vue3中舍弃了filters 过滤器,用函数替代了过滤器
过滤器可以用在两个地方:双花括号插值和v-bind表达式
全局的用Vue.filter():Vue.filter("过滤器名", (值) => {return "返回处理后的值"})
局部的用filters属性: filters: {过滤器名字: (值) => {return "返回处理后的值"}
过滤器传参: vue 变量 | 过滤器传参
多个过滤器: vue变量 | 过滤器1 | 过滤器2
应用场景: 时间格式化用到过滤器,有一个禁用和启用的状态改变用到了过滤器,人员员工的聘用形式用到了过滤器:过滤器的名字:function() {return} 导入,全局过滤器注册, 使用{vue变量:过滤器名字}
6.vuex 的理解
vuex的本质是一个对象,是响应式的,管理公共数据的工具,用于多个组件之间的数据共享。vuex的出现是为了解决web组件化开发的过程中,各组件之间传值的复杂和混乱的问题。
整个虚线部分就是Vuex,我们可以把它看成一个公共仓库store。store中有Actions(行为)、Mutations(变动)和State(状态)。整个的逻辑是组件通过Dispatch调用Actions中的方法,Actions通过Commit调用Mutations中的方法,Mutatisons改变State中的值。
vuex是全局状态管理库,可以通过它来进行全局数据流的管理。
state: 存放多个组件都用得到的公共数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态(相当于data)
mutations: 存放操作数据的方法,修改state (相当于methods)
actions: 存放一些异步操作 (也可以进行一些同步处理) 注意: actions是不能直接修改state数据的, 需要提交mutation
getters: 存放基于state计算出来的一些值 (相当于计算属性)
modules: 分模块, 项目大了, 推荐分模块管理,用到映射,先从vuex中导入mapState,然后使用
注意点: 分模块了, 默认muations, actions, getters 注册到全局的, 一般会开启命名空间,语法: namespaced: true 可以解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名。
简述vuex的数据传递流程
当组件进行数据修改的时候,我们需要调用dispatch来触发actions里面的方法。actions里面的每个方法中都会有一个 commit 方法,当方法执行的时候,会通过commit 来触发 mutations 里面的方法来进行数据的修改, mutations 里面的每个函数都会有一个 state 参数, 这样就可以在 mutations 里面进行state 的数据修改, 当数据修改完成后, 会传导给页面,页面的数据也会发生改变。
7.父子组件的生命周期钩子
0. 加载渲染过程
父 beforeCreate 父 created 父 beforeMount
子 beforeCreate 子 created 子 beforeMount 子 mounted 父 mounted
1. 子组件更新过程
子 beforeUpdate 子 updated
2. 父组件更新过程 父组件更新的数据子组件有使用!
父 beforeUpdate 子 beforeUpdate 子 updated 父 updated
3. 销毁过程
父 beforeDestroy 子 beforeDestroy 子 destroyed 父 destroyed
8.v-mode和.sync的对比
v-model 只能使用一次,一个页面中只能使用一次
.async可以使用多次
vue3中没有async 用函数来替代
v-model = " 父组件属性" 就相当于 :value= “父组件的属性” @ input = "父组件的属性" = $event
v-model
父组件中的子组件标签上 :value="父组件属性&