高级特性
这里将介绍 EwVueComponent 的高级特性,如异步组件、错误边界、插件扩展等。
本文档建设中,敬请期待。
异步组件加载
EwVueComponent 支持异步组件,可以实现按需加载和代码分割:
1. 基础异步组件
vue
<template>
<div class="demo">
<div class="controls">
<button @click="loadComponent('UserProfile')">用户资料</button>
<button @click="loadComponent('Settings')">设置</button>
<button @click="loadComponent('Dashboard')">仪表板</button>
</div>
<div v-if="loading" class="loading">
<div class="spinner"></div>
<p>加载中...</p>
</div>
<EwVueComponent
v-else-if="currentComponent"
:is="currentComponent"
@error="handleError"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref(null)
const loading = ref(false)
const componentMap = {
UserProfile: () => import('./components/UserProfile.vue'),
Settings: () => import('./components/Settings.vue'),
Dashboard: () => import('./components/Dashboard.vue')
}
const loadComponent = async (name) => {
loading.value = true
try {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 1000))
currentComponent.value = componentMap[name]
} catch (error) {
handleError(error)
} finally {
loading.value = false
}
}
const handleError = (error) => {
console.error('异步组件加载失败:', error)
loading.value = false
}
</script>
<style scoped>
.loading {
display: flex;
flex-direction: column;
align-items: center;
padding: 2rem;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 1rem;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
2. 带加载状态的异步组件
vue
<template>
<div class="demo">
<button @click="loadHeavyComponent">加载重型组件</button>
<div v-if="loading" class="loading-state">
<div class="progress-bar">
<div class="progress" :style="{ width: progress + '%' }"></div>
</div>
<p>加载进度: {{ progress }}%</p>
</div>
<EwVueComponent
v-else-if="currentComponent"
:is="currentComponent"
@error="handleError"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref(null)
const loading = ref(false)
const progress = ref(0)
const loadHeavyComponent = async () => {
loading.value = true
progress.value = 0
// 模拟加载进度
const progressInterval = setInterval(() => {
progress.value += 10
if (progress.value >= 100) {
clearInterval(progressInterval)
}
}, 100)
try {
await new Promise(resolve => setTimeout(resolve, 2000))
currentComponent.value = () => import('./components/HeavyComponent.vue')
} catch (error) {
handleError(error)
} finally {
loading.value = false
progress.value = 100
}
}
const handleError = (error) => {
console.error('组件加载失败:', error)
loading.value = false
}
</script>
<style scoped>
.loading-state {
padding: 2rem;
text-align: center;
}
.progress-bar {
width: 100%;
height: 8px;
background: #e2e8f0;
border-radius: 4px;
overflow: hidden;
margin-bottom: 1rem;
}
.progress {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
transition: width 0.3s ease;
}
</style>
错误边界和降级处理
EwVueComponent 提供了完善的错误处理机制:
1. 基础错误处理
vue
<template>
<div class="demo">
<button @click="loadErrorComponent">加载错误组件</button>
<EwVueComponent
:is="currentComponent"
@error="handleError"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('div')
const loadErrorComponent = () => {
// 故意加载一个不存在的组件
currentComponent.value = 'NonExistentComponent'
}
const handleError = (error) => {
console.error('组件错误:', error)
// 降级到默认组件
currentComponent.value = 'div'
}
</script>
2. 使用 fallback 组件
vue
<template>
<div class="demo">
<button @click="loadUnstableComponent">加载不稳定组件</button>
<EwVueComponent
:is="currentComponent"
fallback="div"
@error="handleError"
>
<template #default>
<p>主要内容</p>
</template>
</EwVueComponent>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('div')
const loadUnstableComponent = () => {
// 模拟不稳定的组件
currentComponent.value = Math.random() > 0.5 ? 'UnstableComponent' : 'div'
}
const handleError = (error) => {
console.error('组件错误,使用 fallback:', error)
}
</script>
3. 自定义错误组件
vue
<template>
<div class="demo">
<button @click="loadComponent">加载组件</button>
<EwVueComponent
:is="currentComponent"
:error-component="ErrorComponent"
@error="handleError"
/>
</div>
</template>
<script setup>
import { ref, h } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('div')
// 自定义错误组件
const ErrorComponent = {
render() {
return h('div', { class: 'error-component' }, [
h('h3', '组件加载失败'),
h('p', '抱歉,组件暂时无法加载'),
h('button', {
onClick: () => window.location.reload()
}, '重新加载')
])
}
}
const loadComponent = () => {
// 故意加载错误组件
currentComponent.value = 'BrokenComponent'
}
const handleError = (error) => {
console.error('使用自定义错误组件:', error)
}
</script>
<style scoped>
.error-component {
padding: 2rem;
text-align: center;
background: #fef2f2;
border: 1px solid #fecaca;
border-radius: 0.5rem;
color: #dc2626;
}
.error-component button {
margin-top: 1rem;
padding: 0.5rem 1rem;
background: #dc2626;
color: white;
border: none;
border-radius: 0.25rem;
cursor: pointer;
}
.error-component button:hover {
background: #b91c1c;
}
</style>
插件系统
EwVueComponent 支持插件扩展,可以自定义组件行为:
1. 基础插件
vue
<template>
<div class="demo">
<button @click="togglePlugin">切换插件</button>
<EwVueComponent
:is="currentComponent"
:plugins="activePlugins"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('div')
const activePlugins = ref([])
// 日志插件
const logPlugin = {
name: 'log',
beforeRender(component, props) {
console.log('渲染前:', component, props)
},
afterRender(component, props) {
console.log('渲染后:', component, props)
}
}
// 性能监控插件
const performancePlugin = {
name: 'performance',
beforeRender(component, props) {
performance.mark('component-render-start')
},
afterRender(component, props) {
performance.mark('component-render-end')
performance.measure('component-render', 'component-render-start', 'component-render-end')
}
}
const togglePlugin = () => {
if (activePlugins.value.length === 0) {
activePlugins.value = [logPlugin, performancePlugin]
} else {
activePlugins.value = []
}
}
</script>
2. 自定义插件
vue
<template>
<div class="demo">
<EwVueComponent
:is="currentComponent"
:plugins="[customPlugin]"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('button')
// 自定义插件:添加点击计数
const customPlugin = {
name: 'click-counter',
data: {
clickCount: 0
},
beforeRender(component, props) {
// 在渲染前修改 props
if (component === 'button') {
props.onClick = (event) => {
this.data.clickCount++
console.log(`按钮被点击了 ${this.data.clickCount} 次`)
if (props.originalOnClick) {
props.originalOnClick(event)
}
}
props.originalOnClick = props.onClick
}
}
}
</script>
组件缓存
EwVueComponent 支持组件缓存,提升性能:
vue
<template>
<div class="demo">
<div class="controls">
<button @click="switchToA">组件 A</button>
<button @click="switchToB">组件 B</button>
<button @click="clearCache">清除缓存</button>
</div>
<EwVueComponent
:is="currentComponent"
:cache="true"
:cache-key="cacheKey"
/>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
import ComponentA from './ComponentA.vue'
import ComponentB from './ComponentB.vue'
const currentComponent = ref(ComponentA)
const cacheKey = computed(() => `component-${currentComponent.value.name}`)
const switchToA = () => {
currentComponent.value = ComponentA
}
const switchToB = () => {
currentComponent.value = ComponentB
}
const clearCache = () => {
// 清除组件缓存
// 这里需要调用 EwVueComponent 的缓存清除方法
console.log('缓存已清除')
}
</script>
性能优化
1. 使用 v-if 优化
vue
<template>
<div class="demo">
<button @click="toggleComponent">切换组件</button>
<EwVueComponent
v-if="showComponent"
:is="currentComponent"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const showComponent = ref(true)
const currentComponent = ref('div')
const toggleComponent = () => {
showComponent.value = !showComponent.value
}
</script>
2. 使用 keep-alive
vue
<template>
<div class="demo">
<button @click="switchComponent">切换组件</button>
<keep-alive>
<EwVueComponent
:is="currentComponent"
:key="currentComponent"
/>
</keep-alive>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { EwVueComponent } from 'ew-vue-component'
const currentComponent = ref('ComponentA')
const switchComponent = () => {
currentComponent.value = currentComponent.value === 'ComponentA' ? 'ComponentB' : 'ComponentA'
}
</script>
注意事项
- 异步组件: 确保异步组件函数返回正确的 Promise
- 错误处理: 始终监听
error
事件并提供合适的降级方案 - 性能考虑: 合理使用缓存和 keep-alive,避免不必要的组件重新渲染
- 插件开发: 插件应该遵循单一职责原则,避免副作用
- 类型安全: 使用 TypeScript 时,为插件和异步组件定义正确的类型