• Vue3.3指北(三)


    Vue3.3指北

    • 1、Vue2和Vue3
    • 2、组合式API - setup
      • 2.1、setup选项
      • 2.2、setup中写代码的特点
      • 2.3、`
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 执行时机

        在beforeCreate钩子之前执行

        在这里插入图片描述

        2.2、setup中写代码的特点

        • setup函数中写的数据和方法需要在末尾以对象的方式return,才能给模版template使用
        
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15

        2.3、
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6

        示例:我们在模板里面应用 setup() 函数里面的东西

        <script>
            // 1.创建Vue的实例对象
            const app = Vue.createApp({
        
                setup(props,context) {
                    const message = 'this is message';
                    const logMessage = ()=>{
                        console.log(message);
                    };
                    return {
                        message,
                        logMessage
                    }
                },
        
                // 我们在模板里面应用 setup() 函数里面的东西
                template: `
                

        {{message}}

        `
        }); app.mount('#app'); </script>
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23

        2.4、props和context

        • setup 里接收的参数是 propscontext
        // 声明时props和setup同级,可以通过以下方式对父组件传递的参数在props中声明
        props:{
            msg:String,
            name:String
        },
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • context 上下文包括 attrsemitslots
          • attrs :接收在父组件传递过来的,并且没有在props中声明的参数
          • emit :子组件对父组件发送事件
          • slots :插槽

        在vue2中,子对父发送事件采用this.$emit父组件发送事件,在vue3中子组件对父组件发送事件采用context.emit发送事件

        import { ref } from 'vue';
         
        export default {
          props: {
            message: String
          },
          setup(props, context) {
            const count = ref(0);
         
            // 使用props
            console.log(props.message);
         
            // 使用context
            console.log(context.attrs);
            console.log(context.slots);
            console.log(context.emit);
         
            return {
              count
            };
          }
        };
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22

        在上面的示例中,我们使用了propscontext参数来获取组件的属性、插槽和触发事件的方法。

        需要注意的是,setup()函数在组件初始化期间只会执行一次,并且在datacomputed等选项之前执行。

        3、组合式API - reactive和ref函数

        3.1、reactive

        • 接受对象类型数据的参数传入并返回一个响应式的对象
        <script setup>
         // 导入
         import { reactive } from 'vue'
         // 接收对象类型
         const state = reactive({
           msg:'this is msg'
         })
         const setSate = ()=>{
           // 修改数据更新视图
           state.msg = 'this is new msg'
         }
        script>
        
        <template>
          {{ state.msg }}
          <button @click="setState">change msgbutton>
        template>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17

        3.2、ref

        • 接收简单类型或者对象类型的数据传入并返回一个响应式的对象
          • 让基础类型的数据具备响应式(有点像v-model双向绑定数据的感觉)
        <script setup>
         // 导入
         import { ref } from 'vue'
         // 执行函数 传入参数 变量接收
         const count = ref(0)
         const setCount = ()=>{
           // 修改数据更新视图必须加上.value
           count.value++
         }
        script>
        
        <template>
          <button @click="setCount">点击增加button>
        template>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14

        Tips:

        • 需要注意的是使用ref参数类型修改数据必须加上 .value

        3.3、reactive 对比 ref

        相同点:

        • 都是用来生成响应式数据

        不同点

        1. reactive不能处理简单类型的数据
        2. ref参数类型支持更好,但是必须通过.value做访问修改
        3. ref函数内部的实现依赖于reactive函数

        在实际工作中的推荐

        • 推荐使用ref函数,减少记忆负担

        4、组合式API - computed

        计算属性基本思想和Vue2保持一致,组合式API下的计算属性只是修改了API写法

        • computed()方法返回值是个计算属性ref对象,在模板中使用也是会自动解包的
        • 它的参数是一个回调函数,也就是箭头函数
        <script setup>
        // 导入
        import {ref, computed } from 'vue'
        // 原始数据
        const count = ref(0)
        // 计算属性
        const doubleCount = computed(()=>count.value * 2)
        
        // 原始数据
        const list = ref([1,2,3,4,5,6,7,8])
        // 计算属性list
        const filterList = computed(item=>item > 2)
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13

        5、组合式API - watch

        • 侦听一个或者多个数据的变化,数据变化时执行回调函数
        • 三个参数
          • 第一个参数是:选择要监听的属性选择要监听的属性
          • 第二个参数是:设置的回调函数。即监听到变化时应该执行的函数
          • 第三个参数是配置项
            • immediate 控制立刻执行
            • deep开启深度侦听

        5.1、侦听单个数据

        <script setup>
          // 1. 导入watch
          import { ref, watch } from 'vue'
          const count = ref(0)
          // 2. 调用watch 侦听变化
          watch(count, (newValue, oldValue)=>{
            console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
          })
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9

        5.2、侦听多个数据

        • 侦听多个数据,第一个参数可以改写成数组的写法
        <script setup>
          // 1. 导入watch
          import { ref, watch } from 'vue'
          const count = ref(0)
          const name = ref('cp')
          // 2. 调用watch 侦听变化
          watch([count, name], ([newCount, newName],[oldCount,oldName])=>{
            console.log(`count或者name变化了,[newCount, newName],[oldCount,oldName])
          })
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10

        5.3、immediate

        在侦听器创建时立即出发回调,响应式数据变化之后继续执行回调

        <script setup>
          // 1. 导入watch
          import { ref, watch } from 'vue'
          const count = ref(0)
          // 2. 调用watch 侦听变化
          watch(count, (newValue, oldValue)=>{
            console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
          },{
            immediate: true
          })
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11

        5.4、deep

        • 通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep
        <script setup>
          // 1. 导入watch
          import { ref, watch } from 'vue'
          const state = ref({ count: 0 })
          // 2. 监听对象state
          watch(state, ()=>{
            console.log('数据变化了')
          })
          const changeStateByCount = ()=>{
            // 直接修改不会引发回调执行
            state.value.count++
          }
        script>
        
        <script setup>
          // 1. 导入watch
          import { ref, watch } from 'vue'
          const state = ref({ count: 0 })
          // 2. 监听对象state 并开启deep
          watch(state, ()=>{
            console.log('数据变化了')
          },{deep:true})
          const changeStateByCount = ()=>{
            // 此时修改可以触发回调
            state.value.count++
          }
        script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27

        6、组合式API - watchEffect

        watchEffect 也是一个帧听器,是一个副作用函数。 它会监听引用数据类型的所有属性,不需要具体到某个属性,一旦运行就会立即监听,组件卸载的时候会停止监听。

        6.1、基本使用

        <template>
          <div>
            <h2>{{ counter }}</h2>
            <button @click="addCounter">+1</button>
          </div>
        </template>
        
        <script >
        import { ref, watchEffect } from 'vue';
        
        export default{
          setup() {
            const counter = ref(100)
        
            const addCounter = () => counter.value++
        
            watchEffect(() => {
              console.log("counter:", counter.value);
            })
        
            return {
              counter,
              addCounter
            }
          }
        }
        
        </script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28

        watchEffect会默认执行一次,当有变量发生变化,就会执行侦听

        6.2、watchEffect的其他参数

        watchEffect会返回一个返回值,该返回值是一个函数,在满足条件的时候触发返回值函数。我们可以利用这个返回值做一些操作

        6.2.1、stop停止侦听

        这里我们想要实现计数器增加到15的时候停止侦听:

        <template>
          <div>
            <h2>{{ counter }}</h2>
            <button @click="addCounter"> +1 </button>
          </div>
        </template>
        
        <script >
        import { ref, watchEffect } from 'vue';
        
        export default{
          setup() {
            const counter = ref(10);
        
            const addCounter = () => {
              counter.value++;
              if(counter.value >= 15){
                  stop();
              }
            };
        
            const stop = watchEffect(() => {
              console.log("counter:", counter.value);
            });
        
            return {
              counter,
              addCounter
            };
          }
        }
        
        </script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33

        在这里插入图片描述

        stop()接收watchEffect的返回值,在手动触发计数器到15之后不再侦听变量的改变。

        6.2.2、onInvalidate消除副作用

        我们做一个假设,假设我们需要根据counter的值去触发对应的网络请求,但是在请求数据的过程中,我们再次触发方法改变了counter的值,我们该如何做才能让每次请求回来的都是正确的数据呢?

        我们也可以这么想,也就是我们只要改变了counter的值,就需要清除上一次的请求,重新执行一次请求。

        watchEffect中有一个参数onInvalidate 可以作为消除副作用,它会返回一个函数

        <template>
          <div>
            <h2>{{ counter }}</h2>
            <button @click="addCounter">+1</button>
          </div>
        </template>
        
        <script >
        import { ref, watchEffect } from 'vue';
        
        export default{
          setup() {
            const counter = ref(10)
        
            const addCounter = () => {
              counter.value++
            }
        
            watchEffect( onInvalidate => {
              onInvalidate(() => {
                console.log("onInvalidate");
              })
              console.log("counter:", counter.value);
            })
        
            return {
              counter,
              addCounter
            }
          }
        }
        
        </script>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33

        在这里插入图片描述

        7、组合式API - 父子通信

        7.1、父传子

        如果是setup函数的形式,props 必须以 props 选项的方式声明,props 对象会作为 setup() 函数的第一个参数被传入

        • 在vue3中,只要props这个参数存在,我们就可以直接mustache中使用父组件传递的参数

        基本思想

        1. 父组件中给子组件绑定属性
        2. 子组件内部通过props选项接收数据

        父组件App.vue

        <script setup>
        // 引入子组件
        import sonComVue from './son-com.vue';
        script>
        
        <template>
          
          <sonComVue message="this is app message" />
        template>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9

        子组件son-com.vue

        <script setup>
          // 2.通过 defineProps 接收子组件传递的数据
          const props = defineProps({
            message: String
          })
        
        script>
        
        <template>
            
          {{message}}
        template>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12

        在使用