一直以來,習慣了jquery的DOM操作方式,突然間,開始學習使用vuejs,很多時候,操作DOM觀念總是轉換不過來,雖然也能實現各種效果,但是總有點不倫不類的。
就類似於最近在做的瀑布流布局,正常的方式完成,並且上線之后,作為練手,也使用vuejs來走了一趟。
需求:瀑布流布局照片牆
使用了SUI-Mobile結合vuejs。
實現過程:
<div class="waterfalls"> <ul id="waterfalls-left"> </ul> <ul id="waterfalls-right"> </ul> <ul id="items"> </ul> </div>
前兩個ul作為實際布局需要存在的,就是瀑布流的左邊和右邊兩部分,而第三個id為items的ul,實際上是作為中轉出現的。

<ul id="items">
<li v-for="photo in photos">
<router-link :to="'detail/'+photo.id">
<img :src="photo.src" alt="">
<span v-show="photo.isDel" @click.stop.prevent="noLink">{{photo.delDesc}}</span>
</router-link>
<div class="desc-info">
<p>編號:<span>{{photo.numbering}}</span></p>
</div>
<div class="card-footer no-border">
<a href="#" :class="['link custom-link']" @click.prevent.stop="praise">{{photo.praise || 0}}</a>
<span></span>
<a href="#" class="link custom-link">編輯</a>
<span></span>
<a href="#" class="link custom-link">刪除</a>
</div>
</li>
</ul>
在ul#items里面循環產生所有需要加載的li,原因在於:完全依據數據,是沒辦法哪條數據最終生成的li的高度是多少,從而無法判斷這條數據是應該添加在左邊還是右邊的。
下面就是將ul#items里面生成的li逐個的搬到ul#waterfalls-left或者ul#waterfalls-right里面。
$("#items").children("li").each(function (index, val) {
// 相關搬遷的代碼
});
如果直接這么寫的話,會發現沒有數據,但是當你打印數據的時候,又確實是存在相關數據,通過開發者工具也完全能夠查到相關DOM結構的,關鍵問題在於選取$("#items")時,vuejs還沒有完全生成相關結構,所以最簡單的解決方案是加延時setTimeout();
setTimeout(function () {
$("#items").children("li").each(function (index, val) {
// 相關搬遷的代碼
})
}, 0);
並不需要具體的延時時間。
相關搬遷代碼,有一個關鍵點是,如果ul#waterfalls-left的height小於等於ul#waterfalls-right的height的話,就往ul#waterfalls-left追加,否則追加到ul#waterfalls-right。計算其實際高度的時候,li高度必須完全被撐起來,而li的實際高度是有img的高度決定的。那么很自然的會想到,高度計算必須是在img.onload之后計算的。
var $this = $(this);
var $img = $this.find("img").first();
$img.on("load", function () {
addItems();
});
function addItems() {
if(_this.leftHeight <= _this.rightHeight){
$l.append($this);
_this.leftHeight = $l.height();
}else{
$r.append($this);
_this.rightHeight = $r.height();
}
}
到這里,基本上已經實現了所需要的瀑布流效果,但是經過測試之后,發現存在另一個問題,就是當第一次加載完成之后,直接刷新頁面的話,數據會完全丟失。是因為數據已經存在,所以走不到img.onload里面去了(不知道為什么),解決方案是判斷img.complete。同時,保險起見,添加如果圖片加載失敗的替代圖片。
修改之后的代碼為:
var _this = this,
$l = $("#waterfalls-left"),
$r = $("#waterfalls-right");
setTimeout(function () {
$("#items").children("li").each(function (index, val) {
var $this = $(this);
var $img = $this.find("img").first();
$img.on("error", function () {
$img.attr("src", "../src/assets/images/default.png");
});
if ($img.get(0).complete) {
addItems();
} else {
$img.on("load", function () {
addItems();
});
}
function addItems() {
if(_this.leftHeight <= _this.rightHeight){
$l.append($this);
_this.leftHeight = $l.height();
}else{
$r.append($this);
_this.rightHeight = $r.height();
}
}
});
}, 0);
