この記事は主にモバイル端末の効果のインデックスリストを詳しく紹介していますので、興味のある方は参考にしていただければ幸いです。
前に書いてます
前回のモバイルエフェクトの話に続き、今回はIndexListの実装原理について説明します。効果は次のとおりです:
ここでコードを参照してください: github
モバイルエフェクト用のスワイパー
モバイルエフェクト用のピッカー
モバイルエフェクト用の cellSwiper
1. コア分析
全体的な原理右側のインデックスバーをクリックまたはスライドすると、クリックのインデックス値を取得して左側のコンテンツを対応する位置にスライドさせます。特定の位置にスライドする方法については、以下の内訳を参照してください:
1.1 基本的な HTML コード
<p class="indexlist"> <ul class="indexlist-content" id="content"> <!-- 需要生成的内容 --> </ul> <p class="indexlist-nav" id="nav"> <ul class="indexlist-navlist" id="navList"> <-- 需要生成的索引条 --> </ul> </p> <p class="indexlist-indicator" style="display: none;" id="indicator"></p> </p>
1.2 DOM の初期化
Ele.me コンポーネント ライブラリのindexList は vue コンポーネントを使用して DOM を生成するため、通常、ここでは DOM の生成をシミュレートするために JavaScript を使用します。
// 内容填充 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"><p class="cell-wrapper"><p class="cell-title"><span class="cell-text">'+ item +'</span></p></p></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 イベントがトリガーされた場合にのみ、touchstart イベントの最後で touchmove および touchend イベントがウィンドウにバインドされます。 window スライド イベントと終了イベントをトリガーします。これは、スライド プロセス中に左側のコンテンツ領域をスライドできると同時に、インデックス効果を達成できることを意味します。
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 で確認できます。
マルチタッチが使用されていない場合、changedTouches と touchs の差は特に大きくありません。changedTouches が同じ点で 2 回クリックされた場合、2 回目のタッチ値はありません。詳細については、この記事をご覧ください
ここでスライドの方法を見てみましょう:
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(); } }
elementFromPoint の API については、getBoundingClientRect とscrollIntoView の互換性についてここ
caniuse.com を参照してください
getBoundingClientRect
sc rollIntoView
最後に、ウィンドウ上のスライディングイベントをキャンセルする必要があります
window.removeEventListener('touchmove', handleTouchMove); window.removeEventListener('touchend', handleTouchEnd);
2. 非常に多くの分析があり、以下を参照することで優れた設計コンセプトを学ぶことができます。ソースコード。たとえば、最初にそれを実行するように求められた場合、右側のインデックス バーにイベントをバインドするだけで、左側のコンテンツを関連付けることはできません。そうすると、スライディング エリアが大幅に減少します。
同時に、ソースコードを見ることで比較的遠い知識を学び、自ら学習するよう促すこともできます。たとえば、この記事では、changedTouches や elementFromPoint などの API の研究が挙げられます。
関連する推奨事項:
以上がモバイル端末でのIndexListの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。