相關組件版本:avalon 1.3.六、masonry 3.1.5php
最近,在公司的項目中,要開發一個使用瀑布流的前臺,衡量了各類解決方案後,仍是以爲masonry最成熟,因此就選用了它。而在以前開發後臺的過程當中,對avalon也用得挺熟手的了,因此此次作前臺也用上。因爲avalon是管dom的,masonry也是管dom的,因此實現兼容的重點就是,讓它們管同一份dom,而不是各管各的。css
個人avalon相關代碼是這樣的:jquery
avalon.define({ $id: 'masonry', article_list: <?php echo $articleList; ?>, });
其中的article_list即是存放瀑布流數據的數組,用php生成json格式的字符串輸出,賦給article_list做爲初值(初版數據)。而後,調用avalon的ms-repeat指令來循環渲染瀑布流的dom:ajax
<!-- 瀑布流位置 --> <div id="masonry_container" ms-controller="masonry"> <div id="masonry_content"> <div class="portfolio" ms-repeat-article="article_list"> <div class="portfolio-wrapper" ms-click="open_article_modal(article.id)"> <a> <img ms-attr-src="article.cover_img_url" ms-css-height="article.cover_img_height"> </a> <div class="article_follow side_btn"></div> <div class="article_collect side_btn"></div> <div class="article_body"> <div class="article_meta"> <h2>{{article.title}}</h2> <p></p> </div> </div> </div> </div> </div> </div>
在avalon.scan()之後,實例化masonry,初版數據就算是出來了,一切都很正常。json
可是在後面繼續加載數據的時候,就出問題了。個人設計是,判斷當滾動條拉到最下,就觸發事件用ajax讀取第2、3、四……版的數據。數組
一開始我想得很簡單:不就是把ajax獲取到的數據直接添加到avalon的vm裏,讓它自動完成新數據的渲染就行了,而後再從新實例化masonry。這種方案的問題是,因爲「從新實例化masonry」須要的是先把masonry對象destroy()掉,因此就會看到很明顯的閃爍,並且,能夠預想到,當數據愈來愈多的時候,從新實例化的代價就會愈來愈大,所以這種方案是不可取的。app
接着我仔細閱讀了masonry的文檔,發現其原來是有addItems/appended這樣的方法可供調用的,我讀了文檔上的示例代碼(一個小插曲,因爲本人的原生js實在是太不濟,就想着用jquery版的,卻發現不管如何都調不通,大概是由於用了requireJS來模塊化的緣故吧,這裏暫且不提),發現這個方法的原理就是先往dom樹裏添好新的dom節點,而後再將新的dom節點做爲參數傳入addItems/appended。這就使我犯難了,個人dom樹是交給avalon來處理的,又不是本身拼的,哪來dom節點能夠傳給masonry呀?爲了作出一份能夠傳給masonry的dom節點,我也是拼了,用jquery來生成一份dom節點再傳給masonry,但是試了一下,無效呀,masonry根本就沒有控制新增dom節點的位置。dom
這時候我在嘀咕,會不會是avalon還未生成dom節點,masonry就開始「控制」的緣故呢?爲了測試這個可能性,我使用了avalon中的data-repeat-rendered指令,這個指令能夠指定一個函數,在ms-repeat渲染完後再執行,這樣就能夠保證avalon已經生成好dom節點後masonry再介入。測試的結果很使人沮喪,masonry依然沒有控制dom節點的位置,因此應該不是這個問題。ide
最終,在個人測試下,正確的作法是:把avalon生成的dom節點傳給masonry,怎麼實現呢?提及來也很簡單,記錄下拉取新數據前瀑布流已有多少個文塊,也記錄下拉取到多少個文塊,這樣就能夠獲得新增文塊索引的範圍是從幾到幾了;當avalon渲染完ms-repeat後,用jquery獲取瀑布流全部文塊的dom樹,再根據算出來的新增文塊索引範圍,將新增的dom節點取出來後,傳給masonry,就大功告成了!模塊化