2026-03-10 17:13:50 +08:00
|
|
|
|
<template>
|
2026-03-11 14:38:29 +08:00
|
|
|
|
<!-- <div class="page">
|
2026-03-10 17:13:50 +08:00
|
|
|
|
<div class="controls">
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<button class="btn" @click="generate(2000)">生成 2000 项</button>
|
|
|
|
|
|
<button class="btn" @click="generate(5000)">生成 5000 项</button>
|
|
|
|
|
|
<button class="btn" @click="clearList">清空</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<text class="stat">FPS: {{fpsDisplay}}</text>
|
|
|
|
|
|
<text class="stat">平均帧(ms): {{avgFrameMsDisplay}}</text>
|
|
|
|
|
|
<text class="stat">items: {{items.length}}</text>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="hint">说明:向下快速滚动列表以测试渲染/滚动性能;nvue 将使用原生渲染。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<scroll-view class="list" :scroll-y="true" show-scrollbar="true" @scroll="onScroll">
|
|
|
|
|
|
<div class="item" v-for="item in items" :key="item.id">
|
|
|
|
|
|
<div class="thumb" :style="{backgroundColor: item.color}"></div>
|
|
|
|
|
|
<div class="meta">
|
|
|
|
|
|
<text class="title">Item #{{item.id}}</text>
|
|
|
|
|
|
<text class="desc">这是第 {{item.id}} 个条目,用于增加每个 DOM 的复杂度以测试渲染成本。多行文本强制布局多次换行,模拟真实列表。</text>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</scroll-view>
|
2026-03-11 14:38:29 +08:00
|
|
|
|
</div> -->
|
2026-03-10 17:13:50 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2026-03-11 14:38:29 +08:00
|
|
|
|
// export default {
|
|
|
|
|
|
// data() {
|
|
|
|
|
|
// return {
|
|
|
|
|
|
// items: [],
|
|
|
|
|
|
// // FPS 测量
|
|
|
|
|
|
// measuring: false,
|
|
|
|
|
|
// fpsDisplay: 0,
|
|
|
|
|
|
// avgFrameMsDisplay: 0,
|
|
|
|
|
|
|
|
|
|
|
|
// // 内部用
|
|
|
|
|
|
// _frames: [],
|
|
|
|
|
|
// _rafId: null,
|
|
|
|
|
|
// _idleTO: null
|
|
|
|
|
|
// }
|
|
|
|
|
|
// },
|
|
|
|
|
|
// methods: {
|
|
|
|
|
|
// generate(n) {
|
|
|
|
|
|
// // 生成带颜色的占位项(避免网络请求)
|
|
|
|
|
|
// const list = []
|
|
|
|
|
|
// for (let i = 0; i < n; i++) {
|
|
|
|
|
|
// list.push({
|
|
|
|
|
|
// id: i + 1,
|
|
|
|
|
|
// color: this._randColor()
|
|
|
|
|
|
// })
|
|
|
|
|
|
// }
|
|
|
|
|
|
// this.items = list
|
|
|
|
|
|
// // 清除测量结果
|
|
|
|
|
|
// this.fpsDisplay = 0
|
|
|
|
|
|
// this.avgFrameMsDisplay = 0
|
|
|
|
|
|
// },
|
|
|
|
|
|
// clearList() {
|
|
|
|
|
|
// this.items = []
|
|
|
|
|
|
// this.fpsDisplay = 0
|
|
|
|
|
|
// this.avgFrameMsDisplay = 0
|
|
|
|
|
|
// },
|
|
|
|
|
|
// _randColor() {
|
|
|
|
|
|
// const h = Math.floor(Math.random() * 360)
|
|
|
|
|
|
// const s = 60 + Math.floor(Math.random() * 20)
|
|
|
|
|
|
// const l = 55 + Math.floor(Math.random() * 10)
|
|
|
|
|
|
// return `hsl(${h} ${s}% ${l}%)`
|
|
|
|
|
|
// },
|
|
|
|
|
|
|
|
|
|
|
|
// // 滚动回调(来自原生 nvue scroll-view)
|
|
|
|
|
|
// onScroll(e) {
|
|
|
|
|
|
// // 每次 scroll 事件触发时重置空闲计时器
|
|
|
|
|
|
// // 开始/继续测量 FPS
|
|
|
|
|
|
// if (!this.measuring) this._startMeasure()
|
|
|
|
|
|
// clearTimeout(this._idleTO)
|
|
|
|
|
|
// this._idleTO = setTimeout(() => {
|
|
|
|
|
|
// this._stopMeasure()
|
|
|
|
|
|
// }, 300)
|
|
|
|
|
|
// },
|
|
|
|
|
|
|
|
|
|
|
|
// _startMeasure() {
|
|
|
|
|
|
// this.measuring = true
|
|
|
|
|
|
// this._frames = []
|
|
|
|
|
|
// const pushFrame = (t) => {
|
|
|
|
|
|
// this._frames.push(t)
|
|
|
|
|
|
// // 保持最近 120 帧
|
|
|
|
|
|
// if (this._frames.length > 120) this._frames.shift()
|
|
|
|
|
|
// this._rafId = requestAnimationFrame(pushFrame)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// this._rafId = requestAnimationFrame(pushFrame)
|
|
|
|
|
|
// },
|
|
|
|
|
|
|
|
|
|
|
|
// _stopMeasure() {
|
|
|
|
|
|
// this.measuring = false
|
|
|
|
|
|
// if (this._rafId) {
|
|
|
|
|
|
// cancelAnimationFrame(this._rafId)
|
|
|
|
|
|
// this._rafId = null
|
|
|
|
|
|
// }
|
|
|
|
|
|
// // 计算 FPS 与平均帧时长
|
|
|
|
|
|
// if (this._frames.length < 2) {
|
|
|
|
|
|
// this.fpsDisplay = 0
|
|
|
|
|
|
// this.avgFrameMsDisplay = 0
|
|
|
|
|
|
// return
|
|
|
|
|
|
// }
|
|
|
|
|
|
// const intervals = []
|
|
|
|
|
|
// for (let i = 1; i < this._frames.length; i++) {
|
|
|
|
|
|
// intervals.push(this._frames[i] - this._frames[i - 1])
|
|
|
|
|
|
// }
|
|
|
|
|
|
// const sum = intervals.reduce((a, b) => a + b, 0)
|
|
|
|
|
|
// const avg = sum / intervals.length
|
|
|
|
|
|
// const fps = 1000 / avg
|
|
|
|
|
|
// this.avgFrameMsDisplay = avg.toFixed(2)
|
|
|
|
|
|
// this.fpsDisplay = Math.round(fps)
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
2026-03-10 17:13:50 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
2026-03-11 14:38:29 +08:00
|
|
|
|
/* .page {
|
2026-03-10 17:13:50 +08:00
|
|
|
|
flex: 1;
|
|
|
|
|
|
background-color: #f5f6fa;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.controls {
|
|
|
|
|
|
padding: 20px;
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.row {
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.btn {
|
|
|
|
|
|
padding: 10px 14px;
|
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
|
background: #2d8cf0;
|
|
|
|
|
|
color: #fff;
|
|
|
|
|
|
margin-right: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.stat {
|
|
|
|
|
|
margin-right: 14px;
|
|
|
|
|
|
font-size: 28px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.hint {
|
|
|
|
|
|
color: #888;
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.list {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.item {
|
|
|
|
|
|
height: 160px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
|
|
width: 120px;
|
|
|
|
|
|
height: 120px;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
margin-right: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.meta {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.title {
|
|
|
|
|
|
font-size: 30px;
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
margin-bottom: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.desc {
|
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
|
color: #666;
|
|
|
|
|
|
line-height: 32px;
|
|
|
|
|
|
}
|
|
|
|
|
|
page,
|
|
|
|
|
|
body,
|
|
|
|
|
|
.page {
|
|
|
|
|
|
height: 100%;
|
2026-03-11 14:38:29 +08:00
|
|
|
|
} */
|
2026-03-10 17:13:50 +08:00
|
|
|
|
</style>
|