Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

banner 无限滚动原理解析 #30

Open
hrpc opened this issue May 7, 2021 · 0 comments
Open

banner 无限滚动原理解析 #30

hrpc opened this issue May 7, 2021 · 0 comments

Comments

@hrpc
Copy link
Owner

hrpc commented May 7, 2021

构建如下结构代码:
要点:
红框内叫做内容区域,表示实际内容,元素个数对应数组元素中元素个数。
两个绿框叫做占位区域,标识占位防抖区域,前后各一个元素,使用js动态添加。

image

思路如下:

1. 获取红框内第一个元素A和最后一个元素B
2. 将A追加到列表最后一个元素之后,将B追加到列表第一个元素之前
3. 判断容器滚动到占位区域时,监听transitionend事件,在回调函数中执行换位逻辑,即执行一个0秒的transform,将位置变换到红框内对应的元素之上

tip: 原生js使用cloneNode(true) 用于深拷贝一个node节点,得到以上元素结构,每次滚动距离是容器宽度

实现:
基于vue3 setup script

<template>
  <div class="wrapper">
    <div class="container" ref="container" @transitionend="transitionend">
      <div class="banner" v-for="(item, i) in list" :key="i" :ref="setRef">{{item}}</div>
    </div>
    <button class="pre" @click="pre">pre</button>
    <button class="next" @click="next">next</button>
  </div>
</template>

<script setup>
  import { onMounted, ref, reactive } from 'vue'
  const list = reactive([1, 2, 3])
  const divs = reactive([])
  let targetWidth = 0
  const container = ref(null)
  let fatherNodeOuter = null
  let targetIndex = -1

  const setRef = el => {
    divs.push(el)
  }
  const init = (fatherNode, elements) => {
    let ele_len = elements.length
    const cloneNodeFirst = elements[0].cloneNode(true)
    const cloneNodeLast = elements[ele_len - 1].cloneNode(true)
    fatherNode.appendChild(cloneNodeFirst)
    fatherNode.insertBefore(cloneNodeLast, elements[0])
    fatherNodeOuter = fatherNode
    // 设置样式
    let target = elements[0].getBoundingClientRect()
    targetWidth = target.width
    fatherNode.style.transform = `translate3d(-${targetWidth}px, 0, 0)`
    fatherNode.style.transitionDuration = '0ms'
  }
  const pre = () => {
    // 重置位置索引
    if (targetIndex === -0) {
      targetIndex = -3
    }
    ++targetIndex
    doTransform()
  }
  const next = () => {
    // 重置位置索引
    if (targetIndex === -4) {
      targetIndex = -1
    }
    --targetIndex
    doTransform()
  }
  // 执行动画
  function doTransform() {
    let computedOffset = targetWidth * targetIndex
    fatherNodeOuter.style.transform = `translate3d(${computedOffset}px, 0, 0)`
 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant