持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第11天,点击查看活动详情
Vue3的生命周期
Vue2的生命周期钩子函数:
beforeCreateCreatedbeforeMountMountedbeforeUpdateUpdatedbeforeDestroyDestroyed
Vue3的生命周期钩子函数:
setup组件实例创建之前onBeforeMount挂载DOM前onMounted挂载DOM后onBeforeUpdate更新组件前onUpdated更新组件后onBeforeUnmount卸载销毁前onUnmounted写在销毁后
总结:组合API的生命周期钩子函数有7个,可以多次使用同一个钩子函数,执行顺序和书写顺序相同
setup函数
使用细节:
setup是一个新的组件选项,作为组件中使用组合API的起点- 从组件生命周期来看,它的执行在组件实例创建之前
vue2的beforCreate执行 - 这就意味着在
setup函数中,this还不是组件实例,this此刻是undefined - 在模板中需要使用的数据和函数,需要在
setup中返回
<template>
<div>
{{name}}
</div>
</template>
<script>
export default{
setup(){
const name="张三"
return {name}
}
}
</script>
<style lang='less' scoped>
</style>
总结: setup组件初始化之前执行,它返回的数据和函数可在模板中使用
reactive函数
定义响应式数据
- reactive是一个函数,定义一个
对象成为响应式数据
const obj = reactive({})
toRef函数
- 将响应式数据对象中的某个属性变成了ref对象
toRef将对象里的某个属性转换为应式数据,并且包装成了ref对象,value是存放值的位置
cosnt name=toRef(目标对象,'属性')
const age=toRef(obj,'age') //操作的是同一个数据值, 更新时二者是同步的
const age=ref(obj.name) //拷贝了一份新的数据值单独操作, 更新时相互不影响
- 为源响应式对象上的某个属性创建一个 ref对象, 二者内部操作的是同一个数据值, 更新时二者是同步的
- 区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响
- 应用: 当要将 某个prop 的 ref 传递给复合函数时,toRef 很有用
toRefs函数
问题: reactive 对象取出的所有属性值都是非响应式的
解决: 利用 toRefs 可以将一个响应式 reactive 对象的所有原始属性转换为响应式的 ref 属性
拿出对象里的所有属性为独立响应式变量数据使用
- toRefs是一个函数,转换
响应式对象中所有属性独立响应式数据,并且值是关联的 通常用于解构或展开reactive定义的对象- 把对象中的所有属性,拿出来当变量使用
toRefs将对象里的所有属性转换为应式数据,并且每个属性都包装成了对象,value是存放值的位置
cosnt name=toRefs(目标对象)
使用场景:剥离(解构或展开)响应式对象,想使用响应式对象中的多个或者所有属性作为独立的响应式数据(在模板中不想使用obj.name,想直接使用name)
ref函数
定义简单数据为响应式数据
- ref是一个函数,定义一个简单数据类型为响应式数据
- ref函数也支持定义复杂数据类型为响应式数据
const num = ref(10)
使用场景:
- 当你明确知道需要的是一个响应式数据对象,那么就是用reactive
- 其他情况使用ref
computed函数
定义计算属性
- computed是一个函数,是用来定义计算属性的
// 只有getter的计算属性
const new = computed(()=>{
retun 1
})
// 有getter与setter的计算属性
const fullName = computed({
get () {
return 1
},
set (value: string) {
consolr.log(value)
}
})
实际上返回的是ref类型的对象
watch函数
定义侦听器
- watch是一个函数,用来定义侦听器的
watch三个参数:
1、监听的参数
2、改变后触发的函数
3、深度监听
//监听ref基本数据
const count = ref(0)
watch(count,(new,old)=>{
})
//监听reactive对象
const obj = reactive({})
watch(obj ,(new,old)=>{
})
//监听对象中某一个属性的变化,需要写成函数返回该属性的方式才能监听到
//因为obj是响应式的,obj.name不是,也就是说监听的不是响应式数据,需要通过函数来指定
const obj = reactive({})
watch(()=>obj.name ,(new,old)=>{
})
//监听多个类型数据
const count = ref(0)
const obj = ractive({})
const obj2 = ractive({
name:'123'
})
watch([count,obj,()=>obj2.name],(new,old)=>{
})
//深度监听(对象里有对象)
const obj = reactive({})
watch(obj ,(new,old)=>{
},{
// 深度监听
deep: true,
// 默认触发
immediate: true
})
ref属性
获取DOM或组件实例
vue2获取:
vue3:获取:
获取单个DOM
获取v-for遍历的DOM
获取组件和DOM方法一致
父子组件通讯
父传子:父自定义属性+子props接收
模板中使用和vue2一样
在要steup中使用,需要props参数
子传父:子使用$emit触发父自定义事件
在要steup中使用,需要context参数才能拿到emit
依赖注入
共享父组件数据
场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据
使用:provide函数和inject函数完成后代组件通讯
// 父组件将数据提供给后代组件provide
父组件: provide('属性名', 值)
//子组件接收祖先组件提供的数据inject
任意后代组件: const money = inject('属性名')
子组件如何修改传过来的值
关于子想修改值,必须通知父亲,通知的父亲是谁定义的谁修改
1、父组件可以将修改值的函数提供给后代
2、后代可以接收父组件传过来的函数,再合适的时机调用,传参修改
v-model语法糖
大概思路:
1、 v-moldel=“n“可实现父向子传值
2、 子:props里modelVale 接收
3、 子修改父组件传来的数据,v-moldel包含了async,可直接update:modelVale 修改
注意点:当组件复用时,不能多次使用 v-moldel
<myCompnets v-moldel='n'></myCompnets> //实现组件间的数组双向通信
<myCompnets v-moldel='n'></myCompnets> // v-moldel='n'不能再同一组件出现多次,组件复用也不能写,只能出现一次
vue3里,使用v-moldel实现父子组件之间的数据双向通讯时,要注意只能出现一次,组件复用也只能出现一次,不能出现多次
mixins语法
将重复逻辑的代码抽取出来,然后混入到组件中
main.js里:
1、全局混入:所有组件都混入这些逻辑代码
所有组件DOM挂载后都会打印这句话
2、局部混入
1、创建一个js文件,提供mixin逻辑
// 配置对象
export const followMixin = {
data () {
return {
loading: false
}
},
methods: {
followFn () {
this.loading = true
// 模拟请求
setTimeout(()=>{
// 省略请求代码
this.loading = false
},2000)
}
}
}
2、个别组件内使用
#组件1
<template>
<div class="container1">
<h1> 作者:周杰伦 <a href="javascript:;" @click="followFn">{{loading?'请求中...':'关注'}}</a> </h1>
<hr>
<Son />
</div>
</template>
<script>
import Son from './Son.vue'
import {followMixin} from './mixins'
export default {
name: 'App',
components: {
Son
},
mixins: [followMixin] //使用
}
</script>
##组件2
<template>
<div class="container2">
<h2> 作者:周杰伦 <button @click="followFn">{{loading?'loading...':'关注'}}</button> </h2>
</div>
</template>
<script>
import {followMixin} from './mixins'
export default {
name: 'Son',
mixins: [followMixin] //使用
}
</script>
<style scoped lang="less"></style>
总结:在vue2.0中一些可复用的逻辑可以使用mixins来封装,当是需要考虑逻辑代码冲突问题。vue3.0的组合API很好的解决了这个问题,就不在推荐使用mixins了
API(其它部分)
shallowReactive 与 shallowRef
-
shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)
-
shallowRef: 只处理了value的响应式, 不进行对象的reactive处理
-
什么时候用浅响应式呢?
- 一般情况下使用ref和reactive即可
- 如果有一个对象数据, 结构比较深, 但变化时只是外层属性变化 ===> shallowReactive
- 如果有一个对象数据, 后面会产生新的对象来替换 ===> shallowRef
readonly 与 shallowReadonly
-
readonly:
- 深度只读数据
- 获取一个对象 (响应式或纯对象) 或 ref 并返回原始代理的只读代理。
- 只读代理是深层的:访问的任何嵌套 property 也是只读的。
-
shallowReadonly
- 浅只读数据
- 创建一个代理,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换
-
应用场景:
- 在某些特定情况下, 我们可能不希望对数据进行更新的操作, 那就可以包装生成一个只读代理对象来读取数据, 而不能修改或删除
toRaw 与 markRaw
-
toRaw(变成普通对象)
- 返回由
reactive或readonly方法转换成响应式代理的普通对象。 - 这是一个还原方法,可用于临时读取,访问不会被代理/跟踪,写入时也不会触发界面更新。
- 返回由
-
markRaw(让对象再也不能变成代理对象)
-
标记一个对象,使其永远不会转换为代理。返回对象本身
-
应用场景:
- 有些值不应被设置为响应式的,例如复杂的第三方类实例或 Vue 组件对象。
- 当渲染具有不可变数据源的大列表时,跳过代理转换可以提高性能。
-
响应式数据的判断
- isRef: 检查一个值是否为一个 ref 对象
isRef(ref({}))
- isReactive: 检查一个对象是否是由
reactive创建的响应式代理
isReactive(reactive({}))
- isReadonly: 检查一个对象是否是由
readonly创建的只读代理
isReadonly(readonly({}))
- isProxy: 检查一个对象是否是由
reactive或者readonly方法创建的代理
isProxy(readonly({}))
isProxy(reactive({}))