Composition API

Composition API是Vue3中推荐的组件代码书写方式,相较于传统的Options API来说,它能让业务逻辑处理和后期代码维护变的更加简单。

首先我们来看Options API的优缺点,在Options API中,一个组件通常由data()、methods、watch、computed来组成,在这些选项里我们可以将数据和功能进行完美的划分。

但是这样会出现一个问题,随着代码量越来越大,我们对一个功能的追踪也变的越来越困难,因为该功能的不同部分总是分割在了不同的选项中,如我们要追踪关于数据A的所有代码时,需要从data()到methods再至watch中寻找所有数据A出现的地方,这十分的麻烦:

而Composition API从根本上解决了这种问题,它针对一个数据开展一条业务线,当你需要寻找与该数据相关的逻辑代码时,它总是一目了然的展现在你的面前,如下图所示,关于数据A的处理都被封装在了一个函数中,不管是data()、methods亦或是watch的逻辑代码都书写在这一个函数中,这对后期维护来讲非常的方便:

setup

基本使用

在Composition API中有一个setup(),该函数能够去代替data()、methods、以及watch和computed,你可以将所有该组件能应用到的代码逻辑都写在这个里面,它具有2个参数,props以及context。

让我们通过Composition API书写一个最简单的例子,现在在setup()函数中你不光可以书写属性,还可以书写方法:

<body>
<div id="app">
<main>
<span @click="callbackfn">{{message}}</span>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const message = "hello composition api"
function callbackfn(event) {
console.log("why do you point me?");
}
return {
message,
callbackfn
}
}
})
app.mount("#app")
</script>
</body>

this的支持

Composition API和Options API两者可以同时使用,它们是不冲突的。

但是需要注意的是,setup()函数取代了Options API中beforeCreate以及created这2个生命周期钩子函数,在官方文档中你可以找到这一则说明:

这意味着,在setup()函数中你不能使用this访问到data中的数据项,但是可以在data()中通过$options拿到setup()返回的对象:

<body>
<div id="app">
<main>
<div>{{dataMessage}}</div>
<div>{{setupMessage}}</div>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const setupMessage = "hello composition api"
// console.log(this.dataMessage); // Cannot read properties of undefined
return {
setupMessage
}
},
data() {
const dataMessage = "hello options api"
console.log(this.$options.setup()); // {setupMessage: 'hello composition api'}
return {
dataMessage
}
}
})
app.mount("#app")
</script>
</body>

响应式数据

非响应式支持

Options API中data()返回的数据均是响应式的:

<body>
<div id="app">
<main>
<button @click="number++">+</button>
&nbsp;{{number}}&nbsp;
<button @click="number--">-</button>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
data() {
let number = 0
return {
number
}
}
})
app.mount("#app")
</script>
</body>

而Composition API中setup()返回的数据并不是响应式的:

<body>
<div id="app">
<main>
<button @click="number++">+</button>
&nbsp;{{number}}&nbsp;
<button @click="number--">-</button>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
let number = 0
return {
number
}
}
})
app.mount("#app")
</script>
</body>

ref

ref能够让值类型的数据在Composition API中具有响应式特征,使用前你需要引入它:

const { ref } = Vue;
let number = ref(0)

它本质上是将这个数据进行了proxy包装,格式如下:

proxy({value:0})

当我们需要在setup()函数内部修改该值时,必须使用该代理器的value属性进行修改,如:

number.value++

但是在模板中需要修改该值则可直接进行修改:

number++

示例如下:

<body>
<div id="app">
<main>
<!-- 在setup()函数内部修改 -->
<button @click="add">+</button>
<!-- 在模板中进行修改 -->
<button @click="number++">+</button>
&nbsp;{{number}}&nbsp;
<!-- 在setup()函数内部修改 -->
<button @click="sub">-</button>
<!-- 在模板中进行修改 -->
<button @click="number--">-</button>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const { ref } = Vue;
let number = ref(0)
const add = event => {
number.value++;
}
const sub = event => {
number.value--;
}
return {
number,
add,
sub
}
}
})
app.mount("#app")
</script>
</body>

reactive

reactive能够让引用类型的数据在Composition API中具有响应式特征,使用前你需要引入它:

const { reactive } = Vue;
let ary = reactive([1, 2, 3, 4, 5])

它本质上是将这个数据进行了proxy包装,格式如下:

Proxy {0: 1, 1: 2, 2: 3, 3: 4, 4: 5}

如果是Object,则包装后的格式如下:

Proxy {name: 'Jack', age: 18, gender: 'male'}

我们不管是在模板中,还是在setup()函数中,都可以直接对其进行操作。

示例如下:

<body>
<div id="app">
<main>
<!-- 在setup()函数内部修改 -->
<button @click="push">+</button>
<!-- 在模板中进行修改 -->
<button @click="ary.push(ary[ary.length-1]+1)">+</button>
&nbsp;{{ary}}&nbsp;
<!-- 在setup()函数内部修改 -->
<button @click="pop">-</button>
<!-- 在模板中进行修改 -->
<button @click="ary.pop()">-</button>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const { reactive } = Vue;
let ary = reactive([1, 2, 3, 4, 5]) const push = event => {
const lastValue = ary[ary.length - 1]
ary.push(lastValue + 1)
}
const pop = event => {
ary.pop()
} return {
ary,
push,
pop
}
}
})
app.mount("#app")
</script>
</body>

toRefs

有时候我们并不需要return一个完整的对象,而是return一个对象中单独的某个值,这个时候我们必须通过toRefs对对象进行解构赋值,才能够获得响应对象:

<body>
<div id="app">
<main>
<ul>
<li>
<span @click="name = name.toUpperCase()">{{name}}</span>
</li>
<li>
<span @click="age = '*'+age+'*'">{{age}}</span>
</li>
<li>
<span @click="gender = gender.toUpperCase()">{{gender}}</span>
</li>
</ul>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const { reactive, toRefs } = Vue;
let message = reactive({
name: "Jack",
age: 18,
gender: "male"
})
const { name, age, gender } = toRefs(message)
return {
name,
age,
gender
}
}
})
app.mount("#app")
</script>
</body>

它相当于使用ref对每个值进行包裹,所以说在setup()函数内部修改这些被解构出来的值时,需要使用proxy的value属性进行修改:

setup(props, context) {
const { reactive, ref } = Vue;
let message = reactive({
name: "Jack",
age: 18,
gender: "male"
})
return {
name: ref(message.name),
age: ref(message.age),
gender: ref(message.gender)
}
}

toRef

在我们对对象进行解构赋值时,有可能出现没有的值,这个时候我们得到的结果是undefined。

如果后续对该值进行修改,让其进行变更时也需要进行响应式支持的话,则必须使用toRef进行解构赋值,如下所示:

<body>
<div id="app">
<main>
<ul>
<li>{{name}}</li>
<li>{{age}}</li>
<li>{{gender}}</li>
<li>{{score}}</li>
</ul>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const app = Vue.createApp({
setup(props, context) {
const { reactive, toRefs, toRef, ref } = Vue;
let message = reactive({
name: "Jack",
age: 18,
gender: "male"
})
let { name, age, gender } = toRefs(message)
// 现在获取的对象是undefined,因为message中没有score属性
let score = toRef(message, "score") // 3s后将它修改为100,如果没有使用toRefs对其进行包裹,那么这种变更则不是响应式的
// 它相当于 let score = ref(message.score) || ref(undefined);
setTimeout(() => {
score.value = 100
}, 3000) return {
name,
age,
gender,
score
}
}
})
app.mount("#app")
</script>
</body>

本节陈述

这一小结主要针对Composition API对数据非响应式支持做出的介绍,Vue3中提供了很多种解决方案,最常用的就是上面举例的4种:

  • ref:让值类型的数据能够支持响应式操作
  • reactive:让引用类型的数据能够支持响应式操作
  • toRefs:让解构赋值出的对象和源容器对象之间具备响应式操作
  • toRef:针对解构赋值没有的对象支持响应式操作

除开reactive,其他诸如ref、toRefs以及toRef的数据变更都需要使用proxy.value属性进行操作。

组件化开发

props参数

我们都知道,在setup()函数中不能使用this,因此在父子通信时父组件传递给子组件的信息需要子组件使用setup()的props参数进行接收,以下是使用方法:

<body>
<div id="app">
<cpn :child-recv-data="fatherData"></cpn>
</div> <!-- 子组件模板 -->
<template id="cpn-tpl">
<div>
<span>{{childRecvData}}</span>
</div>
</template>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef } = Vue const app = Vue.createApp({
setup(props, context) {
const fatherData = ref("father data")
return {
fatherData
}
}
}) app.component("cpn", {
template: "#cpn-tpl",
props: {
childRecvData: { required: true, type: String }
},
setup(props, context) {
// 这里的props等同于上面的props
const { childRecvData } = props
return {
childRecvData
}
}
}) app.mount("#app") </script>
</body>

context参数

context参数有3个属性可供调用:

  • attrs:相当于no_props的属性继承
  • slots:能够获取组件中的插槽
  • emit:能够进行自定义事件

首先是context.attrs,如同no_props一样,它能获取组件使用时所元素身上所绑定的非动态属性:

<body>
<div id="app">
<cpn data-font-size="font-size:16px" data-font-color="color:#fff"></cpn>
</div> <!-- 子组件模板 -->
<template id="cpn-tpl">
<div>
<span>cpn</span>
</div>
</template>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef } = Vue const app = Vue.createApp({}) app.component("cpn", {
template: "#cpn-tpl",
setup(props, context) {
console.log(context.attrs["data-font-size"]); // font-size:16px
console.log(context.attrs["data-font-color"]); // color:#fff
return {}
}
}) app.mount("#app") </script>
</body>

其次是context.slots,它能获取组件中的槽位信息:

<body>
<div id="app">
<cpn>
<template v-slot:default>
<span>default slot</span>
</template>
</cpn>
</div> <!-- 子组件模板 -->
<template id="cpn-tpl">
<div>
<slot></slot>
</div>
</template>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef, h } = Vue const app = Vue.createApp({}) app.component("cpn", {
template: "#cpn-tpl",
setup(props, context) {
// {__v_isVNode: true, __v_skip: true, type: 'span', props: null, key: null, …}
console.log(context.slots.default()[0]);
// 修改槽位中元素样式
return () => h("div", { style: "color:#aaa" }, [context.slots.default()])
}
}) app.mount("#app") </script>
</body>

最后是context.emit,它能发送自定义事件,可用于子组件向父组件传递信息,这个是最常用的属性:

<body>
<div id="app">
<cpn @read-event="callbackfn"></cpn>
</div> <!-- 子组件模板 -->
<template id="cpn-tpl">
<div>
<span>cpn</span>
</div>
</template>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef, h } = Vue const app = Vue.createApp({
setup(props, context) {
function callbackfn(...params) {
console.log(params);
// ['child data']
}
return {
callbackfn
}
}
}) app.component("cpn", {
template: "#cpn-tpl",
setup(props, context) {
const childData = "child data"
context.emit("readEvent", childData)
return {}
}
}) app.mount("#app")
</script>
</body>

readonly

通过readonly让对象不可更改,这种不可更改是更深层次的限定,比如数组嵌套对象时,你既不能修改外部数组中的内容,也不能修改内部对象中的内容。

下面是readonly简单的使用例子,我们可将它用于组件通信当中,对于一些只能看不能修改的数据非常方便:

<body>
<div id="app">
{{message}}
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef, readonly } = Vue const app = Vue.createApp({
setup(props, context) {
// 只能看,不能改
const message = readonly(
reactive(
[
{ id: 1, name: "Jack", age: 19 },
{ id: 1, name: "Tom", age: 18 },
{ id: 1, name: "Mary", age: 21 }
]
)
)
return {
message
}
}
}) app.mount("#app") </script>
</body>

inject与provide

令人激动的消息,相信在之前学习组件通信时,你对props和emit的通信方式心存怨念,认为这样太麻烦了。

不错,有许许多多的人和你具有同样的想法,这不,在Vue3中迎来了更简单好用的组件通信方式,即inject()和provide()。

使用它们就像是使用消息发布订阅系统一样,你只需要在某一个组件上通过provide()发送出一则数据,那么该Vue应用下所有的组件都可以使用inject()来对该数据进行接收。

这意味着兄弟组件、爷孙组件等都可以直接的进行通信了,而不再是将数据一层一层的进行传递。

下面是一个简单的使用案例:

<body>
<div id="app">
<cpn></cpn>
</div> <!-- 子组件模板 -->
<template id="cpn-tpl">
<div>
<span>{{message}}</span>
</div>
</template>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, toRefs, toRef, readonly, inject, provide } = Vue const app = Vue.createApp({
setup(props, context) {
const message = readonly(
reactive(
[
{ id: 1, name: "Jack", age: 19 },
{ id: 1, name: "Tom", age: 18 },
{ id: 1, name: "Mary", age: 21 }
]
)
)
// 发布数据,指定key和value
provide("message", message)
return {}
}
}) app.component("cpn", {
template: "#cpn-tpl",
setup(props, context) {
// 订阅数据,指定key和defaultValue,如果没有该数据则采用defaultValue
const message = inject("message", "default value")
return {
message
}
}
}) app.mount("#app") </script>
</body>

计算属性

computed

Composition API中的computed使用与Options API中computed的使用已经不同了。

你必须先导入它然后再到setup()中进行定义,示例如下,computed()参数可以是一个function:

<body>
<div id="app">
<main>
<div>
<span>{{number1}}</span>
</div>
<div>
<span>{{number2}}</span>
</div>
<div>
<! -- 修改number1的值,number2会重新进行计算 -->
<button @click="number1++">number1 + 1</button>
<br>
<button @click="number1--">number1 - 1</button>
</div>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, computed } = Vue;
const app = Vue.createApp({
setup(props, context) {
let number1 = ref(100);
let number2 = computed(() => {
return number1.value * 2
})
return {
number1,
number2
}
}
})
app.mount("#app")
</script>
</body>

get和set

Composition API中的computed()参数也可以是一个Object,该Object允许定义get和set方法,这意味着你可以对computed attribute进行重新赋值。

示例如下:

<body>
<div id="app">
<main>
<div>
<button @click="number++">+</button>
<span>&nbsp;{{number}}&nbsp;</span>
<button @click="number--">-</button>
</div>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, computed } = Vue;
const app = Vue.createApp({
setup(props, context) {
let _n = ref(100);
let number = computed({
get() {
console.log("computed get()");
return _n.value;
},
set(newValue) {
console.log(("computed set()"));
_n.value = newValue;
}
})
return {
number
}
}
})
app.mount("#app")
</script>
</body>

数据侦听

watch

同computed一样,如果你想在Composition API中使用watch进行数据监听,则必须先导入后使用。

以下是关于watch最基本的使用,当点击<span>元素时,会触发watch侦听:

<body>
<div id="app">
<main>
<span @click="count++">count</span>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, watch } = Vue;
const app = Vue.createApp({
setup(props, context) {
let count = ref(0);
// 要监听的属性,回调函数(新值,旧值)
watch(count, (newValue, oldValue) => {
console.log(`count ${oldValue} => ${newValue}`);
})
return {
count
}
}
})
app.mount("#app")
</script>
</body>

Compostion API中的watch允许监听对象的某一个属性,这非常的便捷,如下所示我们只侦听ary中最后一位数据项的变化:

<body>
<div id="app">
<main>
<ul>
<li v-for="v in ary">
<input type="text" v-if="ary.indexOf(v) === ary.length-1" :value="v"
@change="callbackfn(ary.indexOf(v), $event)">
<input type="text" v-else :value="v" @change="callbackfn(ary.indexOf(v), $event)">
</li>
</ul>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, watch } = Vue;
const app = Vue.createApp({
setup(props, context) {
let ary = reactive(
["A", "B", "C", "D"]
); function callbackfn(index, event) {
ary[index] = event.target.value
} // 第一个参数必须是一个函数,返回你要侦听的对象属性
// 第二个参数是回调函数(新值,旧值)
// 如下所示,只侦听ary的最后一个元素变更
watch(() => ary[ary.length - 1], (newValue, oldValue) => {
console.log(`ary last element change : ${oldValue} => ${newValue}`);
}) return {
ary,
callbackfn
}
}
})
app.mount("#app")
</script>
</body>

Composition API中的watch现在可以更加方便的实现监听多个属性的变化了,相对于Options API中的watch这一点十分强大。

下面这个例子中不管是number1发生改变还是number2发生改变,都将触发watch的回调函数:

<body>
<div id="app">
<main>
<p><span @click="number1++">{{number1}}</span></p>
<p><span @click="number2++">{{number2}}</span></p>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, watch } = Vue;
const app = Vue.createApp({
setup(props, context) {
let number1 = ref(100);
let number2 = ref(100);
// watch(数组<监听对象1,监听对象2>, 回调函数(数组<监听对象1新值,监听对象1旧值>, 数组<监听对象2新值,监听对象2旧值>)=>{})
watch([number1, number2], (
(
[number1NewValue, number1OldValue],
[number2NewValue, number2OldValue]
) => {
console.log(`number1 change ${number1NewValue} ${number1OldValue}`)
console.log(`number2 change ${number2NewValue} ${number2OldValue}`)
}
))
return {
number1,
number2
}
}
})
app.mount("#app")
</script>
</body>

watch中允许传入第三个参数配置对象,如下示例:

<body>
<div id="app">
<main>
{{message}}
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, watch } = Vue;
const app = Vue.createApp({
setup(props, context) {
let message = reactive(
[
{ id: 1, name: "Jack", age: 19 },
{ id: 1, name: "Tom", age: 18 },
{ id: 1, name: "Mary", age: 21 }
]
)
watch(message, ((newValue, oldValue) => {
console.log(`message change ${oldValue} => ${newValue}`);
}
), {
// 及早侦听,默认为false,如果为true,它将会在页面一打开就触发callbackfn,而不是在数据发生变更时才触发callbackfn
// 默认的watch为false,即惰性侦听,只有在在数据发生变更时才触发callbackfn
immediate: true,
// 深度侦听,默认为true, 即当多层对象嵌套时它会侦听所有对象内部的变化,而不仅仅是一层
deep: true
})
return {
message,
}
}
})
app.mount("#app")
</script>
</body>

watchEffect

Composition API中新增了watchEffect侦听。

它与watch侦听的区别在于:

  • watchEffect是对当前setup()函数下所有数据的全局侦听,而watch只能侦听一个或者多个,需要我们手动进行配置
  • watchEffect的侦听回调函数是没有参数的,而watch侦听的回调函数是具有参数的
  • watchEffect的侦听是及早侦听,而watch的侦听默认是惰性侦听(可通过配置项配置为及早侦听)

如下示例,我们使用watchEffect侦听当前setup()函数中所有数据的变化:

<body>
<div id="app">
<main>
<table>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>gender</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="text" v-model="name">
</td>
<td>
<input type="number" v-model="age">
</td>
<td>
<select v-model="gender">
<option value="male">male</option>
<option value="female">female</option>
</select>
</td>
</tr>
</tbody>
</table>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, watchEffect } = Vue;
const app = Vue.createApp({
setup(props, context) {
let name = ref("");
let age = ref(0);
let gender = ref("male");
// 会监听name、age、gender。
// 只能拿到当前的值,不能拿到之前的值
watchEffect(() => {
console.log("start watchEffect");
console.log(name.value);
console.log(age.value);
console.log(gender.value);
})
return {
name,
age,
gender
}
}
})
app.mount("#app")
</script>
</body>

其他知识

钩子函数变更

在Options API中如果你需要定义生命周期钩子函数,则只需要新增对应的选项即可,如:

"use strict";
const app = Vue.createApp({
beforeCreate(){
console.log("beforeCreate");
},
created(){
console.log("created");
}
})
app.mount("#app")

而在Composition API中,你必须先导入这些钩子函数,然后在setup()函数中对它们进行使用,注意导入时需要加上前缀on,如下所示:

"use strict";
const { onBeforeMount, onMounted } = Vue;
const app = Vue.createApp({
setup(props, context) {
onBeforeMount(() => {
console.log("beforeMount");
})
onMounted(() => {
console.log("mounted");
})
}
})
app.mount("#app")

官方例举了它们详细的变更记录,如下表所示:

Options API Composition API
beforeCreate 没有了,被setup()函数取代了
created 没有了,被setup()函数取代了
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated

辅助性函数

setup()中可以定义任何数据或者对象,当你的业务非常复杂时,我们也可以定义多个辅助性函数来让代码结构更清晰,如下所示:

<body>
<div id="app">
<button @click="aData.callbackfn">{{aData.a}}</button>
<button @click="bData.callbackfn">{{bData.b}}</button>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict"; const { ref, reactive, computed } = Vue; // 数据A相关逻辑
function logicA() {
const _a = ref("a");
const a = computed({
get() {
return _a.value
}
})
const callbackfn = () => {
console.log("hello a");
}
return {
a,
callbackfn
}
} // 数据B相关逻辑
function logicB() {
const _b = ref("b");
const b = computed({
get() {
return _b.value
}
})
const callbackfn = () => {
console.log("hello b");
} return {
b,
callbackfn
}
} const app = Vue.createApp({
setup(props, context) {
// 调用辅助性函数
const aData = reactive(logicA());
console.log(aData);
const bData = reactive(logicB());
return {
aData,
bData
}
}
})
app.mount("#app")
</script>
</body>

获取真实DOM对象

在某些时候我们需要获取真实的一个DOM对象,该如何做呢?

其实你可以为这个元素绑定一个ref属性,该ref属性指向setup()函数中的一个变量。

然后我们可以通过这个变量的value属性拿到真实的DOM对象,整体流程如下所示:

<body>
<div id="app">
<main>
<!-- 1.指定需要绑定的变量 -->
<span ref="spanNode">span</span>
<div ref="divNode">div</div>
</main>
</div>
<script src='https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js'></script>
<script>
"use strict";
const { ref, reactive, onMounted } = Vue;
const app = Vue.createApp({
setup(props, context) {
// 2. 绑定的变量必须通过ref进行包裹
let spanNode = ref(null);
let divNode = ref(null);
// 3.接下来你就可以通过value属性拿到DOM元素
onMounted(() => {
{
console.log(spanNode.value); // <span>span</span>
console.log(divNode.value); // <div>div</div>
}
})
// 你必须将它们返回出去
return {
spanNode,
divNode
}
}
})
app.mount("#app")
</script>
</body>

好久没发文了,一篇Vue3的Composition API使用奉上的更多相关文章

  1. 基于 Vue3.0 Composition Api 快速构建实战项目

    Quick Start 项目源码:https://github.com/Wscats/vue-cli 本项目综合运用了 Vue3.0 的新特性,适合新手学习

  2. vue3.0 composition API

    一.Setup函数 1.创建时间:组件创建之前被调用,优先与created被调用,this指向的实例为window,created所指向的实例为proxy 2.this指向:不会指向组件实例 3.参数 ...

  3. 好久没来了,重出江湖,共享个python34+pyqt+pyserial串口工具源码

    真的是好久没来了,写博客对我来说还真是难坚持下来,热度一过就忘了,就算什么时候想起来也懒得去敲一个字,这次真不知道能坚持多久,随心吧,想写写,不想写也不勉强自己. 最近由于工作调试需要自己写了一个带图 ...

  4. kotlin电商学习记录,好久没来逛逛了

    好久没来,一直做毕业设计,用kotlin写一个基于以图搜图的购物app,现在又赶上实习,内容多,时间少,不过前途光明并由贵人指点.加油 kotlin电商学习记录 技术选型 视图层 kotlin-and ...

  5. 好久没玩docker了,温下手

    好久没玩docker了,温下手 安装 Docker Docker 软件包已经包括在默认的 CentOS-Extras 软件源里.因此想要安装 docker,只需要运行下面的 yum 命令: yum i ...

  6. 好久没玩laravel了,今天玩下Laravel项目迁移步骤

    .在新的目录中克隆git远程版本库 .执行composer install安装依赖 .执行php artisan key:generate生成key 好久没玩laravel了,今天玩下Laravel项 ...

  7. 好久没写原生的PHP调用数据库代码了分享个

    好久没写原生的PHP代码调用数据库了 eader("Content-type: text/html; charset=utf-8"); $time=$symptoms=$attr= ...

  8. 第三十一篇:vue3和vue2的不同

    好家伙 1.为什么会有vue3? Vue2和Vue3的区别 - 简书 (jianshu.com) 貌似是因为他的对手太优秀,所以他也必须进步 2.什么是api? 从文件操作开始谈API. 以C语言为例 ...

  9. 好久没写Blog了

    上一年的经历: <炸年兽>搞了一阵后,美术去创业了.. 和另一个美术断断续续,做了个<斗战圣佛>,挺山寨的,都没敢跟别人说. 不管怎么说也算是自己上了一个appStore的游戏 ...

随机推荐

  1. Hibernate5 入门之SessionFactory对象的创建

    hibernate5创建SessionFactory不同于hibernate4和hibernate3,下面是代码示例. package top.scorpion.util; import org.hi ...

  2. Commons-Collections(二)之map

    BidiMap: 双重Map 使用双向映射,可以使用值查找键,并且可以使用键轻松查找值.(自然,它可以根绝key移除,也可以根据value移除) public interface BidiMap< ...

  3. [ASP.NET MVC]EntityFramework离线部署

    根据项目需要可能会需要离线开发或者网速不好的情况下,很难配置EF,这种情况下就进行离线配置 (1)下载离线EF包: EF6.0的packages,百度网盘链接:https://pan.baidu.co ...

  4. linux(3)--------SSH工具的安装使用

    0.一般安装服务端的Linux ssh是默认安装的可以运行ssh localhost测试一下是否可以链接 1.SSH是什么 1)ssh:Secure Shell  安全外壳协议 2)建立在应用层基础上 ...

  5. urllib3中学到的LRU算法

    介绍 urllib3._collections.py::RecentlyUserContainer类,是一个线程安全的Dict类容器,用来维护一定数量(maxsize)的Key-Value映射, 当数 ...

  6. linux上传下载文件(转载https://www.jb51.net/article/143112.htm)

    转载于:https://www.jb51.net/article/143112.htmLinux下目录复制:本机->远程服务器 1 scp -r /home/shaoxiaohu/test1 z ...

  7. 集合框架2- ArrayList

    其实 Java 集合框架也叫做容器,主要由两大接口派生而来,一个是 collection,主要存放对象的集合.另外一个是Map, 存储着键值对(两个对象)的映射表. 下面就来说说 List接口,Lis ...

  8. ASH数据的迁移:导出导入

    自己写的小工具: 查看帮助 [oracle@redhat76 2]$ ./orash Usage: sh orash keyword [value1] [value2] --------------- ...

  9. 洛谷P3130 haybalesCounting Haybale P 题解

    题目 [USACO15DEC]haybalesCounting Haybale P 题解 最近刚刚自学了线段树这个数据结构,恰巧做到了这道线段树的模板题.其实也没有什么好多说的,接触过线段树的大犇肯定 ...

  10. Django使用tinymce富文本编辑器

    1 - 安装 pip install django-tinymce==2.6.0 2 - 注册app INSTALLED_APPS = ( ... 'tinymce', ) 3 - 在setting中 ...