The exposure method of component instances
In Vue 3, the component instance exposure mechanism is a core feature of the Composition API. Through APIs like expose
and ref
, developers can precisely control the properties and methods exposed by components to the outside world, while using template refs to directly access DOM or child component instances. This design offers both flexibility and encapsulation.
Basic Exposure Methods for Component Instances
By default, Vue 3 components expose the following:
- All properties in the object returned by
setup()
- Options like
data
,computed
, andmethods
in the component configuration.
// Child component Child.vue
export default {
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
}
// Usage in parent component
<template>
<Child ref="childRef" />
</template>
<script setup>
import { ref } from 'vue'
const childRef = ref(null)
// Can access childRef.value.count and childRef.value.increment
</script>
Controlling Exposed Content with expose
The expose
function allows precise control over what is exposed:
// Child component
export default {
setup(props, { expose }) {
const count = ref(0)
const increment = () => count.value++
const reset = () => (count.value = 0)
// Only expose the increment method
expose({
increment
})
return { count, increment, reset }
}
}
// In parent component
childRef.value.increment() // Works
childRef.value.reset() // Error, not exposed
childRef.value.count // Error, not exposed
Template Refs and Component Instances
In the Composition API, template refs are implemented using ref
:
<template>
<Child ref="childRef" />
<input ref="inputRef" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
const childRef = ref(null)
const inputRef = ref(null)
onMounted(() => {
console.log(childRef.value) // Child component instance
console.log(inputRef.value) // DOM element
})
</script>
Component Type Inference and TypeScript
In TypeScript environments, you can declare types for component refs:
// Child component
const Child = defineComponent({
setup() {
const count = ref(0)
const increment = () => count.value++
return { count, increment }
}
})
// Parent component
<template>
<Child ref="childRef" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
const childRef = ref<InstanceType<typeof Child> | null>(null)
// Now with type hints
childRef.value?.increment()
</script>
Handling Multiple Component Refs
When dealing with refs for multiple identical components:
<template>
<Child v-for="i in 3" :key="i" :ref="setChildRef" />
</template>
<script setup>
import { ref } from 'vue'
const childRefs = ref([])
const setChildRef = el => {
if (el) childRefs.value.push(el)
}
</script>
Dynamic Components and Instance Exposure
Dynamic components also support instance exposure:
<template>
<component :is="currentComponent" ref="dynamicComponentRef" />
</template>
<script setup>
import { shallowRef } from 'vue'
const currentComponent = shallowRef(ComponentA)
const dynamicComponentRef = ref(null)
</script>
Instance Forwarding in Higher-Order Components
Forwarding child component instances in HOCs:
// HOC component
export default defineComponent({
setup(_, { expose }) {
const childRef = ref(null)
expose({
getChildInstance: () => childRef.value
})
return () => h(Child, { ref: childRef })
}
})
Ref Handling in Render Functions
Manual ref handling in render functions:
export default {
setup() {
const root = ref(null)
return () =>
h('div', { ref: root }, [
h(Child, { ref: 'child' })
])
}
}
Component Instance Lifecycle
Accessibility of exposed instances during different lifecycle stages:
<template>
<Child v-if="show" ref="childRef" />
</template>
<script setup>
import { ref, watch } from 'vue'
const show = ref(true)
const childRef = ref(null)
watch(show, (newVal) => {
console.log(childRef.value) // Changes based on show's value
})
</script>
Asynchronous Calls to Component Methods
Handling instance access in asynchronous scenarios:
const childRef = ref(null)
const handleAsync = async () => {
await nextTick()
childRef.value?.someMethod()
}
Debugging Techniques for Component Instances
Tips for inspecting instance content during development:
onMounted(() => {
// Inspect component instance in console
console.log(childRef.value)
// Temporarily expose all content (not recommended for production)
childRef.value.$el.__vue__ // Access internal instance
})
Comparison with Vue 2
Instance access in Vue 2:
// Vue 2 Options API
this.$refs.childRef.methodName()
Changes in Vue 3:
- Explicit
ref
declaration required - Controlled exposure via
expose
- Better TypeScript support
Performance Considerations
Potential performance issues from frequent instance access:
// Avoid frequent access in render functions
const BadExample = {
setup() {
const childRef = ref(null)
return () => {
// Executes on every render
if (childRef.value) {
childRef.value.update()
}
return h(Child, { ref: childRef })
}
}
}
Edge Case Handling
Handling potentially null instance refs:
// Safe access
const value = childRef.value?.someProp ?? defaultValue
// Protected method call
childRef.value?.someMethod?.()
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn