Vue3——组合API

使用选项编写组件的逻辑代码在大多数情况下都有效。但是,当使用Vue构建大型项目时,组件代码会比较复杂,这可能会导致组件难以阅读和理解,尤其对于一开始没有参与编写这些组件的人。能够将与一个逻辑关注点相关的代码配置在一起会更好,而这正是组合式API能够做到的。

1、什么是组合API

Vue 3.0中新增了组合API的功能,它是一组附加的、基于函数的API,可以更加灵活地组织组件代码。通过组合API可以使用函数而不是声明选项的方式来编写Vue组件。因此,使用组合API可以将组件代码编写为多个函数,每个函数处理一个特定的功能,不再需要按选项组织代码。

组合API可以更好地和TypeScript集成,同时,组合API可以和现有的基于选项的API一起使用。需要注意的是,组合API是在选项(data、methods和computed)之前进行解析,因此组合API无法访问这些选项中定义的属性。

2、setup()函数

setup()函数是一个新的组件选项,它是组件内部使用组合API的入口。setup()函数在组件实例创建之前、初始化Prop之后调用,而且setup()函数是在beforeCreate钩子函数之前调用。

setup()函数可以返回一个对象或函数,对象的属性会合并到组件模板渲染的上下文中。示例代码如下:

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //创建一个响应式对象
            const data = Vue.reactive({
                number: 10
            });
            function add() {
                data.number += 1;
            }
            //返回一个对象,对象中的属性可以在模板中使用
            return {
                data,
                add
            }
        }
    });
    vm.mount('#app');
</script>

上述代码中,setup()函数返回的是一个对象,该对象有两个属性,一个是响应式对象,另一个是函数。在组件的模板中可以直接使用这两个属性。代码如下:

<div id="app">
    <button @click="add">{{data.number}}</button>
</div>

setup()函数中不能使用this。但是,当和现有的基于选项的API一起使用时,在选项中可以通过this访问setup()函数返回的属性。

setup()函数可以接收两个可选的参数。

  • 第一个参数是响应式的props对象,通过该参数可以访问props选项中定义的Prop。
  • 第二个参数是一个上下文(context)对象,该对象是一个JavaScript对象,它暴露了attrs、slots和emit三个属性。其中,attrs和slots是有状态的对象,它们会随着组件的更新而发生变化,但是这两个对象本身并不是响应式的,因此不能对它们进行解构。

由于setup()函数接收的props对象是响应式的,因此在组件外部传入新的Prop值时,props对象会随着更新。示例代码如下:

<div id="app">
    <my-demo :msg="msg"></my-demo>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        data() {
            return {
                msg: '海阔凭鱼跃,天高任鸟飞。'
            }
        }
    });
    vm.component('my-demo', {
        props: ['msg'],
        setup(props) {
            Vue.watchEffect(()=> {
                console.log(props.msg);
            })
        },
        template: `<p>{{msg}}</p>`
    })
    vm.mount('#app');
</script>

在这里插入图片描述

在浏览器中打开上述示例的页面后,在控制台中输入

const app = document.querySelector('#app').__vue_app__

app._instance.proxy.msg = 'hello'

按Enter键后,可以看到页面内容发生了变化。因此,调用watchEffect()方法或watch()方法可以监听props对象,并对修改做出响应。

在这里插入图片描述

3、响应式API

3.1、reactive()方法

reactive()方法用于将定义的JavaScript对象转换为响应式对象。示例代码如下:

<div id="app">
    <div>姓名:{{data.name}}</div>
    <div>年龄:{{data.age}}</div>
    <p>
        <button @click="data.age=25">修改年龄</button>
    </p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //创建一个响应式对象
            const data = Vue.reactive({
                name: 'Tony',
                age: 20
            });
            //返回一个对象,对象中的属性可以在模板中使用
            return {
                data
            }
        }
    });
    vm.mount('#app');
</script>

上述代码中,使用reactive()方法创建了一个响应式对象data,并以对象的形式返回该对象。当data对象发生变化时,视图会自动更新。运行结果如图所示。

在这里插入图片描述

在这里插入图片描述

3.2、watchEffect()方法

watchEffect()方法用来监听数据的变化,类似于Vue 2.x中的watch选项。该方法接收一个函数作为参数,它会立即执行一次该函数,同时会跟踪函数里面用到的所有响应式状态,当状态发生变化时会重新运行该函数。示例代码如下:

<div id="app">
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //创建一个响应式对象
            const data = Vue.reactive({
                count: 1
            });
            Vue.watchEffect(()=> {
                document.body.innerHTML = `计数器:${data.count}`
            });
            setInterval(()=> {
                data.count++;
            }, 1000);
        }
    });
    vm.mount('#app');
</script>

上述代码中,当响应式对象data发生变化时,会重新运行watchEffect()方法的参数。运行结果如图所示。

在这里插入图片描述

3.3、ref()方法

reactive()方法可以为一个JavaScript对象创建响应式代理,如果需要对某个基本数据类型(如数值类型、字符串类型)的数据创建响应式代理对象,可以通过ref()方法实现。该方法接收一个原始值作为参数,返回一个响应式的对象,该对象只有一个value属性指向内部值。示例代码如下:

<div id="app">
    <p>{{data}}</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //创建一个响应式对象
            const data = Vue.ref(100);
            setInterval(()=> {
                data.value++;
            }, 1000);
            return {
                data
            }
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

如果将ref()方法创建的响应式代理对象作为属性返回,那么在模板中访问时不需要添加.value。

示例:更改商品数量。

实现购物车中更改商品数量的操作。单击“+”按钮增加商品数量,单击“-”按钮减少商品数量,代码如下:

<div id="app">
    商品数量:
    <button @click="data--" :disabled="data === 1 ? true :false">-</button>
    {{data}}
    <button @click="data++">+</button>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //创建一个响应式对象
            const data = Vue.ref(1);
            return {
                data
            }
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

3.4、computed()方法

和computed选项的作用一样,computed()方法用于创建计算属性。该方法接收一个getter函数,并返回一个不可修改的ref对象。示例代码如下:

<div id="app">
    <p>{{newData}}</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            const data = Vue.ref(10);
            const newData = Vue.computed(()=> data.value + 10);
            return {
                newData
            }
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

示例:转换字符串。

将字符串“HTML+CSS+JavaScript”转换为首字母大写,其他字母小写的形式。代码如下:

<div id="app">
    <p>{{newData}}</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            const data = Vue.ref('HTML + CSS + JavaScript');
            const newData = Vue.computed(()=> {
                const d = data.value;
                return d.charAt(0).toUpperCase() + d.substr(1).toLowerCase();
            });
            return {
                newData
            }
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

3.5、watch()方法

watch()方法相当于Vue根实例选项对象中的watch选项。该方法用于监听特定的数据,并在回调函数中应用。当被监听的数据发生变化时,才会调用回调函数。

watch()方法可以接收两个参数。如果使用该方法监听的是一个ref对象,那么第一个参数是需要监听的ref对象,第二个参数是当监听的数据发生变化时触发的回调函数。示例代码如下:

<div id="app">
    请输入米数:<input type="text" size="6" v-model="data">
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            const data = Vue.ref(0);
            Vue.watch(data, ()=> {
                console.log(data.value + '米 = ' + data.value * 100 + '厘米');
            });
            return {
                data
            }
        }
    });
    vm.mount('#app');
</script>

运行上述代码,当文本框中的数字发生变化时,浏览器控制台会输出单位“米”和“厘米”之间的换算结果,如图所示。

在这里插入图片描述

如果使用watch()方法监听一个响应式对象中的某个属性,那么第一个参数需要使用返回该属性的函数的方式。示例代码如下:

<div id="app">
    <p>商品原价格:{{data.price}}</p>
    请输入新价格:<input type="text" size="6" v-model="data.newprice">
    <p>{{data.text}}</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            const data = Vue.reactive({
                price: 399,
                newprice: '',
                text: ''
            });
            Vue.watch(()=> data.newprice, (newValue)=> {
                data.text ='原价格:' + data.price + ' 新价格:' + newValue;
            });
            return {
                data
            }
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

4、生命周期钩子函数

与基于选项的API相比,组合API中的生命周期钩子函数也发生了变化,将选项中的生命周期钩子函数改成了onXxx()函数的形式。需要注意的是,beforeCreate和created两个钩子函数被删除了,取而代之的是setup()函数。选项API和组合API的钩子函数的对应关系如表所示。

选项API钩子函数组合API钩子函数
beforeCreate没有对应的onXxx()函数,取而代之的是setup()函数
created有对应的onXxx()函数,取而代之的是setup()函数
beforeMountonBeforeMount
mountedonMounted
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted

5、使用ref获取DOM元素

在Vue 3.0中,使用ref()方法除了可以对某个原始值创建响应式代理对象,还可以获取模板中的指定DOM元素。要获取指定DOM元素,首先需要为该元素添加一个ref属性,然后在setup()函数中声明一个名称与ref属性值相同的变量,并传入一个空值null,再通过“变量名.value”的形式就可以获取到该元素。示例代码如下:

<div id="app">
    <div ref="ele"></div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            //变量名必须和模板中ref属性值相同,并传入一个空值null
            const ele = Vue.ref(null);
            Vue.onMounted(() => {
                //获取指定元素的标签名并显示
                document.body.innerHTML = ele.value.tagName;
            });
            return {
                ele
            }
        }
    });
    vm.mount('#app');
</script>

上述代码中,为div元素添加了ref属性,属性值为ele,在setup()函数中声明了一个名称同样为ele的变量,并传入空值null,这样,通过ele.value就可以获取到该div元素。运行结果如图所示。

在这里插入图片描述

示例:单机文本改变样式。

定义一行文本,当单击文本时为文本设置颜色和大小,代码如下:

<div id="app">
    <div ref="demo" @click="setStyle">{{text}}</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
    const vm = Vue.createApp({
        setup() {
            const text = Vue.ref('一寸光阴一寸金');
            const demo = Vue.ref(null);
            const setStyle = ()=> {
                demo.value.style = "color:blue; font-size:50px";
            };
            return {
                text, demo, setStyle
            };
        }
    });
    vm.mount('#app');
</script>

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值