开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第33天,点击查看活动详情
前言
随着Vue 3.2的发布,一个新的组合工具提供给我们,叫做 expose。
你是否曾经创建过一个需要向模板提供一些方法和属性的组件,但又希望这些方法对组件是私有的,不能被父类调用?
如果你在开发一个开源的组件或库,你有可能想保持一些内部方法的私有性。在Vue 3.2之前,这并不容易实现,因为所有在选项API中声明的方法或数据等都是公开的,所以模板可以访问它。
组合API也是如此。我们从setup方法中返回的所有东西都可以被父类直接访问。
组合 API
让我们看一个实际的例子。想象一下,我们有一个组件,它创建了一个计数器,每一秒都会更新这个计数器。
MyCounter.vue
<template>
<p>Counter: {{ counter }}</p>
<button @click="reset">Reset</button>
<button @click="terminate">☠️</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup () {
const counter = ref(0)
const interval = setInterval(() => {
counter.value++
}, 1000)
const reset = () => {
counter.value = 0
}
const terminate = () => {
clearInterval(interval)
}
return {
counter,
reset,
terminate
}
}
}
</script>
从组合的角度来看,我希望父级组件能够在需要时直接调用 reset 方法--但我希望保持 terminate 函数和 counter 的引用只对组件可用。 如果我们把这个组件实例化到一个父类中,例如 App.vue,并给它附加一个 ref 引用,我们可以很容易地让父类调用 reset 方法,因为当我们从 setup 中返回它时,它已经和 terminate 一起被暴露了。
App.vue
<template>
<MyCounter ref="counter" />
<button @click="reset">Reset from parent</button>
<button @click="terminate">Terminate from parent</button>
</template>
<script>
import MyCounter from '@/components/MyCounter.vue'
export default {
name: 'App',
components: {
MyCounter
},
methods: {
reset () {
this.$refs.counter.reset()
},
terminate () {
this.$refs.counter.terminate()
}
}
}
</script>
如果现在运行这个,并单击重置或终止按钮,两者都可以工作。
让我们明确说明我们要向父类暴露(expose)的内容,以便只有 reset 函数可用。
MyCounter.vue
<script>
import { ref } from 'vue'
export default {
setup (props, context) {
const counter = ref(null)
const interval = setInterval(() => {
counter.value++
}, 1000)
const reset = () => {
counter.value = 0
}
const terminate = () => {
console.log(interval)
clearInterval(interval)
}
context.expose({ reset })
return {
counter,
reset,
terminate
}
}
}
</script>
这里,我们在 setup 函数中加入了 props 和 context 参数。我们需要有可用的上下文,因为这是 expose 函数的位置。我们也可以像这样使用重构: { expose }。
接下来,我们使用 context.expose 来声明一个我们想要向实例化这个组件的父类公开的元素对象;在这个例子中,我们只打算让 reset 功能可用。
总结
新的 expose 方法是非常直观的,而且很容易在我们的组件中实现。它清除了一些非常重要的组成问题,这些问题在过去甚至需要重写一个完整的组件,所以即使它不是你日常使用的 API,它也是值得收藏在我们文件夹中吃灰。