本篇文章讲述主要讲述vue3的变化,力求一篇文章可以直接上手vue3.首先推荐一个vue3小插件。
支持vue3语法的高亮显示,以及语法监测。最重要的是可以提供代码补全,在vue3的书写中再也不用手动补充value,这是我这个插件最喜欢的功能
组合式API和选项式API
vue3出现之前都使用的式选项的API,这种写法将用的数据、方法、计算属性、监听等都分布在data、methods、computed等,这样并不利于代码后期的维护和复用。
vue3出现之后,就有了组合式API,可以向传统js一样,使用函数的方式组织代码,让相关联的代码组装在一起。这种写法会使代码更加优雅,更容易阅读和维护
#setup
setup是vue3中新出现的产物,vue3中摒弃了大量使用this的写法,将组件中用到的数据、方法等都分布在setup中。
setup的特点
- 模板中使用的内容需要在setup中返回
- setup中的this是undefined
- setup函数在beforeCreated之前就执行了
vue2和vue3的一些兼容问题
vue3中可以兼容vue2的写法,那就涉及到一些兼容问题,这里浅谈一下。
vue2的配置中是可以访问到setup中的属性和方法。
但是在setup中是无法读取vue2配置中的东西。因为在vue2中所有的数据以及方法调用都需要使用到this,但是在setup中是没有this的。
当两种写法发生冲突时,setup优先,这里并不建议两种写法同时使用,当然如果是项目必要,那就心里骂几句。
setup语法糖
setup使用的时候,需要将所使用到的数据和方法return出去,非常的繁琐。setup语法糖就很好的解决了这个问题,直接将setup写入script中就可以
<script setup lang='ts'></script>
ref
基本类型的响应式数据
vue3中不再使用data来统一定义数据,那么如何使数据变成响应式,就需要用到一些API
ref可以定义基本类型的响应式数据。
语法:let a = ref(xxx) // xxx为基本类型的数据
返回值:返回一个RefImpl的实例对象,简称ref对象。ref的value是响应式的,因此在使用ref定义的响应式数据时,需要.value,如a.value。模板中正常使用即可。
对象类型的响应式数据
语法:let obj = ref({a:1,b:2,c:3})
使用:obj.value.a
ref定义响应式数据和基本类型数据的语法相同的,但是在使用的时候需要注意value。value并不是跟在具体属性后面,因为ref定的响应式数据是对象本身
reactive
reactive不可以创建基本类型的响应式数据,会报错
语法:
let obj = reactive({a:1,c:2,c:3})
let arr = reactive([
{
name:'小明',
age:16
},
{
name:'小红',
age:15
}
])
reactive定义的响应式数据直接使用即可。
reactive数据重新赋值之后,不再是响应式数据。如果需要重新赋值新的对象需要使用object.assign()
toRef与toRefs
toRef和toRefs都是将对象中的属性提取出来且保持响应性。区别就是s可以批量取出
let obj = reactive({name:'张三',age:12,address:'q34'})
// toRefs
let {name,age,address} = toRefs(obj)
// toRef
let name = toRef(obj,'name')
computed计算属性
计算属性的用法和vue2一致,这里不做详细赘述,只是简单成熟vue3中的写法有什么不同
// vue2中
compute:{}
// 使用的时候使用this去点computed中的变量
// vue3,只能写一次只能操作一个变量
let a = computed({
return ...
})
// 使用的时候a.value
watch监听
监听ref定义的基本数据类型
监听的是基本数据类型的value值
// 监视,情况一:监视【ref】定义的【基本类型】数据
const stopWatch = watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
if(newValue >= 10){
// 停止监听
stopWatch()
}
})
监听ref定义的对象数据类型
监听的是数据的存储地址,若想监听对象内部的属性,需要开启深度监听。
注:
- 如果修改对象的属性,newVal和oldVal一致(都是修改后的值),因为修改的是同一对象
- 若修改的整个对象,newVal是新值,oldVal是旧值。因为不是同一个对象
监听reactive监听的对象类型数据
监听reactive创建的对象类型数据时,默认已经开启了深度监听。
监听对象类型的某个属性
无论是ref定义的对象类型数据还是reactive定义的,都需要注意一下几点:
1、若该属性是基本数据类型,需要写成函数形式
2、若属性仍然是对象数据类型,可以直接写,但是建议直接写成函数形式
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
//监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
/* watch(()=> person.name,(newValue,oldValue)=>{
console.log('person.name变化了',newValue,oldValue)
}) */
// 监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
watch(()=>person.car,(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
监听多个数据
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
watchEffect
概念:立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数。
watch和watchEffect对比
- 都可以监听数据的变化,但是监听数据的变化方式不同
- watch只能明确的监听某个数据的变化
- watchEffect不用明确监听某个数据(函数中需要哪些属性,就监听哪些)
// 用watch实现,需要明确的指出要监视:temp、height
watch([temp,height],(value)=>{
// 从value中获取最新的temp值、height值
const [newTemp,newHeight] = value
// 室温达到50℃,或水位达到20cm,立刻联系服务器
if(newTemp >= 50 || newHeight >= 20){
console.log('联系服务器')
}
})
// 用watchEffect实现
const stopWtach = watchEffect(()=>{
// 室温达到50℃,或水位达到20cm,立刻联系服务器
if(temp.value >= 50 || height.value >= 20){
console.log(document.getElementById('demo')?.innerText)
console.log('联系服务器')
}
// 水温达到100,或水位达到50,取消监视
if(temp.value === 100 || height.value === 50){
console.log('清理了')
stopWtach()
}
})
自定义hook
hook本质上是一个函数,有点类似于vue2中的混入。可以让代码更加清晰
useSum.ts
中内容如下:
import {ref,onMounted} from 'vue'
export default function(){
let sum = ref(0)
const increment = ()=>{
sum.value += 1
}
const decrement = ()=>{
sum.value -= 1
}
onMounted(()=>{
increment()
})
//向外部暴露数据
return {sum,increment,decrement}
}
组件中具体使用:
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="increment">点我+1</button>
<button @click="decrement">点我-1</button>
<hr>
<img v-for="(u,index) in dogList.urlList" :key="index" :src="(u as string)">
<span v-show="dogList.isLoading">加载中......</span><br>
<button @click="getDog">再来一只狗</button>
</template>
<script lang="ts">
import {defineComponent} from 'vue'
export default defineComponent({
name:'App',
})
</script>
<script setup lang="ts">
import useSum from './hooks/useSum'
import useDog from './hooks/useDog'
let {sum,increment,decrement} = useSum()
let {dogList,getDog} = useDog()
</script>