助你上手Vue3全家桶之Vue3教程
- 前言
- 1,setup
- 2,ref 创建响应式数据
- 3,reactive 创建响应式数据
- 4,computed 计算属性
- 5,watch 监听
- 6,watchEffect 监听回调
- 7,生命周期
- 8,toRef 创建ref
- 9,toRefs 响应式转换
- 10,shallowReactive 响应式外层转换
- 11,shallowRef 基本数据响应式
- 12,readonly 响应式变只读
- 13,shallowReadonly 响应式变只读
- 14,toRaw 响应式变非响应式
- 15,markRaw 标记永远不响应式
- 16,customRef 依赖更新控制
- 17,provide & inject 通信
- 18,响应式数据的判断
- 19,teleport 移动dom组件
- 20,Suspense 异步渲染组件
- 21,全局API调整
- 22,移除api
- 23,Ref 获取DOM
- 24,emits 自定义事件
- 25,$nextTick 异步更新
- 26,hook 生命周期事件
前言
这些内容是博主在学习过程中记录下来的,有一些不重要的点就跳过了,需要时自行查询文档。其实V2
到V3
的学习成本不高,熟悉V2
的话,看完这篇文章就可以上手V3
。
1,setup
setup
是所有Composition API
的容器,值为一个函数。组件中所用到的数据、方法等等,均要配置在setup
中,它会在beforeCreate
之前执行一次,注意:V3
里this
不再是指向Vue
实例,访问this
会是undefined
1.1,返回值
- 若返回一个对象,则对象中的属性、方法, 在模板中均可以直接使用。
- 若返回一个渲染函数:则可以自定义渲染内容。
1.2,注意点
尽量不要与V2配置混用
V2
配置(data
、methos
、computed
...)中可以访问到setup
中的属性、方法。
但在setup
中不能访问到V2
配置(data
、methods
、computed
...)。
如果有重名, setup
优先。
setup不能是一个async函数
因为返回值不再return
的对象, 而是promise
, 模板看不到return
对象中的属性。(后期也可以返回一个Promise
实例,但需要Suspense
和异步组件的配合)
1.3,语法
<script>
import { ref, reactive } from 'vue'
export default {
name: 'Home',
setup(props, context) {
const title = ref('标题')
const data = reactive({
value: '哈哈哈'
})
return {
title,
data
}
}
}
</script>
1.4,setup的参数
-
props:值为对象,包含组件外部传递过来,且组件内部声明接收了的属性
-
context:上下文对象
- attrs: 值为对象,包含组件外部传递过来,但没有在
props
配置中声明的属性, 相当于this.$attrs
- slots: 收到的插槽内容, 相当于
this.$slots
- emit: 分发自定义事件的函数, 相当于
this.$emit
- attrs: 值为对象,包含组件外部传递过来,但没有在
2,ref 创建响应式数据
使用ref
可以创建一个包含响应式数据的引用对象(reference对象,简称ref对象),可以是基本类型、也可以是对象。
语法
// 创建
const xxx = ref(value)
// 使用
xxx.value
// 在模板中
<div>{{xxx}}</div>
3,reactive 创建响应式数据
定义一个对象类型的响应式数据,内部基于ES6
的Proxy
实现,通过代理对象操作源对象内部数据进行操作
语法
// 创建
const xxx = reactive({
xxx: ''
})
// 使用
xxx.xxx
4,computed 计算属性
与V2
中computed
配置功能一致
语法
import { computed } from 'vue'
setup(){
// 简写语法
let fullName = computed(() => {
return person.firstName + '-' + person.lastName
})
// 完整语法
let fullName = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return fullName
}
5,watch 监听
与V2
中watch
配置功能一致,语法有点改动
语法
- 情况一:监视
ref
定义的响应式数据
watch(sum, (newValue, oldValue) => {
console.log('sum变化了', newValue, oldValue)
}, {immediate:true})
- 情况二:监视多个
ref
定义的响应式数据
watch([sum, msg], (newValue,oldValue) => {
console.log('sum或msg变化了', newValue,oldValue)
})
- 情况三:监视
reactive
定义的响应式数据
// 若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue
// 若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}, { immediate:true, deep:false }) // 此处的deep配置不再奏效
- 情况四:监视
reactive
定义的响应式数据中的某个属性
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job变化了', newValue, oldValue)
}, { immediate:true, deep:true })
- 情况五:监视
reactive
定义的响应式数据中的某些属性
watch([() => person.job, () => person.name], (newValue, oldValue) => {
console.log('person的job变化了', newValue, oldValue)
}, { immediate:true, deep:true })
- 特殊情况:此处由于监视的是
reactive
素定义的对象中的某个属性,所以deep配置有效
watch(() => person.job, (newValue, oldValue) => {
console.log('person的job变化了', newValue, oldValue)
}, { deep:true })
6,watchEffect 监听回调
和watch
的区别是,watch
既要指明监视的属性,也要指明监视的回调。而watchEffect
,不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性,不用写返回值。
语法
// 回调中用到的数据只要发生变化,则直接重新执行回调
watchEffect(() => {
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
7,生命周期
生命周期全都写在setup
中
7.1,改变
- beforeDestroy 改名为 beforeUnmount
- destroyed 改名为 unmounted
- beforeCreate => setup
- created => setup
- beforeMount => onBeforeMount
- mounted => onMounted
- beforeUpdate => onBeforeUpdate
- updated => onUpdated
- beforeUnmount => onBeforeUnmount
- unmounted => onUnmounted
7.2,语法
setup() {
onMounted(() => {
console.log('mounted')
})
}
8,toRef 创建ref
创建一个ref
对象,其value
值指向另一个对象中的某个属性
语法
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
// 传递props
export default {
setup(props) {
useSomeFeature(toRef(props, 'foo'))
}
}
9,toRefs 响应式转换
将响应式对象转换为普通对象,其中结果对象的每个property
都是指向原始对象相应property
的ref
语法
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
// 此时state和stateAsRefs是关联的
10,shallowReactive 响应式外层转换
只处理对象最外层属性的响应式(浅响应式)。适用于:一个对象数据,结构比较深, 但变化时只是外层属性变化
语法
const state = shallowReactive({
foo: 1,
nested: {
bar: 2
}
})
11,shallowRef 基本数据响应式
只处理基本数据类型的响应式, 不进行对象的响应式处理。适用于:一个对象数据,后续功能不会修改该对象中的属性,而是生新的对象来替换
语法
const shallow = shallowRef({
greet: 'Hello, world'
})
12,readonly 响应式变只读
让一个响应式数据变为只读的(深只读),应用于不希望数据被修改时
语法
const shallow = shallowRef({
greet: 'Hello, world', // 只读
nested: {
bar: 2 // 只读
}
})
13,shallowReadonly 响应式变只读
让一个响应式数据变为只读的(浅只读),应用于不希望数据被修改时
语法
const shallow = shallowReadonly({
foo: 1, // 只读
nested: {
bar: 2 // 非只读
}
})
14,toRaw 响应式变非响应式
将一个由reactive生成的响应式对象转为普通对象,对这个普通对象的所有操作,不会引起页面更新。
语法
const foo = {}
const Foo = reactive(foo)
console.log(toRaw(Foo) === foo) // true
15,markRaw 标记永远不响应式
标记一个对象,使其永远不会再成为响应式对象,有些值不应被设置为响应式的,例如复杂的第三方类库等,当渲染具有不可变数据源的大列表时,跳过响应式转换可以提高性能。
语法
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false
// 嵌套在其他响应式对象中时也可以使用
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false
16,customRef 依赖更新控制
创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收track
和trigger
函数作为参数,并且应该返回一个带有get
和set
的对象。
语法
<script>
import { customRef } from 'vue'
export default {
name: 'Home',
setup() {
// 实现防抖函数
const fn = function(value, delay = 500) {
let timeout
return customRef((track, trigger) => {
return {
get() {
track()
return value
},
set(newValue) {
clearInterval(timeout)
timeout = setTimeout(() => {
console.log(newValue)
value = newValue
trigger()
}, delay)
}
}
})
}
const keyword = fn('', 500)
return {
keyword
}
}
}
</script>
17,provide & inject 通信
实现祖与后代组件间通信,父组件有一个provide
选项来提供数据,后代组件有一个inject
选项来开始使用这些数据
语法
// 祖组件
setup(){
let car = reactive({ name:'奔驰', price:'40万' })
provide('car', car)
}
// 后代组件
setup(props, context){
const car = inject('car')
return { car }
}
18,响应式数据的判断
18.1,isRef
检查一个值是否为一个ref
对象
语法
const val = ref('xxx')
isRef(val) // true
18.2,isReactive
检查一个值是否为一个isReactive
对象
语法
const val = isReactive({})
isRef(val) // true
18.3,isReadonly
检查一个对象是否是由readonly
创建的只读代理
语法
const state = reactive({
name: 'John'
})
console.log(isReactive(state)) // true
18.4,isProxy
检查对象是否是由reactive
或readonly
创建的proxy
语法
const state = reactive({
name: 'John'
})
console.log(isProxy(state)) // true
19,teleport 移动dom组件
Teleport
提供了一种干净的方法,允许我们控制在DOM
中哪个父节点下渲染了HTML
,而不必求助于全局状态或将其拆分为两个组件。
语法
<teleport to="移动位置">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗</h3>
<button @click="isShow = false">关闭弹窗</button>
</div>
</div>
</teleport>
// to的格式
<teleport to="#some-id" />
<teleport to=".some-class" />
<teleport to="[data-teleport]" />
// disabled的格式
<teleport to="#popup" :disabled="displayVideoInline">
<video src="./my-movie.mp4">
</teleport>
20,Suspense 异步渲染组件
等待异步组件时先渲染一些额外内容,让应用有更好的用户体验
语法
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template #default>
<Child/>
</template>
<template #fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>
import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(() => import('./components/Child.vue'))
components: {
Child
}
21,全局API调整
将全局的API,即:Vue.xxx调整到应用实例(app)上
V2的api | V3的api |
---|---|
Vue.config.xxxx | app.config.xxxx |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
22,移除api
名称 | 现状 |
---|---|
Vue.config.productionTip | 已移除 |
config.keyCodes | 已移除 |
$children | 已移除 |
$listeners | 已移除 |
$on | 已移除 |
$off | 已移除 |
$once | 已移除 |
filters | 已移除 |
.native | 已移除 |
23,Ref 获取DOM
由于V3
中不在存在this
,所以ref
的获取调整了
23.1,单个ref
语法
<div ref="Qrcode" class="qr_codeode_url" />
import { ref } from 'vue'
export default {
setup() {
const Qrcode = ref(null)
// 挂载后
onMounted(() => {
console.log(Qrcode.value)
})
return {
Qrcode
}
}
}
23.2,循环中的ref
V3
中在for
循环元素上绑定ref
将不再自动创建$ref
数组。要从单个绑定获取多个ref
,请将ref
绑定到一个更灵活的函数上
语法
<div v-for="item in list" :ref="setItemRef"></div>
import { onBeforeUpdate, onUpdated } from 'vue'
export default {
setup() {
let itemRefs = []
const setItemRef = el => {
if (el) {
itemRefs.push(el)
}
}
onBeforeUpdate(() => {
itemRefs = []
})
onUpdated(() => {
console.log(itemRefs)
})
return {
setItemRef
}
}
}
itemRefs
不必是数组:它也可以是一个对象,其ref
可以通过迭代的key
被设置- 如有需要,
itemRef
也可以是响应式的,且可以被侦听
24,emits 自定义事件
定义一个组件可以向其父组件触发的事件
// 在子组件中
<h1 @click="father">{{ msg }}</h1>
export default {
name: 'HelloWorld',
props: {
msg: {
type: String,
default: ''
}
},
emits: ['close'],
setup(props, { emit }) {
const father = function() {
emit('close', 'child')
}
return {
father
}
}
}
// 在父组件中
<HelloWorld :msg="msg" @click="fn" @close="fn2" />
25,$nextTick 异步更新
使用方式修改
import { nextTick } from 'vue'
nextTick(() => {
// ...
})
26,hook 生命周期事件
通过事件来监听组件生命周期中的关键阶段
语法
// V2的语法
<template>
<child-component @hook:updated="onUpdated">
</template>
// V3的语法
<template>
<child-component @vnode-updated="onUpdated">
</template>
// 驼峰写法
<template>
<child-component @vnodeUpdated="onUpdated">
</template
如果看了觉得有帮助的,我是@上进的鹏多多,欢迎 点赞 关注 评论;END
PS:在本页按F12,在console中输入document.querySelectorAll('.diggit')[0].click(),有惊喜哦
公众号
往期文章
- 助你上手Vue3全家桶之Vue-Router4教程
- 助你上手Vue3全家桶之VueX4教程
- 使用nvm管理node.js版本以及更换npm淘宝镜像源
- 超详细!Vue-Router手把手教程
- vue中利用.env文件存储全局环境变量,以及配置vue启动和打包命令
- 微信小程序实现搜索关键词高亮
- 超详细!Vue的九种通信方式
- 超详细!Vuex手把手教程
个人主页