vue 3.x 实用特性,赶快码起来

内容

对 vue 3.x 中的一些常用特性做下记录
比对 vue 2.x 做分析

写在前面

Vue 的强大可谓不言而喻,可它仍在进行着不断的完善,作为追求者的我们,当然要紧跟其步伐,同其一起变得强大。本文就谈一谈,关于 vue 3.x 中一些实用的新特性,赶紧偷学起来(哈哈哈)。源文档地址:composition-api

emmmm 借大佬撑下牌面。。。

在这里插入图片描述

好了,开始我的表演

起步

对于新特性的使用,需要依赖官方 API ,所以此处就需要创建 vue 项目,然后安装 @vue/composition-api,安装后将其应用于 vue 项目(类似于 vue-router 的使用)即可。

1. setup

该setup功能是新的组件选项。它充当在组件内部使用Composition API的入口点。

1.1 调用时间

setup创建组件实例时,在初始组件后立即调用。在生命周期方面,它在 beforeCreate 之后 created 之前调用

1.2 基本使用
<template>
  <div>
    我是 setup 函数
    <div>{
    
    {
    
    name}}</div>
  </div>
</template>

<script>
import {
    
    reactive} from '@vue/composition-api'

export default {
    
    
    props:{
    
    
        name:String  //用于验证props 类型
    },
    // setup函数传入两个参数
    setup(props,context){
    
        //setup() 函数调用的时机为 beforeCreate() 之前,created() 之后
        console.log('setup');
        console.log(props); //打印 props 的值
        console.log(context); // 打印 context(object)
        console.log(context.root)   //setup 使用this 的方式,必须在参数中传入context 来打点调用
    },
}
</script>

注意:此处是将组件作为 App.vue 的子组件进行渲染,props 来自于 App.vue (下同),渲染结果略

2. reactive,ref

vue 2.x 组件的数据都有data() 函数包裹; 此处两个 api 都用于动态创建响应式数据。reactive 一次可创建 n 多个数据({name:‘’,age:’’…});ref 一次只能创建一个数据对象。实操时经常会 reactive 和 ref 配合使用

2.1 reactive
<template>
  <div>
    <div>{
    
    {
    
    msg}}</div>
    <div>couut值为{
    
    {
    
    count}}</div>
    <button @click="count++">+1</button>
  </div>
</template>

<script>
import {
    
    reactive} from '@vue/composition-api'
export default {
    
    
    setup(){
    
        //setup() 函数调用的时机为 beforeCreate() 之前,created() 之后
        const myData = reactive({
    
    msg:'奥利给',count:1})  //rective() 必须写在 setup() 中,创建私有数据(响应式)
        console.log(myData.msg)  //内部调用
        return myData
    },
}
2.2 ref
<template>
  <div>
      我是ref函数
      <p>{
    
    {
    
    refCount}}</p>
  </div>
</template>

<script>
import {
    
    ref} from '@vue/composition-api'
export default {
    
    
    setup(){
    
    
        const refCount = ref(1); // ref() 返回值为一个对象,且只包含 value 一个属性
        console.log(refCount.value); // 在 setup 中用 .value 调用,在模板中不写 .value
        return {
    
        //此处return 后加{} 返回对象
            refCount, 
        }
    }
}
</script>
2.3 reactive 返回 ref 对象
    setup(){
    
    
        const count = ref(1);
        const state = reactive({
    
    
            count   //此数会自动把响应式数据展开为原始的值,不需要打掉调用
        })
        return state
    }
2.4 新的 ref 会覆盖 旧的 ref

3. isRef,toRefs

3.1 isRef 用于判断对象是否是由 ref方法创建出来的对象。应用场景:当需要展开某个可能是 ref() 创建的对象的时候
const data = isRef(foo) ? foo.value : 'foo'
3.2 toRefs 可以将 reactive 创建的响应式对象转换成普通对象,此时这个对象上的每个属性都是 ref() 类型的响应式数据
<template>
  <div>
      我是toRefs函数
      <p>{
   
   {age}}</p>
      <button @click="add">+1</button>
  </div>
</template>

<script>
import {
     
     reactive,toRefs} from '@vue/composition-api'
export default {
     
     
    setup(){
     
     
        const data = reactive({
     
     
            name:'zs',
            age:18
        })
        // 定义逻辑的函数(vue 2 写在 methods 中,vue 3 全部写在 setup() 中)
        const add = ()=>{
     
     
            data.age++
        }
        return{
     
     
               // ...data, 直接把 reactive 创建的响应式数据展开后数据就不具备响应式;
            ...toRefs(data), //需要用toRefs 进行包裹,让其每个节点都成为ref 创建的响应式节点
            add // 把方法返回出去(逻辑较多时,把函数写在 setup 中)
        }
    }
}
</script>

4. computed

4.1 创建只读的计算属性
const count = ref(1)
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // error (只读无法进行更改)
4.2 创建可读写的计算属性
 const one = ref(1);
 
 const two = computed({
    
    
      get:()=> one.value + 1,
      set:val=> one.value = val
 })
 
 console.log(one.value) //1
 console.log(two.value) //2
 two.value = 8
 console.log(two.value) //9

5. watch

5.1 监视单个数据源
  setup() {
    
    
    // 监听ref 创建的数据
    const refCount = ref(1);
    // 监听 state 数据变化,数据改变执行函数
    watch(refCount, (newRef, oldRef) =>
      console.log(newRef, oldRef) //切记此处无需 .value
    );
    // 定义定时器来改变数据
    setTimeout(() => {
    
    
      refCount.value++;
    }, 1000);


    // 监听 reactive 创建的数据
    const retcount = reactive({
    
    
      count: 0,
    });
    watch(
      () => retcount.count,
      (newCount, oldCount) => console.log(newCount, oldCount)
    );
    setTimeout(() => {
    
    
      retcount.count++;
    }, 1000);
  },

注意:监视单个 reactive 数据源时 watch 的第一个参数为函数,第二个参数也为函数;监视单个 ref 数据源时 watch 的第一个参数为 ref 数据,第二个参数为函数

5.2 监视多个数据源(注释含解释)
setup() {
    
    
    const retCount = reactive({
    
    
        age:18,
        length:20
    })
    // 监听多个 reactive 数据时,第一个参数为数组(中包含函数),第二个参数为函数(函数参数为数组)
    watch([()=>retCount.age,()=>retCount.length],([newAge,newLenght],[oldAge,oldLength])=>{
    
    
        console.log(newAge,oldAge)
        console.log(newLenght,oldLength)
    })

    setTimeout(()=>{
    
    
        retCount.age++,
        retCount.length++
    },1000)


     const refAge = ref(18);
     const refLength = ref(21);
    // 监听多个 ref 数据时,第一个参数为数组(中包含 ref 数据),第二个参数为函数(函数参数为数组)
    watch([refAge,refLength],([newAge,newLenght],[oldAge,oldLength])=>{
    
    
        console.log(newAge,oldAge)
        console.log(newLenght,oldLength)
    })
    setTimeout(()=>{
    
    
        refAge.value++,
        refLength.value++
    },1000)
  },

注意:watch 也可有第三个参数,参数的类型为 object ,写一些相关配置

5.3 清除监视

setup() 函数内创建的 watch 监视,会在当前组件被销毁时自动停止,如果想要明确地停止某个监视,可调用 watch 函数的返回值即可。

const stop = watch(refCount,(oldCount,newCound)=>{
    
    
      console.log(oldCount,newCound)
});
const stopWatch = ()=>{
    
    //调用watch 返回值即可清除侦听(把方法返回供使用)
      stop()
}
5.4 在 watch 中清除无效的异步任务

有时,当被 watch 监视的数据发生变化时,或 watch 本身被 stop后,我们期望能够清除无效的异步任务,此时,watch回调函数中提供了一个 cleaup registrator function 来执行清除工作。

这些函数会在以下情况下被调用:1. watch 被重复执行、2. watch 被强制stop了。

示例:(watch 被重复执行,只执行最后一次 watch(性能优化))

<template>
  <div>
      <input type="text" v-model="refCount">
      <!-- 执行效果为,当停止输入1s 后,控制台打印输入内容 -->
  </div>
</template>

<script>
import {
     
     ref,watch} from '@vue/composition-api'
export default {
     
     
    setup(){
     
     
        const refCount = ref('');   //用ref 创建响应式数据
        const asyncWatch = val =>{
     
       //定义返回异步任务的函数
           return setTimeout(()=>{
     
       //return 出 timeId
                console.log(val)
            },1000)
        }
        watch(refCount,(refCount,newCount,onclear)=>{
     
      //watch对无效的异步任务进行清除
            const timeId = asyncWatch(refCount);  //监视 refCount 变化
            onclear(()=>clearTimeout(timeId))	// 当 1s 内 refCount 发生变化,就清除上次定时器(结果)
        })
        return{
     
     
            refCount,
            asyncWatch
        }
    }
}
</script>

6. 钩子函数

vue 3.x 的生命周期函数,可以按需到入到组件中,且只能在 setup() 函数中使用

import {
    
     onMounted, onUpdated, onUnmounted } from 'vue'

const MyComponent = {
    
    
  setup() {
    
    
    onMounted(() => {
    
    
      console.log('mounted!')
    })
    onUpdated(() => {
    
    
      console.log('updated!')
    })
    onUnmounted(() => {
    
    
      console.log('unmounted!')
    })
  }
}

钩子函数:vue 2.x 与 vue 3.x 的映射关系

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • activated -> onActivated
  • deactivated -> onDeactivated
  • errorCaptured -> onErrorCaptured

7. provide & inject

provide()inject() 可以实现嵌套组件之间的数据传递,这两个传递函数只能在 setup() 函数中使用。父组件使用 provide() 函数向下传递数据,子(后代) 组件使用 inject() 获取上层传递过来的数据。

7.1 共享普通数据

父组件:

<template>
  <div>
      我是父组件
    <com-son></com-son>
  </div>
</template>

<script>
import {
     
     provide} from '@vue/composition-api'
import ComSon from './ComSon.vue'
export default {
     
     
    components:{
     
     
        'com-son':ComSon
    },
    setup(){
     
     
        provide('color','red') // 父组件通过provide 传递数据
    }
}
</script>

子组件:

<template>
  <div>
      <p :style="{
       
       color:color}">我是子组件</p>
  </div>
</template>

<script>
import {
     
     inject} from '@vue/composition-api'
export default {
     
     
    setup(){
     
     
        const color = inject('color')  //子组件通过 inject 接收数据
        return {
     
     
            color
        }
    }
}

</script>

执行结果为:子组件的字体变为了红色

注意:父组件若要向下传递多条数据,使用 provide 需要一条条创建;对于数据多的情况,完全可以使用:组件间传值方式,或者 vuex (Vuex解读

7.2 共享响应式数据

父组件:

<template>
  <div>
      <p>我是父组件</p>
    <button @click="refcolor = 'green'">绿色</button>
    <button @click="refcolor = 'orange'">橙色</button>
    <button @click="refcolor = 'pink'">粉色</button>
    <com-son></com-son>
  </div>
</template>

<script>
import {
     
     provide,ref} from '@vue/composition-api'
import ComSon from './ComSon.vue'
export default {
     
     
    components:{
     
     
        'com-son':ComSon
    },
    setup(){
     
     
        const refcolor = ref('red')
        provide('color',refcolor)
        return{
     
     
            refcolor
        }
    }
}
</script>

子组件(同上一个子组件)

执行结果:

在这里插入图片描述

8. template refs

通过 ref() 可以获取页面上元素或组件

8.1 元素的引用

示例:

<template>
  <div>
      <p ref="refp">我是p标签</p>
  </div>
</template>

<script>
import {
     
     ref,onMounted} from '@vue/composition-api'
export default {
     
     
    setup(){
     
     
        const refp = ref(null);  // 创建一个 DOM 引用(名字必须与标签内 ref 值一致)

        // 在DOM 首次加载完毕,才能获取元素的引用
        onMounted(()=>{
     
     
            // 为DOM 元素设置字体颜色 (refp.value 是原生的DOM 对象)
            refp.value.style.color = 'red'
            console.log(refp)
        })

        return{
     
     
            refp
        }
    }
}

</script>

执行结果:

在这里插入图片描述
注意:其跟vue 2.x 的 vm.$refs 相比较,似乎更加灵活,传送:refs

vm.$refs 演示

示例:

<template>
  <div>
    <p ref="refTest">我是用来测试的</p>
  </div>
</template>

<script>
export default {
     
     
  data() {
     
     
    return {
     
     };
  },
  mounted() {
     
     
    console.log(this.$refs.refTest);
  },
};
</script>

结果:

在这里插入图片描述

8.2 组件的引用

示例:

父组件:

<template>
  <div>
      <p>我是父组件</p>
    <com-son ref="refSon"></com-son>
  </div>
</template>

<script>
import {
     
     ref,onMounted} from '@vue/composition-api'
import ComSon from './ComSon.vue'
export default {
     
     
    components:{
     
     
        'com-son':ComSon
    },
    setup(){
     
     
        const refSon = ref(null);
        onMounted(()=>{
     
     
            console.log(refSon)
        })
        return{
     
     
            refSon
        }
    }
}

</script>

子组件:

<template>
  <div>
      <p>我是子组件</p>
  </div>
</template>

<script>
import {
     
      ref} from '@vue/composition-api'
export default {
     
     
    setup(){
     
     
        const str = ref('我是子组件的内容')
        return {
     
     
            str
        }
    }
}
</script>

执行结果:

在这里插入图片描述
注意:此处获取了子组件的所有属性及方法,亦可灵活的操控子组件

写在最后

Vue 的进步也预示着各方面技术正朝着更全面的方向发展,未来的技术人可谓任重道远,所以我们更应该不断紧跟技术潮流。让自己成为 “弄潮人”。come on !!! 最后附上要学习的: composition-api。哈哈哈哈

结束

猜你喜欢

转载自blog.csdn.net/cwq521o/article/details/108468921