VUE之组合式API

  • Post author:
  • Post category:vue



目录


组合式API


前言


组合式API的简单使用


ref和reactive


toRefs


watch与watchEffect响应式更改


在setup中使用计算属性


在setup中使用生命周期函数


setup中的参数


props


父组件向子组件传值


子组件从父组件接收值


context


获取父组件内子组件的属性


触发事件


暴露公共属性


返回页面的渲染函数


在setup中使用provide-inject


父组件向子组件发送值


子组件接收父组件值


组合式API语法糖


基本语法


基本使用

组合式API

前言


含义:

在使用vue的7大属性来组织逻辑时都很有效,但是当我们的组件开始变大的时候,逻辑关注点的列表也会不断增长,因此对于同一个业务逻辑可能造成东一块西一块,这样项目便不容易维护,组合式API的出现就是为了解决这种问题,它可以把相关业务逻辑组合在一起,最终项目易于维护


组合式API的入口:

vue的新属性setup


setup函数执行时机:

其会在组件被创建之前执行——经验证setup函数会在beforeCreated函数之前执行


注意:

在setup函数中应尽量避免使用this,因为他不会找到组件实例,

setup的调用发生在data、methods等被解析之前

,所以他们无法在setup中获取

组合式API的简单使用

<template>
  <div class="hello">
    <!-- helloworld组件内 -->
    <h1>{{msg}}</h1>
    <button @click="changeMsg()">改变msg</button>
  </div>
</template>
<script>
  export default {
    //组合式API,将同一个逻辑关注点的相关代码收集到一起
    //组合式API会在组件被创建之前执行
    setup(){
      //定义变量
      let msg="Good idea"
      //改变msg
      function changeMsg(){
        //注意:这里改变了msg并不会响应到模板页面中
        msg="Nice"
        console.log(msg);
      }
      //暴露变量,方法
      return {msg,changeMsg}
    }
  }
</script>

ref和reactive


ref:

定义基本数据类型


reactive:

定义引用数据类型


目的:

实现响应式


使用前提:

import {ref,reactive} from ‘vue’

<template>
  <div class="hello">
    <!-- helloworld组件内 -->
    <!-- 模板会自动解析value值 -->
    <h1>{{counter}}</h1>
    <h1>{{user.name}}</h1>
    <button @click="changeMsg()">改变msg</button>
    <button @click="changeUser()">改变user</button>
  </div>
</template>
<script>
  //引入ref
  import {ref,reactive} from 'vue'
  export default {
    setup(){
      //定义变量
      const msg="Good idea"
      const counter=ref(msg)
      //改变msg
      function changeMsg(){
        //实现响应式
        counter.value="Nice"
      }

      //定义user
      const user=reactive({
        name:"lili",
        age:18
      })
      //改变user
      function changeUser(){
        user.name="lala"
        user.age=28
      }
      //暴露变量,方法
      return {counter,changeMsg,user,changeUser}
    }
  }
</script>


注意:

暴露的对象尽量不要用展开运算符进行解构,因为它会使对象中的属性不是响应式的

toRefs


toRefs作用:

让结构赋值后的数据重新获得响应式


使用前提:

import {reactive,toRefs} from ‘vue’

<template>
  <div class="hello">
    <h1>{{children.name}}</h1>
    <h1>{{name}}</h1>
    <button @click="changeUser()">改变user</button>
  </div>
</template>
<script>
  //解构赋值响应式
  import {reactive,toRefs} from 'vue'
  export default {
    setup(){
      //定义user
      const user=reactive({
        name:"lili",
        age:18,
        children:{
          name:"luck"
        }
      })
      //改变user
      function changeUser(){
        user.name="lala"
      }
      //toRefs使解构后的数据重新具有响应式(加了toRefs后解构后的数据变成了对象,内部有value属性,同时也具有响应式功能)
      return {changeUser,...toRefs(user)}
    }
  }
</script>

watch与watchEffect响应式更改


使用前提:

import {ref,reactive,watch,watchEffect} from ‘vue’

<template>
  <div class="hello">
    <h1>{{counter}}</h1>
    <h1>{{user.name}}</h1>
    <button @click="changeCounter()">改变counter</button>
    <button @click="changeUser()">改变user</button>
  </div>
</template>
<script>
  //解构赋值响应式
  import {ref,reactive,watch,watchEffect} from 'vue'
  export default {
    setup(){
      const counter=ref("hello")
      function changeCounter(){
        counter.value="hi"
      }
      //监听属性
      watch(counter,(newValue,oldValue)=>{
        console.log("counter被改变了,新值为:"+newValue+"旧值为:"+oldValue);
      })

      const user=reactive({
        name:"lili",
        age:18
      })
      function changeUser(){
        user.name="lala"
      }
      //监听对象
      watchEffect(()=>{
        //user.name若发生改变的话,那么就会执行该函数
        console.log(user.name);
      })
      return {changeCounter,counter,user,changeUser}
    }
  }
</script>


注意:

watchEffect不需要指定监听的属性,其会自动收集依赖,只要在回调中引入响应式的属性,只要这些属性发生改变,那么就会执行该函数;而watch就只能够监听指定的属性

在setup中使用计算属性


使用前提:

import {ref,computed} from ‘vue’

<template>
  <div class="hello">
    <h1>{{msg}}</h1>
    <h1>{{reverseMsg}}</h1>
    <button @click="changeMsg()">改变msg</button>
  </div>
</template>
<script>
  //解构赋值响应式
  import {ref,computed} from 'vue'
  export default {
    setup(){
      const msg=ref("hello")
      function changeMsg(){
        msg.value="hi"
      }
      //计算属性的使用
      const reverseMsg=computed(()=>{
        return msg.value.split("").reverse().join("")
      })
      return {msg,changeMsg,reverseMsg}
    }
  }
</script>

在setup中使用生命周期函数


前言:

可以通过生命周期钩子函数前面加”on” 来访问组件的生命周期钩子


注意:

因为setup是围绕beforeCreate和Created函数运行的,所以不需要显示的定义他们,换句话说,在这些钩子中编写的任何代码都应该直接在setup中编写


使用前提:

import {onMounted} from “vue”(引入特定的生命周期钩子)

<template>
    <div class="hello">
      <h1>生命周期函数</h1>
    </div>
  </template>
  <script>
  //使用生命周期函数时必须引入
  import {onMounted} from "vue"
  export default {
    setup(){
      //没有调用,自动执行,还比以前有优势,以前同一个生命周期函数只能存在一个,现在可以存在多个
      onMounted(() => {
        console.log("挂载后");
      })
      onMounted(() => {
        console.log("挂载后的第二个生命周期函数");
      })
    }
  }
  </script>

setup中的参数


注意:

使用setup时他会接收两个参数(props,context)

props

父组件向子组件传值

<template>
    <div id="first">
        <!-- 父组件内 -->
        <Second :msg="message" :name="username"></Second>
    </div>
</template>
<script>
import Second from "./Second.vue";
export default {
    data(){
        return{
            message:"helloworld",
            username:"lili"
        }
    },
    components:{
        Second
    }
}
</script>

子组件从父组件接收值

<template>
    <div id="second">
        <!-- 子组件内 -->
        <h1>second</h1>
    </div>
</template>
<script>
export default {
    props: {
        msg: {
            type: String,
            default:"你好"
        },
        name:{
            type:String,
            default:"大白"
        }
    },
    //setup中获取父级传过来的值
    setup(props) {
        console.log(props);
        //获取特定的传过来的值
        console.log(props.msg);
    }
}
</script>

context


理解:

context为一个普通的js对象,暴露了其他可能在setup中有用的值

获取父组件内子组件的属性

<template>
    <div id="first">
        <!-- 父组件内 -->
        <Second class="box"></Second>
    </div>
</template>
<script>
import Second from "./Second.vue";
export default {
    components:{
        Second
    }
}
</script>
<template>
    <div id="second">
        <h1>second</h1>
    </div>
</template>
<script>
export default {
    setup(props,context) {
        //拿到父组件中定义在该组件内的属性
        console.log(context.attrs);
    }
}
</script>


插槽:

context.slot等价于slot

触发事件

<template>
    <div id="second">
        <button @click="sendParent">发送数据</button>
    </div>
</template>
<script>
import {ref} from 'vue'
export default {
    setup(props,context) {
        const count=ref(20)
        //将值传给父组件
        function sendParent(){
            context.emit("send",count.value)
        }
        return {sendParent}
    }
}
</script>
<template>
    <div id="first">
        <!-- 父组件内 -->
        <Second @send="injectCount"></Second>
    </div>
</template>
<script>
import Second from "./Second.vue";
export default {
    methods:{
        injectCount(value){
            console.log(value);
        }
    },
    components:{
        Second
    }
}
</script>

暴露公共属性

<template>
    <div id="second">
        <h1>second</h1>
    </div>
</template>
<script>
import { ref,h } from 'vue';
    export default {
        setup(props,content){
        const msg=ref("hello")
        //在返回渲染函数的情况下还想向外暴露内容从而可以被外部使用
        content.expose({
            msg
        }) 
        return ()=>h("div","helloworld")       
    }
    }
</script>
<template>
    <div id="first">
        <Second ref="second"></Second>
    </div>
</template>
<script>
import Second from "./Second.vue";
export default {
    components:{
    Second
},
mounted(){
    //父组件访问子组件内容
    console.log(this.$refs.second.msg);
}
}
</script>

返回页面的渲染函数


使用:

在父组件内使用子组件second


子组件内


使用前提:

import { h } from ‘vue’;

<template>
    <div id="second">
        <h1>second</h1>
    </div>
</template>
<script>
import { h } from 'vue';
    export default {
        setup(){
            //h为渲染函数,第一个参数为渲染根元素,第二个元素为渲染根元素里的内容
            //返回渲染元素后就会渲染该渲染函数内的元素,而不渲染当前的组件了
            return ()=>h("div","helloworld")
        }
    }
</script>

在setup中使用provide-inject

父组件向子组件发送值


使用前提:

import { provide,ref } from “vue”;


provide函数的两个参数:

(发送属性的名称,发送属性的值)

<template>
    <div id="first">
        <Second></Second>
        <button @click="changeName">更改值</button>
    </div>
</template>
<script>
import { provide,ref } from "vue";
import Second from "./Second.vue";
export default {
    setup() {
        //实现响应式
        const name=ref("张三")
        //父组件向子组件传值
        provide('name', name)
        function changeName(){
            name.value='luck'
        }
        return {name,changeName}
    },
    components: {
        Second
    }
}
</script>

子组件接收父组件值


inject函数的两个参数:

(inject的属性名称,接收属性的默认值)其返回的值就为接收的值


使用前提:

import { inject } from ‘vue’;

<template>
    <div id="second">
        <h1>{{name}}</h1>
    </div>
</template>
<script>
import { inject } from 'vue';
export default {
    setup() {
       const name=inject('name','lili')
       return {name}
    }
}
</script>

组合式API语法糖

基本语法

<script setup>
console.log("setup");
</script>


注意:

这样写的代码会被编译成组件setup函数内的内容。这意味着与普通的script只在组件被首次引用的时候执行一次不同,<script setup>中的代码会在每次组件实例被创建的时候执行

基本使用

<template>
    <div id="first">
        <h1>{{a}}</h1>
        <button @click="change">改变值</button>
        <Second></Second>
    </div>
</template>
<script setup>
import { ref } from 'vue'
import Second from "../components/Second.vue"
const a =ref(20)
function change(){
    a.value=80
}
</script>


总结:

  • 引入组件不需要注册
  • 定义的变量可以直接在模板中使用,不需要导出
  • 定义响应式的变量还是要从vue中引入相关内容


不需要导出数据的原因:

顶层的setup绑定会将数据暴露给模板



版权声明:本文为m0_60027772原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。