- API 路由统一: 移除 /api/h5/,统一 /api/pms/ 入口 - 二进制改名: api-server -> pms-api(与服务名一致) - nginx: 合并 /api/ + /pms/api/ 为 /api/pms/ - 新增 docs/API.md 接口文档 - 后端: CabinetDetail 增加 rssi/pow_fail/address/soc 等字段 - Redis 管道批量读取仓体实时数据(SOC/电压/电流/功率) - DB: 所有 TIMESTAMP 列改为 DATETIME(修复类型不匹配) - 用户管理: 新增创建时间/修改时间列,状态改用 Switch - 角色管理/用户管理: 操作按钮改为图标 - PC 设备详情: 基本信息补全 RSSI/ICCID/电源/地址 - PC 卡片: 通道统计改用 Lucide 图标,颜色统一 - PC 二维码: canvas 渲染,含编号文字,支持右键下载 - H5: 按 uni-app 规范修正导航(navigateTo 替代 reLaunch) - H5: 详情页加返回导航条 - H5: 扫码支持摄像头(jsQR)+ ?id= 参数 - H5: 底部 tabBar 在所有页面常显 - H5: 首页统计改为 6 项(设备/通道/空闲/充电/充满/故障) - H5: 下拉刷新 / 上拉加载 - 产品首页: 添加业务联系 - 文档: 清理过时文件,补充缺失规范章节
4.5 KiB
4.5 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Prefer Animating Transform and Opacity for Performance | MEDIUM | Animating layout-triggering properties like height or margin causes expensive reflows and janky animations | best-practice |
|
Prefer Animating Transform and Opacity for Performance
Impact: MEDIUM - When creating Vue transitions, you should prefer animating transform and opacity properties. These are GPU-accelerated and do not trigger expensive CSS layout recalculations. Animating properties like height, width, margin, padding, or top/left causes the browser to recalculate layout on every frame, resulting in janky, low-performance animations.
Task Checklist
- Use
transformfor position and size animations (translate, scale, rotate) - Use
opacityfor fade effects - Avoid animating
height,width,margin,padding,top,left,right,bottom - If you must animate height, consider using
max-heightwith a generous value or JavaScript-based solutions - Use
will-changesparingly and only when needed
Problematic Code:
/* BAD: Animating height triggers layout recalculation every frame */
.slide-enter-active,
.slide-leave-active {
transition: height 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
height: 0;
}
.slide-enter-to,
.slide-leave-from {
height: 200px;
}
/* BAD: Animating margin causes layout thrashing */
.slide-enter-active,
.slide-leave-active {
transition: margin-top 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
margin-top: -100%;
}
Correct Code:
/* GOOD: Using transform and opacity - GPU accelerated */
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
/* GOOD: Using transform for slide animations */
.slide-enter-active,
.slide-leave-active {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.slide-enter-from {
transform: translateX(-100%);
opacity: 0;
}
.slide-leave-to {
transform: translateX(100%);
opacity: 0;
}
/* GOOD: Using scale instead of width/height */
.scale-enter-active,
.scale-leave-active {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.scale-enter-from,
.scale-leave-to {
transform: scale(0);
opacity: 0;
}
When You Must Animate Height
If you absolutely need to animate height (e.g., accordion), consider these alternatives:
<template>
<!-- Option 1: max-height trick (simple but not precise) -->
<Transition name="expand">
<div v-if="expanded" class="content">
<slot />
</div>
</Transition>
</template>
<style>
.expand-enter-active,
.expand-leave-active {
transition: max-height 0.3s ease, opacity 0.3s ease;
overflow: hidden;
}
.expand-enter-from,
.expand-leave-to {
max-height: 0;
opacity: 0;
}
.expand-enter-to,
.expand-leave-from {
max-height: 500px; /* Set to expected max content height */
opacity: 1;
}
</style>
<script setup>
// Option 2: JavaScript hooks for precise height animation
function onEnter(el, done) {
el.style.height = '0'
el.style.overflow = 'hidden'
// Force reflow
el.offsetHeight
el.style.transition = 'height 0.3s ease'
el.style.height = el.scrollHeight + 'px'
el.addEventListener('transitionend', () => {
el.style.height = ''
el.style.overflow = ''
done()
}, { once: true })
}
function onLeave(el, done) {
el.style.height = el.scrollHeight + 'px'
el.style.overflow = 'hidden'
el.offsetHeight
el.style.transition = 'height 0.3s ease'
el.style.height = '0'
el.addEventListener('transitionend', done, { once: true })
}
</script>
<template>
<Transition @enter="onEnter" @leave="onLeave">
<div v-if="expanded">
<slot />
</div>
</Transition>
</template>
Performance Comparison
| Property | Layout | Paint | Composite | Performance |
|---|---|---|---|---|
transform |
No | No | Yes | Excellent |
opacity |
No | No | Yes | Excellent |
background-color |
No | Yes | Yes | Good |
width/height |
Yes | Yes | Yes | Poor |
margin/padding |
Yes | Yes | Yes | Poor |
top/left |
Yes | Yes | Yes | Poor |
Reference
- Vue.js Transition Documentation
- CSS Triggers - Reference for which properties trigger layout/paint
- High Performance Animations