avalon搭配masonry實現MVVM瀑布流

相關組件版本:avalon 1.3.6、masonry 3.1.5

最近,在公司的項目中,要開發一個使用瀑布流的前臺,衡量了各種解決方案後,還是覺得masonry最成熟,所以就選用了它。而在之前開發後臺的過程中,對avalon也用得挺熟手的了,所以這次做前臺也用上。由於avalon是管dom的,masonry也是管dom的,所以實現兼容的重點就是,讓它們管同一份dom,而不是各管各的。

我的avalon相關代碼是這樣的:

        avalon.define({
          $id: 'masonry',
          article_list: <?php echo $articleList; ?>,
        });

其中的article_list便是存放瀑布流數據的數組,用php生成json格式的字符串輸出,賦給article_list作爲初值(第一版數據)。然後,調用avalon的ms-repeat指令來循環渲染瀑布流的dom:

      <!-- 瀑布流位置 -->
      <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,第一版數據就算是出來了,一切都很正常。

但是在後面繼續加載數據的時候,就出問題了。我的設計是,判斷當滾動條拉到最下,就觸發事件用ajax讀取第二、三、四……版的數據。

一開始我想得很簡單:不就是把ajax獲取到的數據直接添加到avalon的vm裏,讓它自動完成新數據的渲染就好了,然後再重新實例化masonry。這種方案的問題是,由於“重新實例化masonry”需要的是先把masonry對象destroy()掉,所以就會看到很明顯的閃爍,而且,可以預想到,當數據越來越多的時候,重新實例化的代價就會越來越大,因此這種方案是不可取的。

接着我仔細閱讀了masonry的文檔,發現其原來是有addItems/appended這樣的方法可供調用的,我讀了文檔上的示例代碼(一個小插曲,由於本人的原生js實在是太不濟,就想着用jquery版的,卻發現無論如何都調不通,大概是因爲用了requireJS來模塊化的緣故吧,這裏暫且不提),發現這個方法的原理就是先往dom樹裏添好新的dom節點,然後再將新的dom節點作爲參數傳入addItems/appended。這就使我犯難了,我的dom樹是交給avalon來處理的,又不是自己拼的,哪來dom節點可以傳給masonry呀?爲了做出一份可以傳給masonry的dom節點,我也是拼了,用jquery來生成一份dom節點再傳給masonry,可是試了一下,無效呀,masonry根本就沒有控制新增dom節點的位置。

這時候我在嘀咕,會不會是avalon還未生成dom節點,masonry就開始“控制”的緣故呢?爲了測試這個可能性,我使用了avalon中的data-repeat-rendered指令,這個指令可以指定一個函數,在ms-repeat渲染完後再執行,這樣就可以保證avalon已經生成好dom節點後masonry再介入。測試的結果很令人沮喪,masonry依然沒有控制dom節點的位置,所以應該不是這個問題。

最終,在我的測試下,正確的做法是:把avalon生成的dom節點傳給masonry,怎麼實現呢?說起來也很簡單,記錄下拉取新數據前瀑布流已有多少個文塊,也記錄下拉取到多少個文塊,這樣就可以得到新增文塊索引的範圍是從幾到幾了;當avalon渲染完ms-repeat後,用jquery獲取瀑布流所有文塊的dom樹,再根據算出來的新增文塊索引範圍,將新增的dom節點取出來後,傳給masonry,就大功告成了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章