原生实现一个走马灯效果

348 阅读2分钟

需求

实现一个横向滚动,一个页面同时只能显示5(可以根据需求自定义)个信息展示项,超出部分通过左按钮或者右按钮就行滑动,如果滑动到头,则按钮置灰,表示无法滑动

思路

使用相对定位,如果点击滑动的时候,让项相对原本位置进行偏移,然后加上简单的动画效果让偏移更加丝滑。

实现代码

/*html*/
<div class="center-content">
        <div :class="['center-content-item', (index + 1 === frontIndex || index === frontIndex + 4) ? '' : 'split-line']"
          v-for="(item, index) in businessData" :key="index" :style="getContentStyle()">
          <div class="title">{{ item.deviceName }}</div>
          <div v-for="(subItem, subIndex) in item.prodDtos" :key="index + '-' + subIndex" class="text">
            {{ subItem.instId }}
          </div>
        </div>
      </div>
<div class="center-bottom-item">
        <div @click="changeItem('left')" :class="['left', frontIndex === 0 ? 'disabled-click' : '']">
          <ArrowLeft :class="['center-bottom-btn', frontIndex === 0 ? 'disabled-click' : '']" />
        </div>
        <div @click="businessData.length > 5 && changeItem('right')"
          :class="['right', businessData.length <= 5 ? 'disabled-click' : frontIndex === (businessData.length - 5) ? 'disabled-click' : '']">
          <ArrowRight
            :class="['center-bottom-btn', businessData.length <= 5 ? 'disabled-click' : frontIndex === (businessData.length - 5) ? 'disabled-click' : '']" />
        </div>
      </div>
/*js*/
// 需要偏移的位移
const offsetWidth = ref(0)
// 显示在第一个的index
const frontIndex = ref(0)

//点击向左或者向右的按钮时
const changeItem = (command) => {
  const elements = document.getElementsByClassName('center-content-item'); // 替换为你要获取宽度的元素的类名
  const width = elements[0].offsetWidth;
  offsetWidth.value = width//获取单个item的宽度,用于偏移,为了能自适应屏幕
  if (command === 'left') {
    frontIndex.value === 0 ? '' : --frontIndex.value
    offsetWidth.value = frontIndex.value * width

  } else if (command === 'right') {
    frontIndex.value === (businessData.value.length - 5) ? '' : ++frontIndex.value
    offsetWidth.value = frontIndex.value * width
  }
}
//获取样式
const getContentStyle = () => {
  return {
    position: 'relative',
    right: offsetWidth.value + 'px',
  }
}

/*css*/
.center-content {
    height: 70%;
    display: flex;
    overflow-x: hidden;
    max-width: 100%;
    margin: 0;
    white-space: nowrap;
    position: relative;
  }

  .center-content-item {
    flex: 0 0 calc(20% - 20px);
    /* 每个子元素占据 20% 的宽度 */
    min-width: calc(20% - 20px);
    transition: transform 0.3s;
    /* 最小宽度 20% */
    height: 154px;
    // border-right: 1px solid red;
    margin: 0 10px;
    padding: 20px 0px;
    position: relative;
    transition: right 0.5s;
  }

  .split-line::after {
    content: '';
    position: absolute;
    top: 12%;
    right: -2px;
    height: 76%;
    width: 1px;
    background-color: #e8e8e8;
  }
 .center-bottom-item {
    text-align: center;
    display: flex;
    justify-content: center;

    .left {
      width: 20px;
      height: 20px;
      background-color: #E8F2FF;
      margin-right: 10px;
      line-height: 20px;
    }

    .right {
      width: 20px;
      height: 20px;
      background-color: #E8F2FF;
    }


    .center-bottom-btn {
      width: 16px;
      height: 16px;
      position: relative;
      top: 2px;
      cursor: pointer;
      color: #1D59F2;
    }

    .disabled-click {
      background-color: #eaecf0;
      color: #999999;
      cursor: not-allowed;
    }
  }

改进

如果需要自动滑动(走马灯效果),那么在页面渲染的时候加个定时器,让其定时去调用changeItem函数即可,如果滑到最右边之后需要从头开始或者再从右往左滑动,根据条件动态改变frontIndex的值即可 例如:

let direation = 'upward'//滑动的方向
let timeInterval = null;
onMounted(() => {
  timeInterval = setInterval(() => {
    if (frontIndex.value === 0) {
      changeItem('right')
      direation = 'upward'
    } else if (frontIndex.value === (businessData.value.length - 5)) {
      changeItem('left')
      direation = 'backward'
    }else{
      direation==='upward'?changeItem('right'):changeItem('left')//根据方向调用
    }
  }, 3000)
})
onDeactivated(() => {
  clearInterval(timeInterval)

})
/*如果希望到头后从头开始,判断到头,然后重置frontIndex和offsetWidth 即可*/