移動端效果之IndexList

寫在前面

接着前面的移動端效果講,此次講解的的是IndexList的實現原理。效果以下:javascript

IndexList

代碼請看這裏:githubcss

移動端效果之swiperhtml

移動端效果之pickervue

移動端效果之cellSwiperjava

1. 核心解析

整體來講的原理就是當點擊或者滑動右邊的索引條時,經過獲取點擊的索引值來使左邊的內容滑動到相應的位置。其中怎樣滑動到具體的位置,看下面分解:git

1.1 基本html代碼

<div class="indexlist">
    <ul class="indexlist-content" id="content">
        <!-- 須要生成的內容 -->
    </ul>
    <div class="indexlist-nav" id="nav">
        <ul class="indexlist-navlist" id="navList">
            <-- 須要生成的索引條 -->
        </ul>
    </div>
    <div class="indexlist-indicator" style="display: none;" id="indicator"></div>
</div>

1.2 DOM初始化

因爲餓了麼組件庫中的indexList是採用vue組件生成DOM,我這裏大體使用javascript來模擬生成DOMgithub

// 內容填充
function initialDOM() {
    // D.data 獲取內容數據
    var data = D.data;
    var contentHtml = '';
    var navHtml = '';
    // 初始化內容和NAV
    data.forEach(function(d) {
        var index = d.index;
        var items = d.items;
        navHtml += '<li class="indexlist-navitem">'+ index +'</li>';
        contentHtml += '<li class="indexsection" data-index="'+ index +'"><p class="indexsection-index">'+ index +'</p><ul>';
        items.forEach(function(item) {
            contentHtml += '<a class="cell"><div class="cell-wrapper"><div class="cell-title"><span class="cell-text">'+ item +'</span></div></div></a>';
        });
        contentHtml += '</ul></li>';
    });

    content.innerHTML = contentHtml;
    navList.innerHTML = navHtml;
}

// 樣式初始化
if (!currentHeight) {
    currentHeight = document.documentElement.clientHeight -content.getBoundingClientRect().top;
}
// 右邊索引欄的寬度
navWidth = nav.clientWidth;
// 左邊內容的初始化高度和右邊距
// 高度爲當前頁面的高度與內容top的差值
content.style.marginRight = navWidth + 'px';
content.style.height = currentHeight + 'px';

1.3 綁定滑動事件

在右邊的索引欄上加上滑動事件,當點擊或者滑動的時候觸發。在源代碼中在touchstart事件的結尾處,在window上綁定了touchmovetouchend事件,是爲了使得滑動得區域更大,只有在開始的時候在索引欄上觸發了touchstart事件時,以後再window上觸發滑動和結束事件,這就意味着咱們在滑動的過程當中能夠在左側的內容區域滑動,同時也能達到index的效果。app

function handleTouchstart(e) {
    // 若是不是從索引欄開始滑動,則直接return
    // 保證了左側內容區域可以正常滑動
    if (e.target.tagName !== 'LI') {
        return;
    }
    
    // 記錄開始的clientX值,這個clientX值將在以後的滑動中持續用到,用於定位
    navOffsetX = e.changedTouches[0].clientX;
  
    // 內容滑動到指定區域
    scrollList(e.changedTouches[0].clientY);
    if (indicatorTime) {
        clearTimeout(indicatorTime);
    }
    moving = true;
    
    // 在window區域註冊滑動和結束事件
    window.addEventListener('touchmove', handleTouchMove, { passive: false });
    window.addEventListener('touchend', handleTouchEnd);
}

這裏面用到了e.changedTouches,這個API能夠去MDN查一下。dom

若是不是用到多點觸控,changedTouchestouches的區別並非特別大,changedTouches在同一點點擊兩次,第二次將不會有touch值。具體能夠看這篇文章學習

下面看一下如何滑動:

function scrollList(y) {
    // 經過當前的y值以及以前記錄的clientX值來得到索引欄中的對應item
    var currentItem = document.elementFromPoint(navOffsetX, y);
    if (!currentItem || !currentItem.classList.contains('indexlist-navitem')) {
        return;
    }
  
    // 顯示指示器
    currentIndicator = currentItem.innerText;
    indicator.innerText = currentIndicator;
    indicator.style.display = '';

    // 找到左側內容的對應section
    var targets = [].slice.call(sections).filter(function(section) { 
        var index = section.getAttribute('data-index');
        return index === currentItem.innerText;
    });
    var targetDOM;
    if (targets.length > 0) {
        targetDOM = targets[0];
        // 經過對比要滑動到的區域的top值與最開始的一個區域的top值
        // 二者的差值即爲要滾動的距離
        content.scrollTop = targetDOM.getBoundingClientRect().top - firstSection.getBoundingClientRect().top;
      
        // 或者使用scrollIntoView來達到相同的目的
        // 不過存在兼容性的問題
        // targetDOM.scrollIntoView();
    }
}

關於elementFromPointAPI能夠看這裏

http://www.javashuo.com/tag/caniuse.com上關於getBoundingClientRectscrollIntoView的兼容性

  • getBoundingClientRect

getBoundingClientRect

  • scrollIntoView

scrollIntoView

最後須要註銷window上的滑動事件

window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('touchend', handleTouchEnd);

2. 總結

分析就這麼多,多看源碼可以學到優秀的設計理念。好比若是最開始讓我來作的話,我能夠就只會在右側的索引欄上綁定事件,而不會關聯左側的內容,這樣滑動的區域將會大大減少。

同時看源碼能夠學到一些比較偏僻的知識,促使本身去學習。好比文中的changedTouches以及elementFromPointAPI的學習。

相關文章
相關標籤/搜索