Context exposure (expose API)
In Vue.js, Context Exposure (Expose API) is a mechanism that allows internal component state or methods to be exposed to parent components or other external calls. Through the expose
option or the defineExpose
macro, developers can precisely control which content is accessible externally while maintaining the component's encapsulation.
Understanding the Basic Concepts of Context Exposure
Vue 3's Composition API introduced the expose
functionality, allowing components to explicitly declare which properties and methods can be accessed externally. By default, when using the setup()
function, all bound reactive data and methods are automatically exposed. However, expose
can be used to restrict this behavior.
// Child component Child.vue
<script setup>
import { ref } from 'vue'
const internalState = ref('secret')
const publicMethod = () => console.log('Called from parent')
defineExpose({
publicMethod
})
</script>
Using expose
with Options API
In the Options API, the expose
option can be used to specify what to expose:
// Child component Child.vue
export default {
data() {
return {
privateData: 'hidden',
publicData: 'accessible'
}
},
methods: {
privateMethod() { /* ... */ },
publicMethod() { /* ... */ }
},
expose: ['publicData', 'publicMethod']
}
defineExpose
in Composition API
defineExpose
is more commonly used with the <script setup>
syntactic sugar:
<script setup>
const count = ref(0)
const increment = () => count.value++
defineExpose({
count,
increment
})
</script>
How Parent Components Access Exposed APIs
Parent components access exposed content via template refs:
// Parent component Parent.vue
<template>
<Child ref="childRef" />
<button @click="callChildMethod">Call Child Method</button>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const childRef = ref(null)
const callChildMethod = () => {
childRef.value.publicMethod()
console.log(childRef.value.count)
}
</script>
Practical Use Cases
Form Component Validation
Exposing validation methods for parent components to call:
// FormComponent.vue
<script setup>
const validate = () => {
// Validation logic
return isValid
}
defineExpose({ validate })
</script>
// Parent component
const submit = () => {
if (formRef.value.validate()) {
// Submit form
}
}
Complex Component Control
Video player component exposing control methods:
// VideoPlayer.vue
<script setup>
const play = () => { /* ... */ }
const pause = () => { /* ... */ }
const seek = (time) => { /* ... */ }
defineExpose({ play, pause, seek })
</script>
Differences from provide/inject
Key differences between context exposure and provide/inject
:
expose
is for vertical parent-child component communicationprovide/inject
is for cross-level data passingexpose
is better for precise interface controlprovide/inject
is better for global state sharing
TypeScript Support
Adding type definitions for exposed APIs:
// Child.vue
<script setup lang="ts">
const count = ref(0)
const increment = (step: number) => count.value += step
defineExpose({
count,
increment
})
</script>
// In the parent component
const childRef = ref<{
count: number
increment: (step: number) => void
}>()
Considerations
- Avoid over-exposure: Only expose necessary interfaces.
- Naming conflicts: Ensure exposed property names don't clash with native DOM properties.
- Reactivity: Exposed refs are automatically unwrapped.
- Lifecycle: Ensure refs are accessed after the component is mounted.
Advanced Patterns: Dynamic Exposure
Dynamically deciding what to expose based on conditions:
<script setup>
import { computed } from 'vue'
const adminMode = ref(false)
const sensitiveMethod = () => { /* ... */ }
defineExpose(computed(() =>
adminMode.value ? { sensitiveMethod } : {}
))
</script>
Interaction with Template Refs
Combining template refs and expose
:
<template>
<input ref="inputRef">
</template>
<script setup>
import { ref } from 'vue'
const inputRef = ref(null)
defineExpose({
focus: () => inputRef.value.focus()
})
</script>
Performance Considerations
- Exposing large amounts of data may impact memory.
- Frequent exposure updates may cause performance issues.
- Consider using
shallowRef
for complex objects.
Comparison with Other Frameworks
React's useImperativeHandle
is similar to Vue's expose
:
// React comparison
useImperativeHandle(ref, () => ({
publicMethod: () => { /* ... */ }
}))
Debugging Tips
Inspecting what APIs a component exposes:
// Console debugging
console.log(childRef.value)
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn