問題
公司接入weex
大概也有半年多的時(shí)間了超埋,sdk
的版本是0.6.4
卦溢,自定義的組件一大堆。不過image
這個(gè)組件一直沒有自定義泵殴。
我們的應(yīng)用有一個(gè)“發(fā)現(xiàn)”頁面涮帘,全部是圖片,用weex
寫的笑诅。交互抱怨圖片加載后调缨,亂顯示的,體驗(yàn)很不好吆你,希望一張一張有順序地顯示弦叶。
weex
提供的image
組件,圖片下載要自己實(shí)現(xiàn)妇多,demo
程序是用SDWebImage
做的伤哺,所以這邊也是依樣畫葫蘆。SDWebImage
是用NSOperationQueue
實(shí)現(xiàn)者祖,默認(rèn)并發(fā)數(shù)為3
立莉,是并行加載的,要求圖片順序顯示七问,怎么可能桃序?
所以,這個(gè)問題從去年底就提出來了烂瘫,一直沒人去管,并且還記下來一個(gè)坑:
目前圖片加載順序, 異步隨機(jī)
方案1:Native
層自定義組件
-
weex SDK
中<image>
組件對(duì)應(yīng)的Native
類是WXImageComponent
- 關(guān)于圖片下載的過程,用了一個(gè)全局的串行隊(duì)列坟比,套了好幾層主線程做下載任務(wù)分發(fā)芦鳍。真正的下載過程,通過協(xié)議
WXImageOperationProtocol
讓使用者來實(shí)現(xiàn)葛账。 - 一般實(shí)現(xiàn)都是通過
SDWebImage
這個(gè)第三方庫(kù)來做的柠衅,下載圖片是并行的,并發(fā)數(shù)默認(rèn)是3 - 估計(jì)是將
SDWebImage
這種第三方庫(kù)引入weex
框架籍琳,會(huì)導(dǎo)致框架本身太龐大菲宴,不合適。所以采用了協(xié)議加demo
程序這種方式趋急。 - 圖片下載過程采用并行方式是合理的喝峦,不然,串行下載呜达,性能太差谣蠢。
- 不過,這里需求是圖片順序顯示查近,那么進(jìn)行串行下載是最方便的眉踱。既然采用
SDWebImage
這個(gè)第三方庫(kù),只要將它的最大并發(fā)數(shù)設(shè)置為1霜威,編程串行隊(duì)列下載谈喳,就可以了。戈泼、 - 默認(rèn)的
image
組件不變婿禽,可以參照寫法,稍微改一下矮冬,新建一個(gè)串行的圖片組件谈宛,比如seiral-image
就可以了。自定義組件就可以直接用SDWebImage
來實(shí)現(xiàn)胎署,不需要WXImageOperationProtocol
來過渡吆录。為了不影響默認(rèn)的image
組件,下載過程不要用SDWebImage
共享單例琼牧,而是新建一個(gè)實(shí)例變量來做恢筝,這樣就互不影響。
方案2:通過opacity
屬性巨坊,串行顯示圖片
-
native
層組件保持不變撬槽,在JavaScript
層來控制 -
if
指令不合適,這個(gè)隱藏和native
的隱藏含義不一樣趾撵,是整個(gè)結(jié)點(diǎn)都不創(chuàng)建侄柔,在這里不適用 - 加載過程保持串行不變共啃。加載完成后,
native
會(huì)發(fā)送load
事件到JavaScript
層暂题。 - 默認(rèn)將圖片的
opacity
設(shè)置為0移剪,就算加載完成了,也看不到圖片薪者。在收到load
事件后纵苛,將圖片的opacity
設(shè)置為1,顯示圖片言津。這時(shí)可以加入一些自定義的邏輯攻人,比如順序顯示等。 - 下面是一個(gè)簡(jiǎn)單的例子:
<template>
<list>
<cell class="cell">
<image class="image" repeat="item in imageList" src="{{item.filePath}}" style="opacity:{{opacitys[$index]}}" onload="imageLoad($index)">
</image>
</cell>
</list>
</template>
<style>
.cell {
height: 212px;
flex-direction: row;
justify-content: space-between;
align-items: stretch;
padding-top: 30px;
padding-left: 24px;
padding-right: 24px;
}
.image {
width: 223px;
}
</style>
<script >
module.exports = {
data: {
imageList: [],
loadFlags:[],
opacitys:[]
},
created: function(){
this.onrefresh();
},
methods: {
onrefresh: function(){
this.displayRefreshing = 'show';
this.refreshing = true;
let stream = require("@weex-module/stream");
var modal = require('@weex-module/modal');
let self = this;
stream.fetch({
url: "/app/image",
indicator: "silent",
}, function(ret) {
self.refreshing = false;
self.displayRefreshing = 'hide';
self.imageList = ret.imageList;
// 只是添加新的元素悬槽,舊的元素不更改怀吻。函數(shù)onrefresh()可能被反復(fù)調(diào)用,只要第一次將opacity由0變1陷谱,不反復(fù)更改
var startIndex = self.loadFlags.length;
for (var i = startIndex; i < ret.imageList.length; i++) {
self.loadFlags[i] = false;
self.opacitys.$set(i, 0);
}
// 設(shè)定超時(shí)保護(hù)(30秒)烙博,圖片全部顯示
setTimeout(function() {
self.dispalyAllImages()
}, 30000);
}, function(err){
self.refreshing = false;
self.displayRefreshing = 'hide';
modal.toast({'message': '網(wǎng)絡(luò)不給力,請(qǐng)稍后再試烟逊!', 'duration': 2});
}
);
},
imageLoad: function(index) {
this.loadFlags[index] = true;
this.updateImageOpacity();
},
updateImageOpacity: function() {
// 圖片順序展示
for (var i = 0; i < this.commonLoadFlags.length; i++) {
// 還沒加載渣窜,就不顯示; 要求順序,后面的就不管了
if (false == this.commonLoadFlags[i]) {
break;
}
// 如果已經(jīng)顯示宪躯,就沒必要重復(fù)設(shè)置
if (this.opacitys[i] > 0) {
continue;
}
this.opacitys.$set(i, 1);
}
},
// 超時(shí)函數(shù)乔宿;加載狀態(tài)不更新;但是顯示狀態(tài)全部設(shè)置為顯示
dispalyAllImages: function() {
for (var i = 0; i < this.opacitys.length; i++) {
// 如果已經(jīng)顯示访雪,就沒必要重復(fù)設(shè)置
if (this.opacitys[i] > 0) {
continue;
}
this.opacitys.$set(i, 1);
}
}
}
}
</script>
imageList: []
, 存放圖片的信息详瑞,比如url
就是其中的filePath
屬性
-
loadFlags:[]
, 存放加載狀態(tài)信息,false
- 圖片還沒加載臣缀;true
-圖片已經(jīng)加載 -
opacitys:[]
坝橡,存放圖片的opacity
值,0-圖片隱藏精置;1-圖片顯示 - imageLoad(index)為
load
事件響應(yīng)函數(shù)计寇,native
層觸發(fā),將圖片的序號(hào)傳給JavaScript
層 -
stream.fetch()
脂倦,native
層實(shí)現(xiàn)番宁,JavaScript
層調(diào)用的網(wǎng)絡(luò)取數(shù)據(jù)函數(shù) -
array.$set(index, value)
,是weex
框架提供數(shù)組設(shè)置函數(shù)赖阻,將index
的值替換為value
蝶押。$set
是函數(shù)名。用這個(gè)函數(shù)火欧,可以結(jié)合weex
框架內(nèi)部的數(shù)據(jù)綁定機(jī)制棋电,可以觸發(fā)界面元素的重新渲染茎截。 - 在這里,初始化時(shí)
self.opacitys.$set(i, 0);
离陶,weex
框架將圖片渲染為不可見稼虎。當(dāng)后來self.opacitys.$set(i, 1);``weex
框架將圖片渲染為可見。如果直接設(shè)置self.opacitys[i] = 0或者1招刨,相應(yīng)的數(shù)值值會(huì)改變,但是界面元素不會(huì)渲染哀军,也就沒有圖片從一開始的不可見到可見的過程沉眶。 -
setTimeout
函數(shù)先套一個(gè)匿名函數(shù),然后用另一個(gè)變量杉适,比如self
來代替this
谎倔,這樣調(diào)用才有效果。記住這種用法猿推。