1.组合式API
组合式API是将同一个逻辑关注点代码收集在一起,避免组件的逻辑内容复杂,难以梳理。为了使用组合式API,我们首先需要一个可以实际使用它的地方,在vue组件中,我们将此位置成为setup。
组合式API的基本使用和ref:
<template>
<div>
<button @click="changeA">change</button>
<button @click="changeCounter">changeCounter</button>
<h2>{
{ a }}--{
{ counter }}</h2>
</div>
</template>
<script>
import {ref} from "vue"
export default {
// 注意:setup是在组件创建前执行,也就是在beforeCreate和created生命函数之前执行,相当于包含了这两个生命周期,所以在组合式API中没有这俩个生命周期函数。
setup(){
let a="hello"
// 在setup中无法使用this,因为找不到组件实例
console.log(a); //hello
function changeA(){
a="hi"
console.log(a);//点击按钮数据没有改变,因为数据不是响应式的
}
function changeCounter(){
counter.value++
}
// 通过ref定义响应式变量
const counter=ref(0) //ref()返回的是带有value属性的对象
// 将变量暴露出去
return{a,changeA,counter,changeCounter}
}
}
</script>
2.组合式API中的reactive和toRefs:
<template>
<div>
<button @click="changeObj">changeObj</button>
<h2>{
{ obj.name }}</h2>
<p>{
{ name }}---{
{ children.name }}</p>
</div>
</template>
<script>
// ref定义Number和String,reactive定义引用数据类型,toRefs让解构后的数据重新变成响应式
// import {ref,reactive} from "vue"
import {reactive,toRefs} from "vue"
export default {
setup(){
const obj=reactive({
name:"张三",
age:18,
children:{
name:"小张"
}
})
function changeObj(){
obj.name="李四",
obj.children.name="小李"
}
// let {name,children}=toRefs(obj)
// 通过ES6扩展运算符进行解构使得对象中的属性不是响应式的,...obj,此时{
{}}内不在需要obj开头
return{obj,changeObj,...toRefs(obj)}
}
}
</script>
3.在setup中使用watch:
组合式API可以使用从Vue导入的watch函数执行相同的操作,他接受三个参数:
①一个想要侦听的响应式引用或getter函数
②一个回调
③可选的配置选项
<template>
<div>
<button @click="changeNum">changeNum</button>
<h2>{
{num }}</h2>
<button @click="changeObj">changeName</button>
<p>{
{ obj.name }}</p>
</div>
</template>
<script>
import {reactive,ref,watch,watchEffect} from "vue"
export default {
setup(){
let num=ref(0)
const obj=reactive({
name:"张三",
age:18,
})
watch(num,(newVal,oldVal)=>{
console.log(newVal,oldVal);
})
watch(obj,(newVal,oldVal)=>{
console.log(newVal,oldVal);//Proxy {name: '李四', age: 18} Proxy {name: '李四', age: 18}
})
//watchEffect(回调函数)注意:不需要指定监听的属性,组件初始化的时候会执行一次回调函数,自动收集依赖
watchEffect(()=>{
console.log(obj.name);
})
// watch和watchEffect的区别
//1.watchEffect不需要指定监听的属性,自动收集依赖,只要在回调中引用到了响应式的属性,只要这些属性发生改变,回调就会执行。watch只能监听指定的属性,做出回调函数的执行,可以侦听多个在vue3里
//2.watch可以获取新旧值,watchEffect拿不到
// 3.watchEffect在组件初始化的时候就会自动执行一次,用来收集依赖,watch不需要,一开始就指定了。
function changeNum(){
num.value++
}
function changeObj(){
obj.name="李四"
}
return{obj,changeObj,num,changeNum}
}
}
</script>
4.在setup中使用computed:
<script>
import {ref,computed} from "vue"
export default {
setup(){
const msg=ref("helloworld")
//返回一个带有value属性的对象
const reverseMsg=computed(()=>{
return msg.value.split("").reverse().join("")
})
console.log(reverseMsg.value);
return{msg,reverseMsg}
}
}
</script>
5.生命周期钩子在setup中的使用
通过在生命周期钩子前面加上"on",来访问组件的生命周期钩子。
<script>
import {onBeforeMount,onMounted,onBeforeUpdate,onUpdated} from "vue"
export default {
setup(){
// 生命周期钩子函数是一个回调函数,在setup中生命周期钩子函数可以多次使用
onBeforeMount(()=>{
console.log("onBeforeMount");
})
onBeforeMount(()=>{
console.log("onBeforeMount");
})
onMounted(()=>{
console.log("onMounted");
})
return{}
}
}
</script>
6.setup函数中的两个参数之props
setup函数中的第一个参数是props,他是响应式的,当传入新的prop时,他将被更新,并且props是响应式的,不能使用ES6解构,他会消除props的响应性,如果需要解构,可以使用toRefs函数来完成此操作。
//父组件
<template>
<div>
<Children :message="message" />
</div>
</template>
<script>
import Children from "./components/Children.vue";
export default {
data(){
return{
message:"hello"
}
},
components:{
Children
},
setup(){
return{}
},
}
</script>
//子组件
<template>
<div>
123
</div>
</template>
<script>
export default{
props:{
message:{
type:String,
default:"你好"
}
},
setup(props){
console.log(props.message);
}
}
</script>
7.setup函数中的两个参数之context
传递给setup函数的第二个参数是context,context是一个普通的js对象,暴露了其他可能在setup中有用的值,他不是响应式的,可以正常使用解构。
根组件
<template>
<div>
<!-- <Children :message="message" class="box" @sendCounter="getParent"/> -->
<Children class="box" id="content" ref="content" @sendCounter="getParent"/>
</div>
</template>
<script>
import Children from "./components/children.vue";
export default {
data(){
return{
message:"hello",
msg:""
}
},
methods:{
getParent(value){
console.log(value);
}
},
mounted(){
// 此处调用的是expose暴露出来的方法
this.$refs.content.senParent()
},
components:{
Children
},
setup(){
return{}
},
}
</script>
子组件
<template>
<div>
<button @click="senParent">向父组件发送数据</button>
</div>
</template>
<script>
import { ref,h} from "vue"
export default{
props:{
message:{
type:String,
default:"你好"
}
},
setup(props,context){
// console.log(props.message);
// console.log(context);
// 可以拿到父组件定义的选择器,如class,id等。(非响应式对象,等同于$attrs)
console.log(context.attrs);
//插槽(非响应式对象,等同于$slots)
console.log(context.slots);
//context.emit触发事件(方法,等同于$emit)
const counter=ref(20)
function senParent(){
context.emit("sendCounter",counter.value)
//context.expose暴露公共property(函数)
}
// return{senParent}
context.expose({
senParent,counter
})
return ()=>h("div",counter.value)
}
}
</script>
8.setup中的provide和inject
在setup中使用provide和inject时,我们首先从vue导入provide和inject方法,这使我们能够调用provide来定义每个property,而inject导入之后就可以调用它来定义暴露给我们的组件方式。
provide函数允许你通过两个参数定义property:
①name(String类型)
②value
inject函数有两个参数:
①要inject的property的name
②默认值(可选)
父组件:
<template>
<div>
<Children class="box" id="content" ref="content" />
<button @click="changeName">改变</button>
</div>
</template>
<script>
import Children from "./components/children.vue";
import { provide,ref } from "vue";
export default {
data(){
return{
message:"hello",
msg:""
}
},
components:{
Children
},
setup(){
// 非·响应式的
// provide("name","张三")
// 响应式的
const nm=ref("张三")
provide("name",nm)
function changeName(){
nm.value="李四"
}
return{changeName}
},
}
</script>
子组件:
<template>
<div>
{
{ value }}
</div>
</template>
<script>
import { inject} from "vue"
export default{
setup(){
const value=inject("name")
return {value}
}
}
</script>
9.在单文件组件SFC使用组合式API语法糖(script标签直接使用setup)
<template>
<Children class="box" id="content" />
<!-- 此处下的红色下划线报错,是插件不识别vue3语法导致,不影响vue3正常运行 -->
<Children class="box" id="content" />
<h2>{
{ a }}</h2>
<h2>{
{ b}}</h2>
<button @click="changeAdd">add</button>
</template>
<script setup>
//在script标签中使用setup语法糖
//1.引入组件不需要注册
//2.定义变量不在需要return暴露,直接使用
//3.定义响应式变量,还需引入
import { ref } from "vue";
import Children from "./components/children.vue";
const a=20
console.log(a);
let b=ref(10)
function changeAdd(){
b.value++
}
</script>