Vue 3, with its refactored Composition API and reactive system, provides developers with more flexible code organization and powerful extensibility. This section dives deep into Vue 3’s core advanced features, offering a comprehensive exploration from reactive programming to plugin development.
Composition API
Core Concepts of the Composition API
The setup function serves as the entry point for the Composition API, playing a critical role during component creation:
export default {
setup(props, context) {
// props: Destructuring loses reactivity
const { title } = toRefs(props)
// context includes attrs, slots, emit
const { emit } = context
// Returned object is exposed to the template
return {
title,
handleClick: () => emit('click')
}
}
}
Reactivity Basics:
ref: Wraps primitive values, accessed via.value.reactive: Creates reactive objects, supporting nested properties.toRefs: Converts a reactive object into a collection of ref objects.
Reactive Data Management Strategies
Choosing Between ref and reactive:
| Scenario | Recommended API | Reason |
|---|---|---|
| Primitive values | ref | reactive cannot directly proxy primitives |
| Objects/Arrays | reactive | Maintains object reference, avoids losing reactivity during destructuring |
| Destructuring reactive objects | toRefs + reactive | Keeps destructured properties reactive |
| Template references | ref | Specifically for DOM elements or component instances |
Complex Scenario Example:
setup() {
// Primitive type
const count = ref(0)
// Object type
const user = reactive({
name: 'Alice',
profile: {
age: 25
}
})
// Destructuring with reactivity
const { name, profile } = toRefs(user)
return { count, name, profile }
}
Computed Properties and Watchers
Computed Implementation:
import { ref, computed } from 'vue'
setup() {
const price = ref(100)
const quantity = ref(2)
// Cached computed property
const total = computed(() => price.value * quantity.value)
// Writable computed property
const doubleCount = computed({
get: () => count.value * 2,
set: (val) => { count.value = val / 2 }
})
return { total, doubleCount }
}
Advanced watchEffect Usage:
import { ref, watchEffect } from 'vue'
setup() {
const searchQuery = ref('')
const results = ref([])
// Automatically tracks dependencies
watchEffect(async (onCleanup) => {
const timer = setTimeout(async () => {
results.value = await fetchResults(searchQuery.value)
}, 500)
// Cleanup side effects
onCleanup(() => clearTimeout(timer))
})
return { searchQuery, results }
}
Lifecycle Hooks Mapping
Composition API Lifecycle Comparison:
| 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 |
Multiple Hooks Registration Example:
import { onMounted, onUpdated, onUnmounted } from 'vue'
setup() {
const timer = ref(null)
onMounted(() => {
timer.value = setInterval(() => {
console.log('Component mounted')
}, 1000)
})
onUpdated(() => {
console.log('Component updated')
})
onUnmounted(() => {
clearInterval(timer.value)
})
}
Custom Hook Development Pattern
Custom Hook Example: useFetch:
// hooks/useFetch.js
import { ref } from 'vue'
export function useFetch(url) {
const data = ref(null)
const error = ref(null)
const loading = ref(false)
const fetchData = async () => {
loading.value = true
try {
const response = await fetch(url)
data.value = await response.json()
} catch (err) {
error.value = err
} finally {
loading.value = false
}
}
return { data, error, loading, fetchData }
}
// Usage in component
import { useFetch } from './hooks/useFetch'
setup() {
const { data, loading, fetchData } = useFetch('/api/user')
onMounted(fetchData)
return { data, loading }
}
Hook Composition Example:
// Combining multiple hooks
setup() {
const user = useUser()
const cart = useCart()
const notifications = useNotifications()
return { ...user, ...cart, ...notifications }
}
Render Functions and JSX
Render Function Basics
Core Parameters of the h Function:
import { h } from 'vue'
export default {
render() {
return h('div',
{ class: 'container' },
[
h('h1', 'Title'),
h(MyComponent, { prop: 'value' })
]
)
}
}
Dynamic Component Rendering:
const components = {
'text': TextComponent,
'image': ImageComponent
}
render() {
return h(components[this.type], {
...this.$attrs
})
}
JSX Configuration and Transformation
vite.config.js Configuration:
import vue from '@vitejs/plugin-vue'
export default {
plugins: [
vue({
jsx: true // Enable JSX support
})
]
}
JSX Syntax Example:
export default {
props: ['message'],
setup(props) {
const handleClick = () => {
console.log(props.message)
}
return () => (
<button onClick={handleClick}>
{props.message}
</button>
)
}
}
Dynamic Component Implementation
Advanced Dynamic Component Pattern:
const DynamicRenderer = {
props: ['componentType', 'propsData'],
setup(props) {
const componentMap = {
alert: AlertComponent,
modal: ModalComponent
}
return () => {
const Component = componentMap[props.componentType]
return Component ? h(Component, props.propsData) : null
}
}
}
Higher-Order Component Implementation
HOC Factory Function:
function withLoading(WrappedComponent) {
return {
props: WrappedComponent.props,
setup(props, { slots }) {
const loading = ref(false)
const wrappedSlots = {
default: (props) => h(WrappedComponent, { ...props, loading })
}
return () => loading.value
? h('div', 'Loading...')
: h(WrappedComponent, { ...props, loading })
}
}
}
// Usage
const EnhancedComponent = withLoading(BaseComponent)
Render Performance Optimization
Key Optimization Strategies:
- Static Hoisting: Extract static nodes outside the render function.
- Patch Flags: Vue 3 automatically marks dynamic nodes.
- Event Handler Caching: Avoids recreating functions repeatedly.
- v-memo Directive: Caches subtree rendering.
Optimization Example:
// Optimize list rendering with v-memo
render() {
return h('ul',
this.items.map(item =>
h('li',
{ key: item.id, vMemo: [item.id] },
item.text
)
)
)
}
Custom Directives and Plugin Development
Advanced Directive Implementation
Complete Directive Lifecycle:
const vFocus = {
// When element is mounted
mounted(el, binding) {
if (binding.modifiers.autofocus) {
el.focus()
}
},
// When component updates
updated(el, binding) {
if (binding.value !== binding.oldValue) {
el.style.color = binding.value ? 'red' : 'black'
}
},
// When element is unmounted
unmounted(el) {
el.removeEventListener('click', handleClick)
}
}
// Directive with parameters
const vResize = {
mounted(el, binding) {
const callback = binding.value
const observer = new ResizeObserver(entries => {
callback(entries[0].contentRect)
})
observer.observe(el)
el._resizeObserver = observer
},
unmounted(el) {
el._resizeObserver.disconnect()
}
}
Directive Parameter Parsing
Modifier Handling Example:
const vDebounce = {
mounted(el, binding) {
const { value: fn, modifiers } = binding
let delay = 300
if (modifiers.fast) delay = 100
if (modifiers.slow) delay = 1000
let timeout
el.addEventListener('input', () => {
clearTimeout(timeout)
timeout = setTimeout(() => fn(), delay)
})
}
}
Plugin Development Standards
Standard Plugin Structure:
// plugins/myPlugin.js
export default {
install(app, options) {
// 1. Register global component
app.component('MyComponent', MyComponent)
// 2. Register global directive
app.directive('focus', vFocus)
// 3. Add global method
app.config.globalProperties.$myMethod = () => {...}
// 4. Provide dependency injection
app.provide('myInjection', options.value)
// 5. Mixin global logic
app.mixin({
created() {
console.log('Global mixin')
}
})
}
}
// Use plugin
import { createApp } from 'vue'
import App from './App.vue'
import myPlugin from './plugins/myPlugin'
const app = createApp(App)
app.use(myPlugin, { value: 123 })
app.mount('#app')
Plugin Performance Optimization
On-Demand Plugin Loading:
// Dynamic plugin loading
export async function loadPlugin(app, pluginName) {
const plugin = await import(`./plugins/${pluginName}`)
app.use(plugin.default)
}
// Conditional directive registration
const conditionalDirective = {
install(app) {
if (process.env.NODE_ENV === 'development') {
app.directive('debug', vDebug)
}
}
}
Compatibility Handling
Browser Feature Detection:
const vIntersection = {
mounted(el, binding) {
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
binding.value()
}
})
observer.observe(el)
el._intersectionObserver = observer
} else {
// Fallback solution
binding.value()
}
},
unmounted(el) {
if (el._intersectionObserver) {
el._intersectionObserver.disconnect()
}
}
}
Polyfill Strategy:
// vite.config.js
import legacy from '@vitejs/plugin-legacy'
export default {
plugins: [
legacy({
targets: ['defaults', 'not IE 11']
})
]
}
By mastering Vue 3’s advanced features, developers can build more flexible, efficient, and maintainable large-scale applications. It’s recommended to gradually introduce these advanced features based on project needs and continuously optimize application performance using performance analysis tools.



