阿里云主机折上折
  • 微信号
Current Site:Index > Context exposure (expose API)

Context exposure (expose API)

Author:Chuan Chen 阅读数:51599人阅读 分类: Vue.js

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 communication
  • provide/inject is for cross-level data passing
  • expose is better for precise interface control
  • provide/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

  1. Avoid over-exposure: Only expose necessary interfaces.
  2. Naming conflicts: Ensure exposed property names don't clash with native DOM properties.
  3. Reactivity: Exposed refs are automatically unwrapped.
  4. 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

  1. Exposing large amounts of data may impact memory.
  2. Frequent exposure updates may cause performance issues.
  3. 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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.