Vue3之setup()、reactive、ref

概述

在Vue3中,将Vue2.0的option API 制作成hook函数,比如watch,compute方法等,在Vue3中新增的setup()方法中,可以以函数的形式去使用Vue2.0的watch,compute等属性,setup函数的调用时机是创建组件实例,然后初始化props,紧接着是调用setup函数,从生命周期的角度来看,它会在beforeCreate之前调用,所以在setup函数内是拿不到上下文对象的,它创建的是datamethod.

reactive、ref是两个响应式引用,用它们修饰的变量或者是对象会具有响应式的效果,ref主要用于处理基础类型的数据,如字符串,数字等,而reactive处理非基础类型的数据,比如自定义的对象就可以用reactive修饰,使其具有响应式的效果

实例解析

在Vue3中,setup函数主要负责完成组件内部的状态管理,响应式数据的设置,引入第三方库,组合函数等操作,setup函数接收两个参数,分别是propscontext, 其中props是组件的属性对象,context是一个包含了一些实用的对象和方法的上下文对象。setup需要返回一个对象,这个对象包含了组件中需要使用的所有数据和方法等。

响应式API ref()和reactive()

我们可以看一个简单的例子,使用setup函数和ref定义一个变量展示一个name,2秒后自动改变name的内容。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>setUp、ref、reactive的使用</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>

 const app = Vue.createApp({
      
      
   template:`<div>{
       
       {name}}<div>`,
   setup(props,context){
      
      
            const {
      
      ref} = Vue;
            const name = ref('zhongxj');
            setTimeout(()=>{
      
      
               name.value = 'walt';
            },2000);

            return {
      
      name}
        }
 });
        
 const vm = app.mount('#root');
</script>

在上面的代码中我们需要注意的是,使用ref之前需要使用

const {ref} = Vue;

来导入Vue对象的ref函数,然后使用时用ref包含起来的值就会自动带有响应式的效果,如上面的例子中,先是定义了name的值为‘zhongxj’,过来2秒,将值修改成‘walt’时,页面中的展示的值也会自动跟着改变。


说完setup和ref函数的使用,我们在本文的开始还提到了reactive函数,这个函数的作用和ref的作用是一样的,都是为了给修饰的值赋予响应式的效果,只是reactive主要修饰的是非基础类型的数据,如下面代码所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>setUp、ref、reactive的使用</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>

 const app = Vue.createApp({
      
      
   template:`<div>{
       
       {nameObj.name}}<div>`,
   setup(props,context){
      
      
            const {
      
      reactive} = Vue;
            const nameObj = reactive({
      
      name:'zhongxj'});
            setTimeout(()=>{
      
      
               nameObj.name = 'walt';
            },2000);

            return {
      
      nameObj}
        }
 });
        
 const vm = app.mount('#root');
</script>

从上面的代码中可以知道,可以使用reactive去修饰一个对象,从而让这个对象具有响应式的能力。ref和reactive这两个响应式API的原理是通过代理的方式实现的,通过proxy对数据进行封装,当数据变化时,触发模版等内容的更新 。比如:

 // 基础数据类型
 let name = ref('zhong');
 //会将 'zhong' 变成proxy({value:'zhong'}) 这样的响应式引用
 //非基础数据类型
const nameObj = reactive({
    
    name:'xcy'});
// 会将{name:'xcy'} 变成proxy({name:"xcy"})的一个响应式引用

toRef()、toRefs()使数据具有响应式能力

我们普通的对象是不具有响应式能力的,如果要想让它具备响应式能力,我们必须转化一下,Vue提供了toRef()和toRefs() API可以将普通对象转换成具有响应式能力的对象。
首先要介绍的式toRef()的使用,先看一段代码。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>toRef使用</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
 const app = Vue.createApp({
      
      
        template: 
        `
        <div> {
       
       {age}}</div>
        ` ,
        setup(props,context){
      
      
            const {
      
      reactive,toRef} = Vue;
            const data = reactive({
      
      name:'walt',age:'18'});
            const age = toRef(data,'age');
            setTimeout(()=>{
      
      
                age.value='22'
            },2000);
            return{
      
      age};
        }
    });  
    const vm = app.mount('#root');
</script>

上面的代码展示了toRef方法的使用,我们首先定义了一个data的响应式数据,但是我们只想返回age给到界面展示,这时候我们新定义了一个age变量,如果不用toRef()函数转换一下,我们的age是不具备响应式能力的。加了toRef后,age就带有响应式能力了。这里还有一个细节,假设我们的age是原来对象中没有的属性,也可以转。如下所示:

   setup(props,context){
    
    
            const {
    
    reactive,toRef} = Vue;
            const data = reactive({
    
    name:'walt'});// 没有age属性
            const age = toRef(data,'age');// 将age转成响应式的变量
            setTimeout(()=>{
    
    
                age.value='22'
            },2000);
            return{
    
    age};
        }

上面的代码也是没有问题的。但是我们发现此时我们转换的都是单一的属性,假设我们需要将整个对象转成响应式的就需要使用toRefs()函数,具体的使用方法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>toRefs的使用</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>

 const app = Vue.createApp({
      
      
   template:
         `
          <div>{
       
       {name}}</div>
          <div>{
       
       {age}}</div>
         `,
      setup(props,context){
      
      
            const {
      
      reactive ,toRefs} = Vue;
            const nameObj = reactive({
      
      name:'walt',age:29,sex:'male'});
           
            setTimeout(()=>{
      
      
                nameObj.name = 'zhongxj';
                nameObj.age = 28;
            },2000);

            const {
      
      name,age} = toRefs(nameObj);
            return {
      
      name,age}
        }
 });
        
 const vm = app.mount('#root');
</script>

如上面代码所示,我们定义了一个nameObj对象,然后使用toRefs()方法将其转变成立响应式的对象,当我们在2秒后改变了对象内的name,age属性时,界面上的name和age属性也会随之跟着改变。

最后简单介绍下setUp()函数中的context参数,如下面代码所示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>toRef和context参数使用</title>
    <script src="https://unpkg.com/vue@next"></script>
</head>
<body>
    <div id="root"></div>
</body>
<script>
 const app = Vue.createApp({
      
      
        // template: 
        // `
        // <child app='zhongxj' />
        // ` ,
        // template: 
        // `
        // <child>
        //     parent
        // </child>
        // ` ,
        template:`<child @change="handleClick"></child>`,
        methods:{
      
      
            handleClick(){
      
      
                alert('change')
            }
        },
        setup(props,context){
      
      
            const {
      
      reactive,toRef} = Vue;
            const data = reactive({
      
      name:'walt'});
            return{
      
      data};
        }
    });
    
    app.component('child',{
      
      
        // template: 
        // `
        // <div>child</div>
        // ` ,

        template:`<div @click="handleClick">hello world </div>`,
        setup(props,context){
      
      
            const{
      
      attrs,slots,emit} = context;
            const {
      
      h} = Vue;
            // 父组件传递过来的None-Props属性,子组件不用props['app']
            //的方式接收的话就叫做Nons-props属性
           // console.log(attrs.app); 
           // console.log(slots.default());
           // 可以使用render的h函数渲染父组件传递过来的插槽内容
          // return () => h('div',{},slots.default()); 

          function handleClick(){
      
      emit('change')}
          return{
      
      
            handleClick
          }
        } 
    });
    const vm = app.mount('#root');
</script>

上面的代码中最主要的就是const{attrs,slots,emit} = context; 这段代码,即从context中可以拿到父组件传递过来的None-props属性、插槽、emit。然后可以实现很多灵活的需求,比如本例中的事件通信,具体的读者可以打开代码中的注释体验。

注:子组件不用props['app']的方式接收的话就叫做Nons-props属性

总结

本文主要介绍了Vue3的setUp函数和响应式的API toRef(),toRefs(),以及其使用的方法,本文的介绍其实只是入门的知识,只是为了抛砖引玉,读者在简单入门后若要深刻了解请移步官网或者其他大牛的博客。

猜你喜欢

转载自blog.csdn.net/zxj2589/article/details/130571850