問題現象
頁面一次加載了100條數據,頁面滑動出現卡頓。
問題代碼
|
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
<template>
<div class=
"container"
>
<div class=
"nav"
>
<text class=
"nav-item"
>list</text>
</div>
<!-- List -->
<list class=
"list"
onclick=
"listClick"
onlongpress=
"listLongPress"
onscrollbottom=
"scrollbottom"
id=
"list"
scrollpage=
"{{scrollPage}}"
>
<list-item type=
"listItem"
class=
"item"
onclick=
"listItemClick"
if
=
"{{listData.length>0}}"
>
<div
for
=
"{{listData}}"
style=
"flex-direction:column;"
>
<text class=
"txt"
>{{$item}}--{{$idx}}</text>
</div>
</list-item>
<!-- Loading More -->
<list-item type=
"loadMore"
class=
"load-more"
if
=
"{{loadMore}}"
>
<progress type=
"circular"
></progress>
<text>More</text>
</list-item>
</list>
</div>
</template>
<style>
.container{
flex-direction: column;
}
.list {
padding-left: 10px;
padding-right: 10px;
columns: 1;
flex-direction: column;
border-color:
#FF0000;
border-width: 5px;
}
.item {
flex-direction: column;
align-items: flex-start;
margin-bottom: 15px;
border-color:
#9400D3;
border-width: 5px;
margin-right: 20px;
#f76160;
}
.load-more {
justify-content: center;
align-items: center;
height: 100px;
border-color:
#bbbbbb;
border-bottom-width: 1px;
}
.btn-little {
flex: 1;
height: 80px;
margin-left: 15px;
border-radius: 5px;
color:
#ffffff;
font-size: 30px;
text-align: center;
#0faeff;
}
.nav {
padding-left: 60px;
padding-right: 60px;
padding-bottom: 30px;
}
.nav-item {
flex: 1;
padding-bottom: 30px;
border-bottom-width: 5px;
border-color:
#fbf9fe;
font-size: 35px;
color:
#666666;
text-align: center;
}
</style>
<script>
import prompt from
'@system.prompt'
export
default
{
data: {
componentName:
'list'
,
loadMore:
true
,
listAdd: [
'A'
,
'B'
,
'C'
,
'D'
,
'E'
,
'F'
,
'G'
,
'H'
,
'I'
,
'J'
,
'K'
,
'L'
,
'M'
,
'N'
,
'O'
,
'P'
,
'Q'
,
'R'
,
'S'
,
'T'
,
'U'
,
'V'
,
'W'
,
'X'
,
'Y'
,
'Z'
],
listData: [],
scrollPage:
false
,
},
onInit:
function
() {
this
.$page.setTitleBar({ text:
'list'
})
for
(
var
index = 0;index < 100;index++){
this
.listData[index] =
'A'
;
}
},
scrollbottom:
function
() {
prompt.showToast({
message:
'The list slides to the bottom and starts loading other data.'
})
// Load next page
var
that =
this
var
renderData = [].concat(that.listData, that.listAdd)
setTimeout(
function
() {
that.listData = renderData
}, 1000)
},
// monitoring during sliding
scroll:
function
(e) {
let msg =
'scroll'
+
'.scrollX:'
+ e.scrollX
+
' .scrollY:'
+ e.scrollY
+
' .scrollState:'
+ e.scrollState
console.info(msg)
},
listItemClick:
function
(e) {
e.stopPropagation()
console.info(
'List Item is clicked.'
)
prompt.showToast({
message:
'List Item is clicked.'
})
},
listClick:
function
(e) {
e.stopPropagation()
console.info(
'List is clicked.'
)
prompt.showToast({
message:
'List is clicked.'
})
},
listLongPress:
function
(e) {
e.stopPropagation()
console.info(
'List is long pressed.'
)
prompt.showToast({
message:
'List is long pressed.'
})
},
}
</script>
|
問題分析
以上代碼使用list、list-item來加載大規模數據,但是使用方法不當,導致list-item的視圖view沒有被復用。
我們知道快應用的引擎是一個android apk,list、list-item的實現最終都是通過android的ListView、BaseAdapter等這些實現的,了解這些其實知道列表界面上超過屏幕顯示的區域是不會重新創建視圖的,而是復用第一次在界面上可見區域的那些view的,只需要把數據刷新一下即可。每一行的視圖view其實就是list-item。
以上代碼雖然看起來是列表,但是只有1個list-item,開發者在list-item內部使用了for循環,每循環一次,都會創建一個新的view,當數據量很大時,內存占用越多,手機內存吃緊,不斷地做申請、釋放內存的操作,應用性能受到嚴重影響,導致滑動卡頓。
解決方法
基於list組件的特點,在list-item內部內部需謹慎使用if指令或for指令,根據列表每行數據特點,在list-item上設置不同的type,盡可能復用list-item,在list-item上使用for語句。修改后代碼如下(注意list-item部分):
|
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
|
<template>
<div class=
"container"
>
<div class=
"nav"
>
<text class=
"nav-item"
>list</text>
</div>
<!-- List -->
<list class=
"list"
onclick=
"listClick"
onlongpress=
"listLongPress"
onscrollbottom=
"scrollbottom"
id=
"list"
scrollpage=
"{{scrollPage}}"
>
<list-item type=
"listItem"
class=
"item item-color"
onclick=
"listItemClick"
for
=
"{{listData}}"
>
<text class=
"txt"
>{{$item}}--{{$idx}}</text>
</list-item>
<!-- <list-item type=
"listItem"
class=
"item"
onclick=
"listItemClick"
if
=
"{{listData.length>0}}"
>
<div
for
=
"{{listData}}"
style=
"flex-direction:column;"
>
<text class=
"txt"
>{{$item}}--{{$idx}}</text>
</div>
</list-item> -->
<!-- Loading More -->
<list-item type=
"loadMore"
class=
"load-more"
if
=
"{{loadMore}}"
>
<progress type=
"circular"
></progress>
<text>More</text>
</list-item>
</list>
</div>
</template>
|
代碼運行效果圖對比:
|
|
|
| 圖1 修改后效果 |
圖2 修改前效果 |
從上面效果圖中我們看到,雖然都是列表數據,但是圖1每一行都是一個list-item(list-item的css中背景色設置的是紅色),而且type值都一樣,能很好地復用list-item,但是圖2中只有1個list-item,里面列表數據都是作為list-item的子節點。圖2的效果和使用普通的div加載大量列表數據是一樣的,根源在於開發者沒有很好地理解list、list-item的原理。
欲了解更多詳情,請參見:
快應用list開發指導:
https://developer.huawei.com/consumer/cn/doc/development/quickApp-References/quickapp-component-list#h1-1592485335262
原文鏈接:https://developer.huawei.com/...
原作者:Mayism


