AI 辅助声明
本文的所有示例由 Deepseek 完成.
有些组件的渲染消耗不少性能, 这其中包括规划中的直接渲染 DirectDraw Surface (.dds) 格式图像的组件.
Vue.js 提供了异步组件完成这一点, 异步组件只会在需要时才渲染, 然后将结果缓存以供之后的重渲染. 例:
JavaScript
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 在此处定义组件
resolve({
template: `
<div>
此处内容异步加载
</div>
`
});
}, 1000);
});作为工厂函数, 其将收到 resolve 回调, 这一回调函数只会在从服务器得到组件定义时被调用. 此外亦可调用 reject (reason) 表示加载失败.
工厂函数
定义: 工厂函数
称返回非单一固定值, 每次调用都返回新实例的函数为工厂函数.
在 Vue.js 中主要用于确保每个组件实例拥有独立的状态副本.
以下是 Vue 2 中选项式 API 的例子:
js
// 非工厂函数: 所有组件实例共享同一 data 对象
Vue.component("my-component", {
data: {
count: 0,
user: {
name: "Alice",
},
},
});
// 工厂函数: 每个组件实例各自拥有独立对象
Vue.component("my-component", {
data() {
return {
count: 0,
user: {
name: "Bell",
},
};
},
});为何使用工厂函数?
- 组件可能被多次实例化;
- 不使用工厂函数, 所有实例将持有同一 data 对象. (你知道吗, Rust 的所有权系统正为此而诞生.)
- 单个实例修改数据将同时影响所有其他实例.
下面是其他示例:
js
// Vue 3 组合式 API
// 组合式函数(Composables)本身就是工厂函数
import { ref, reactive } from 'vue'
function useCounter(initialValue = 0) {
const count = ref(initialValue)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, double, increment }
}
// 每个组件调用时获得独立状态
export default {
setup() {
const counter1 = useCounter(10) // 独立的 ref
const counter2 = useCounter(20) // 独立的 ref
return { counter1, counter2 }
}
}js
// provide/inject 中的工厂函数
// 父组件
export default {
provide() {
return {
// 使用工厂函数提供动态值
theme: computed(() => this.theme),
// 每次注入都获得新实例
createLogger: () => new Logger(this.userId)
}
}
}
// 子组件
export default {
inject: ['createLogger'],
created() {
// 每个组件获得独立的 logger 实例
this.logger = this.createLogger()
}
}js
// Vue Router 的路由组件传参
const router = createRouter({
routes: [
{
path: '/user/:id',
component: UserView,
props: route => ({ // 工厂函数,每次路由变化重新计算
userId: route.params.id,
timestamp: Date.now()
})
}
]
})核心理念
| 场景 | 非工厂函数 | 工厂函数 |
|---|---|---|
| 组件复用 | 所有实例共享状态 | 实例隔离, 互不干扰 |
| 服务端渲染 | 请求间互相污染 | 每个请求状态独立 |
| 测试 | 测试用例互相影响 | 每个测试创建新实例 |
| 组合式函数 | 无法独立使用 | 随时调用, 状态独立 |
注意
- Vue 2 根实例 data 允许为对象, 这是唯一例外;
- 需要访问
this时使用普通函数而非箭头函数; - 性能问题: 工厂函数返回的对象不应包含重复创建的大对象.