uni-app性能优化实战:从加载到渲染的全方位提升 0 次阅读

性能优化是提升用户体验的关键因素,本文将从多个维度详细介绍uni-app应用的性能优化策略,帮助你构建流畅的跨端应用。

1. 首屏加载优化

1.1 分包加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// pages.json
{
"pages": [{
"path": "pages/index/index",
"style": { ... }
}],
"subPackages": [{
"root": "pagesA",
"pages": [{
"path": "list/index",
"style": { ... }
}]
}]
}

1.2 预加载策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 预加载分包
uni.preloadSubPackage({
name: 'pagesA',
success: () => {
console.log('分包预加载成功')
},
fail: () => {
console.log('分包预加载失败')
}
})

// 预加载页面
onLoad() {
// 在首页预加载其他页面
uni.preloadPage({
url: '/pagesA/list/index'
})
}

1.3 骨架屏实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!-- components/skeleton.vue -->
<template>
<view class="skeleton" v-if="loading">
<view class="skeleton-header"></view>
<view class="skeleton-content">
<view class="skeleton-item" v-for="i in 5" :key="i"></view>
</view>
</view>
</template>

<style>
.skeleton {
padding: 20rpx;
}
.skeleton-header {
height: 40rpx;
background: #f0f0f0;
margin-bottom: 20rpx;
animation: skeleton-loading 1s infinite;
}
.skeleton-item {
height: 100rpx;
background: #f0f0f0;
margin-bottom: 20rpx;
animation: skeleton-loading 1s infinite;
}
@keyframes skeleton-loading {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
</style>

2. 渲染性能优化

2.1 长列表优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<!-- 虚拟列表实现 -->
<template>
<view class="list-container">
<view
class="list-phantom"
:style="{ height: listHeight + 'px' }"
></view>
<view
class="list-content"
:style="{ transform: getTransform }"
>
<view
class="list-item"
v-for="item in visibleData"
:key="item.id"
>
{{ item.content }}
</view>
</view>
</view>
</template>

<script>
export default {
data() {
return {
listData: [], // 完整列表数据
itemHeight: 50, // 每项高度
visibleCount: 10, // 可视区域显示的数量
startIndex: 0, // 起始索引
endIndex: 0 // 结束索引
}
},
computed: {
listHeight() {
return this.listData.length * this.itemHeight
},
visibleData() {
return this.listData.slice(this.startIndex, this.endIndex)
},
getTransform() {
return `translate3d(0, ${this.startIndex * this.itemHeight}px, 0)`
}
},
methods: {
handleScroll(e) {
const scrollTop = e.detail.scrollTop
this.startIndex = Math.floor(scrollTop / this.itemHeight)
this.endIndex = this.startIndex + this.visibleCount
}
}
}
</script>

2.2 避免频繁更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 使用防抖
function debounce(fn, delay) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}

// 使用节流
function throttle(fn, delay) {
let timer = null
let start = Date.now()
return function(...args) {
const current = Date.now()
const remaining = delay - (current - start)
if (timer) clearTimeout(timer)
if (remaining <= 0) {
fn.apply(this, args)
start = Date.now()
} else {
timer = setTimeout(() => {
fn.apply(this, args)
start = Date.now()
}, remaining)
}
}
}

// 在组件中使用
export default {
methods: {
updateData: debounce(function() {
// 更新数据的操作
}, 300)
}
}

3. 内存优化

3.1 及时销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export default {
data() {
return {
timer: null,
observer: null
}
},
beforeDestroy() {
// 清除定时器
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}

// 清除监听器
if (this.observer) {
this.observer.disconnect()
this.observer = null
}
}
}

3.2 避免内存泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 图片预加载
const preloadImages = (urls) => {
const promises = urls.map(url => {
return new Promise((resolve, reject) => {
const image = new Image()
image.onload = () => {
image.onload = null // 清除事件监听
resolve(url)
}
image.onerror = () => {
image.onerror = null // 清除事件监听
reject(url)
}
image.src = url
})
})
return Promise.all(promises)
}

4. 网络优化

4.1 请求合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 请求队列管理
class RequestQueue {
constructor() {
this.queue = new Map()
}

async request(key, promiseCreator) {
if (this.queue.has(key)) {
return this.queue.get(key)
}

const promise = promiseCreator()
this.queue.set(key, promise)

try {
const result = await promise
this.queue.delete(key)
return result
} catch (err) {
this.queue.delete(key)
throw err
}
}
}

// 使用示例
const requestQueue = new RequestQueue()

function fetchData(id) {
return requestQueue.request(`data_${id}`, () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, data: 'some data' })
}, 1000)
})
})
}

4.2 数据缓存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class CacheManager {
constructor(expire = 5 * 60 * 1000) {
this.cache = new Map()
this.expire = expire
}

set(key, value) {
this.cache.set(key, {
value,
timestamp: Date.now()
})
}

get(key) {
const data = this.cache.get(key)
if (!data) return null

if (Date.now() - data.timestamp > this.expire) {
this.cache.delete(key)
return null
}

return data.value
}

clear() {
this.cache.clear()
}
}

// 使用示例
const cache = new CacheManager()

async function getData(key) {
// 先从缓存获取
const cached = cache.get(key)
if (cached) return cached

// 缓存不存在则请求
const data = await fetchData(key)
cache.set(key, data)
return data
}

5. 其他优化技巧

5.1 图片优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 图片懒加载指令
Vue.directive('lazy', {
bind(el, binding) {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = binding.value
observer.unobserve(el)
}
})
})
observer.observe(el)
}
})

// 使用示例
<image v-lazy="imageUrl" />

5.2 组件优化

1
2
3
4
5
6
7
8
9
10
11
12
13
// 使用keep-alive缓存组件
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>

// 异步组件
const AsyncComponent = () => ({
component: import('./heavy-component.vue'),
loading: LoadingComponent,
error: ErrorComponent,
delay: 200,
timeout: 3000
})

6. 性能监控

6.1 页面性能监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const performance = {
// 记录时间点
mark(name) {
if (typeof performance !== 'undefined') {
performance.mark(name)
}
},

// 测量两个时间点之间的时间
measure(name, startMark, endMark) {
if (typeof performance !== 'undefined') {
performance.measure(name, startMark, endMark)
const measures = performance.getEntriesByName(name)
return measures[0].duration
}
return 0
},

// 上报性能数据
report(data) {
// 上报逻辑
console.log('性能数据:', data)
}
}

7. 总结

  1. 合理使用分包加载
  2. 实现虚拟列表
  3. 优化更新机制
  4. 注意内存管理
  5. 做好网络优化
  6. 监控性能指标

如果觉得文章对你有帮助,欢迎点赞、评论、分享,你的支持是我继续创作的动力!

上一篇 uni-app路由与页面跳转:最佳实践与踩坑指南
下一篇 uni-app组件通信完全指南:从基础到进阶
感谢您的支持!
微信赞赏码 微信赞赏
支付宝赞赏码 支付宝赞赏