Vue组合式API

2022-08-24  本文已影响0人  wqjcarnation

Composition API简介

Composition API:组合式 API;一组低侵入式的、函数式的 API,使得我们能够更灵活地【组合】组件的逻辑。

这是有别于 Options API 的一种函数式 API。无需通过很多选项来完成业务逻辑,Composition API提供了一个setup函数,我们可以将data数据、计算属性、方法等等,都放在setup函数中,这样就可以对业务进行集中处理了。

1.1setup()入口

setup 函数是一个新的组件选项,它是在组件内使用 Composition API 的入口点。它会在Vue实例创建完成前被调用。所以,setup函数中没有this指针

  <template>
  <div></div>
</template>

  <script>
  export default {
    setup() {
      //这里书写本地状态(data数据)、计算属性或方法等
      console.log('setup函数');
    }
  }
  </script>

如果 setup 返回一个对象,则对象的属性将会被合并到组件模板的渲染上下文,我们就可以在模板里使用对应的属性和方法。所以,我们可以将本地状态(data数据)、方法、计算属性等写在 setup 函数中。

    <template>
        <div id="app">
            {{num}}
        </div>
    </template>

    <script>
        export default{
            setup(){
                let num=0;
                return {num};
            }
        }
    </script>

1.2ref 响应式监听(了解,后续有更好的方案)

接下来,试着在其中加入函数

    <template>
        <div id="app">
            {{num}}
            <button @click="add">+</button>
        </div>
    </template>

    <script>
        export default{
            setup(){
                let num=0;
                function add(){
                    num++;
                }
                return {num,add};
            }
        }
    </script>

运行后发现数字没有变化 ,原因很简单,num只是声明的一个普通数据,不具备响应功能。

在 Vue 3.0 中,我们可以通过一个 ref 函数来实现响应式数据监听。ref 接受一个参数,并将其包裹在一个带有 value 属性的对象中返回,然后可以使用该 value 属性访问或更改响应式变量的值:

    <template>
        <div id="app">
            {{num}}
            <button @click="add">+</button>
        </div>
    </template>

    <script>
        //1、注意:要导入ref
        import {ref} from 'vue';
        export default{
            setup(){
                let num=ref(0);//2、ref
                function add(){
                    num.value++;//3、 .value
                }
                return {num,add};
            }
        }
    </script>

为什么要将值封装在一个对象中,看似没有必要,但为了保持 JavaScript 中不同数据类型的行为统一,这是必须的。因为在 JavaScript 中,Number 或 String 等基本类型是通过值传递的,而不是通过引用传递的

1.3reactive与toRefs

上面实例中,操作数据时需要使用 value 属性,比较麻烦。
可以使用 reactive 与 toRefs 解决这个问题。首先使用 reactive 创建响应式对象,封装数据。

    <template>
        <div id="app">
            <!--data.num -->
            {{data.num}}
            <button @click="add">+</button>
        </div>
    </template>

    <script>
        //1、注意:要导入reactive
        import {reactive} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0
                })
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                }
                return {data,add};
            }
        }
    </script>

更复杂一点的示例

    <template>
        <div id="app">
            <!--data.num -->
            {{data.num}}<button @click="add">+</button><br>
            {{data.userObj.userName}}
            <ul v-for="(item,index) in data.userList" :key="item.id">
                <li>{{item.userId}}-{{item.userName}}</li>
            </ul>
        </div>
    </template>

    <script>
        //1、注意:要导入reactive
        import {reactive} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0,
                    userObj:{
                        userName:'wang.qj'
                    },
                    userList:[{userId:1,userName:'张三'}]
                })
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                    
                }
                return {data,add};
            }
        }
    </script>

但是因为只有data是响应式数据,而data中的那些数据还不是响应式的。所以在视图访问数据时都需要使用 data作为前缀才可以。这就比较麻烦了。
此时我们可以使用 toRefs 进行优化。toRefs可以将state中的每一个数据进行展开,且都包装成响应数据。这样视图层就可以直接使用了。

终极的写法

    <template>
        <div id="app">
            <!--data.num -->
            {{num}}<button @click="add">+</button><br>
            {{userObj.userName}}
            <ul v-for="(item,index) in userList" :key="item.id">
                <li>{{item.userId}}-{{item.userName}}</li>
            </ul>
        </div>
    </template>

    <script>
        //1、注意:要导入reactive
        import {reactive,toRefs} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0,
                    userObj:{
                        userName:'wang.qj'
                    },
                    userList:[{userId:1,userName:'张三'}]
                })
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                    
                }
                return {
                ...toRefs(data),
                add};
            }
        }
    </script>

● 在返回时使用 ...toRefs(data) ,这样视图层就可以不使用 data前缀了。
● 为什么要使用 ... 参数扩展运输符呢?因为toRefs(data) 将data对象展开,并包装成多个响应数据。

TIP:
ref 和 reactive 都可以做响应式数据,它们的区别如下:
● reactive:用于定义引用类型。只能修改数据,不能改变其引用。
● ref:用于定义基本类型和引用类型。可以修改数据,也可以改变其引用。
○ 在方法中修改数据时需要使用 value属性。因为,Ref的本质是通过Reactive创建的,Ref(10) 就相当于:Reactive({value:10});
○ 在视图模板调用可以省略value属性的书写。

1.4computed

    <template>
        <div id="app">
            <!--data.num -->
        ...
            {{comNum}}<br>
    .
        </div>
    </template>

    <script>
        //1、注意:要导入reactive,toRefs,computed
        import {reactive,toRefs,computed} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0,
                    userObj:{
                        userName:'wang.qj'
                    },
                    userList:[{userId:1,userName:'张三'}],
                                            //计算属性
                    comNum:computed(()=>{
                        return data.num+"$"
                    })
                })
                
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                    
                }
                return {
                ...toRefs(data),
                add};
            }
        }
    </script>

<style>
</style>

注意:计算属性写在reactive里
watch不需要写在reactive里

1.5监听器

● 使用watch函数来进行数据监听。watch函数有两个参数。
● 第一个参数:要监听的数据。
● 第二个参数:触发监听时的处理函数(包括newValue, oldValue)

    <template>
        <div id="app">
            <!--data.num -->
            {{num}}<button @click="add">+</button><br>
            {{comNum}}<br>
            {{userObj.userName}}
            <ul v-for="(item,index) in userList" :key="item.id">
                <li>{{item.userId}}-{{item.userName}}</li>
            </ul>
        </div>
    </template>

    <script>
        //1、注意:要导入reactive
        import {reactive,toRefs,computed,watch} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0,
                    userObj:{
                        userName:'wang.qj'
                    },
                    userList:[{userId:1,userName:'张三'}],
                    comNum:computed(()=>{
                        return data.num+"$"
                    })
                })
                watch(data,(newvalue,oldvlaue)=>{
                    console.log(newvalue)
                    console.log(oldvlaue)
                })
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                    
                }
                return {
                ...toRefs(data),
                add};
            }
        }
    </script>

<style>
</style>

上面实例中直接监听state响应对象。但我们知道,在state中会有很多数据,如果只想监听其中的某个数据,就需要换一种写法:

    <template>
        <div id="app">
            <!--data.num -->
            {{num}}<button @click="add">+</button><br>
            {{comNum}}<br>
            {{userObj.userName}}
            <ul v-for="(item,index) in userList" :key="item.id">
                <li>{{item.userId}}-{{item.userName}}</li>
            </ul>
        </div>
    </template>

    <script>
        //1、注意:要导入reactive
        import {reactive,toRefs,computed,watch} from 'vue';
        export default{
            setup(){
                //2 reactive({})定义数据
                let data=reactive({
                    num:0,
                    userObj:{
                        userName:'wang.qj'
                    },
                    userList:[{userId:1,userName:'张三'}],
                    comNum:computed(()=>{
                        return data.num+"$"
                    })
                })
                watch(()=>data.num,(newvalue,oldvlaue)=>{
                    console.log(newvalue)
                    console.log(oldvlaue)
                })
                function add(){
                    data.num++;//3、 直接访问,不需要加.value,但要通过data访问
                    
                }
                return {
                ...toRefs(data),
                add};
            }
        }
    </script>

<style>
</style>

第一个参数要写成函数返回值的形式,这样就能监听state响应对象中的某个数据了。

上一篇下一篇

猜你喜欢

热点阅读