运行时性能优化
更新时间:
本节提供的关键优化手段可显著提升页面渲染与更新效率。
避免在 CSS 中使用 ID 选择器
推荐级别:强烈
如果只需要在 css 中给组件添加样式,建议使用 class 选择器,只有需要使用 js 操作组件时,才会给组件注册 ID。
反例 1
<!-- 错误:在CSS中通过ID定义样式 -->
<template>
<div id="red"></div>
</template>
<style>
#red {
color: red;
} /* 存在选择器性能损耗 */
</style>
复制代码
正例 1
<!-- 正确:使用class类选择器 -->
<template>
<div class="red"></div>
</template>
<style>
.red {
color: red;
} /* 高效样式定义方式 */
</style>
复制代码
特殊场景说明
<!-- 当元素需被JS操作时保留id -->
<template>
<!-- ID用于JS交互 -->
<div id="root"></div>
</template>
<script>
export default {
onInit() {
this.$element('root').animate() // 通过ID获取元素
},
}
</script>
复制代码
避免循环指令与条件指令叠加使用
推荐级别:建议
若需在循环渲染时进行条件过滤,建议在 JavaScript 中预处理数据,而非在模板层混合for
与if
指令。此优化可减少模板解析复杂度,避免重复渲染计算。
反例
<!-- 低效:模板中混合循环与条件判断 -->
<div for="{{foodList}}" if="{{$item.vegetarian}}">
<text>{{$item.name}}</text>
<text>{{$item.category}}</text>
</div>
复制代码
正例
<!-- 高效:数据层预过滤 -->
<!-- 直接渲染已过滤数据 -->
<div for="{{vegetarianFoods}}">
<text>{{$item.name}}</text>
<text>{{$item.category}}</text>
</div>
复制代码
export default {
data: { vegetarianFoods: [] },
onInit() {
this.vegetarianFoods = foodList.filter((food) => food.vegetarian)
},
}
复制代码
合理选择条件指令
推荐级别:建议
if
与show
指令的本质差异在于 DOM 树操作机制:
if
指令:触发组件级 DOM 树动态构建/销毁,适合低频次状态变更场景show
指令:通过 CSS display 属性控制可视性,DOM 结构保持稳定,适用于高频次显隐切换场景
最佳实践原则:
- 首屏不可见但需快速激活 →
if
指令(降低初始化开销) - 高频交互元素(如 Tab 切换) →
show
指令(减少 DOM 操作损耗)
反例 1
<!-- show指令导致隐藏元素参与首屏渲染,破坏分段加载设计 -->
<template>
<div>
<div>首屏核心模块</div>
<div show="{{display}}">延迟加载模块</div>
</div>
</template>
<script>
export default {
data: { display: false },
onShow() {
this.display = true // 触发CSS样式变更而非DOM操作
},
}
</script>
复制代码
正例 1
<template>
<div>
<div>首屏核心模块</div>
<div if="{{display}}">动态加载模块</div>
</div>
</template>
<script>
export default {
data: { display: false },
onShow() {
this.display = true // 触发DOM树动态构建
},
}
</script>
复制代码
反例 2
<!-- if指令导致高频DOM重建,引发布局抖动 -->
<template>
<div>
<text @click="changeView('A')">视图A</text>
<text @click="changeView('B')">视图B</text>
<div if="{{viewState == 'A'}">视图内容A</div>
<div elif="{{viewState == 'B'}">视图内容B</div>
</div>
</template>
复制代码
正例 2
<template>
<div>
<text @click="changeView('A')">视图A</text>
<text @click="changeView('B')">视图B</text>
<div show="{{viewState == 'A'}">视图内容A</div>
<div show="{{viewState == 'B'}">视图内容B</div>
</div>
</template>
复制代码
组件层级精简
推荐级别:建议
在页面布局中,尽量减少组件的嵌套,如 list-item
本身可以作为容器,不需在其内部要额外的 div 嵌套。
反例
冗余嵌套结构
<template>
<list>
<list-item>
<!-- 冗余包装容器 -->
<div>
<text>数据项标题</text>
<image src="item.png"></image>
</div>
</list-item>
</list>
</template>
复制代码
正例
扁平化结构
<template>
<list>
<list-item>
<text>数据项标题</text>
<image src="item.png"></image>
</list-item>
</list>
</template>
复制代码
组件抽象平衡法则
推荐级别:鼓励
组件化需遵循以下原则:
- 单一页面自定义组件数 ≤ 3
- 简单元素组合(≤3 个基础组件)不建议抽象
反例 1
过度抽象
<!-- 简单统计模块被过度拆分为独立组件 -->
<import src="./components/heartRateBlock.ux" name="heartRate"></import>
<import src="./components/calorieBlock.ux" name="calorie"></import>
复制代码
反例 2
抽象组件滥用
<!-- 独立心率数字展示无需组件化 -->
<import src="./components/heartRate.ux"></import>
<template>
<heartRate></heartRate>
</template>
复制代码
页面职责单一化原则
推荐级别:鼓励
工程化实践要求:
- 功能模块隔离:独立业务状态使用独立页面承载
- 路由参数规范:仅传递必要标识参数,避免状态注入
- 页面体积控制:单文件源码 ≤ 1000 行(编译前)
反例
<template>
<!-- 多态视图混合实例 -->
<div if="{{status === 1}}">
<div>视图模块A</div>
<!-- 50+ 相关节点 -->
</div>
<div if="{{status === 2}}">
<div>视图模块B</div>
<!-- 30+ 相关节点 -->
</div>
</template>
<script>
export default {
data: {
status: 1, // 状态维护成本随功能增加而上升
},
}
</script>
复制代码
正例
采用路由级组件拆分:
<!-- modules/module-a.ux -->
<template>
<div class="optimized-view">
<div>独立视图模块A</div>
<!-- 功能隔离的节点树 -->
</div>
</template>
<!-- modules/module-b.ux -->
<template>
<div class="optimized-view">
<div>独立视图模块B</div>
<!-- 精简的独立节点树 -->
</div>
</template>
复制代码
指定列表渲染标识
推荐级别:鼓励
在动态列表场景中,通过tid
属性指定唯一性标识,确保 Diff 算法准确执行节点复用。
实施要点
- 使用业务主键而非数组索引
- 确保
tid
值的全局唯一性
正例
<template>
<!-- 使用唯一业务标识 -->
<text for="{{athleteList}}" tid="athleteId" class="sport-item">
{{$item.rank}} {{$item.name}}
</text>
</template>
<script>
export default {
data: {
athleteList: [
{ athleteId: 1001, rank: '金牌', name: '张三' },
{ athleteId: 1002, rank: '银牌', name: '李四' },
],
},
}
</script>
复制代码