Vue3中的组合式API的使用

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>

猜你喜欢

转载自blog.csdn.net/qq_72760247/article/details/128650570
今日推荐