Vue | 带有左右点击按钮可控制滑动的列表

这篇博客介绍了如何使用JavaScript和CSS实现一个横向滑动列表的功能,包括左右按钮控制item的平滑移动。通过设置元素的`position: relative`和`left`属性,结合`transition`实现动画效果。文章详细讲解了滑动逻辑,包括判断边界条件和计算滑动距离,并提供了相应的Vue组件代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

效果

请添加图片描述

功能点

大概有如下两个功能点:

  • 列表横向排列
  • 点击左右两个按钮可以左右移动每个item(附加动画)

思路

列表横向排列可以使用flex布局解决,主要逻辑在左右滑动的控制上面。

在样式上来看,左右滑动其实可以看成:改变position为relative时属性left值。

具体分析如下:

请添加图片描述

如上图,蓝色为外层div,红色为内层div。

内层div装有列表的各项item,所以它的宽度可能会大于外层div的宽度。外层div采用定宽,同时设置overflow: hidden,使内层div突出的部分隐藏起来。然后通过设置内层div的position: relative,调整left属性的值来达到左右滑动的效果。

请添加图片描述

如上图,把外层div的宽度称为boxLength,内层div的宽度称为allLength,属性值left的绝对值(因为这里left的值应该为负数)称为leftMove。

基于上面的分析,如果左右两个按钮要控制滑动,实际上就是控制left的属性值。

先来分析右边的按钮:

假设一个列表项目item的宽度为120px,如果要向右移动3个项目item单位,实际上是将left属性值-360。

而且从上图容易得到,当leftMove+boxLength ≥ allLength的时候,向右滑动就应该暂停。

但这里有个小细节,如果内层div(红)右边隐藏部分的width < 360px,则应该只移动那小于360px的一部分宽度,而不应该直接向左移动360px,不然外层div的右侧就会有一段空白。

基于上面这段逻辑,有:

scrollRight() {
  const allLength = this.monitorList.length * 120 // monitorList是项目列表
  const boxLength = document.getElementById('list-box').clientWidth // 用clientWidth获取外层div的宽度
  if (allLength < boxLength) return // 不需要滑动
  const listEl = document.getElementById('list')
  const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null).left))
  if (leftMove + boxLength + 360 > allLength) {
    // 到底的时候
    listEl.style.left = '-' + (allLength - boxLength) + 'px'
  } else {
    listEl.style.left = '-' + (leftMove + 360) + 'px'
  }
}

这里有个小tip,获取left属性的时候,不能用

document.getElementById('xxx').style.left

这样得到的值将会是undefined,可以用window.getComputedStyle(listEl, null).left来获取。

如何使用JavaScript获取CSS的left属性值?

Window.getComputedStyle() - Web API 接口参考 | MDN

同理,向左滑动,就是将left的属性值+360px;当leftMove + boxLength - 360 < boxLength的时候,就应该是滚动到最前面了,此时left的属性值就为0。

scrollLeft() {
  const allLength = this.monitorList.length * 120
  const boxLength = document.getElementById('list-box').clientWidth
  if (allLength < boxLength) return
  const listEl = document.getElementById('list')
  const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
  if (leftMove + boxLength - 360 < boxLength) {
    // 滚到
    listEl.style.left = '0px'
  } else {
    listEl.style.left = '-' + (leftMove - 360) + 'px'
  }
}

最后,要像滑动有动画效果,可以使用transition: left 1s;来实现。

demo

<template>
  <div>
    <el-card>
      <div class="monitor-list">
        <!-- 左边按钮 -->
        <div class="btn" @click="scrollLeft">
          <i class="el-icon el-icon-caret-left" />
        </div>
        <!-- 中间列表 -->
        <div id="list-box" class="list-box">
          <div id="list" class="list">
            <div v-for="item in monitorList" :key="item.id" class="list-item">
              <img v-if="item.status" width="60" height="60" :src="imgList.alive" alt="">
              <img v-else width="60" height="60" :src="imgList.down" alt="">
              {{ item.name }}
            </div>
          </div>
        </div>
        <!-- 右边按钮 -->
        <div class="btn" @click="scrollRight">
          <i class="el-icon el-icon-caret-right" />
        </div>
      </div>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    return {
      monitorList: [],
      imgList: {
        alive: require('@/assets/images/icon/device-alive.png'),
        down: require('@/assets/images/icon/device-down.png')
      }
    }
  },
  created() {
    this.initMonitorList()
  },
  methods: {
    initMonitorList() {
      for (let i = 1; i < 21; i++) {
        this.monitorList.push({
          id: i,
          name: `item${i + 1}`,
          status: 0
        })
      }
    },
		// 左滑动逻辑
    scrollLeft() {
      const allLength = this.monitorList.length * 120
      const boxLength = document.getElementById('list-box').clientWidth
      if (allLength < boxLength) return
      const listEl = document.getElementById('list')
      const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
      if (leftMove + boxLength - 360 < boxLength) {
        // 到最开始的时候
        listEl.style.left = '0px'
      } else {
        listEl.style.left = '-' + (leftMove - 360) + 'px'
      }
    },
		// 右滑动逻辑
    scrollRight() {
      const allLength = this.monitorList.length * 120
      const boxLength = document.getElementById('list-box').clientWidth
      if (allLength < boxLength) return
      const listEl = document.getElementById('list')
      const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
      if (leftMove + boxLength + 360 > allLength) {
        listEl.style.left = '-' + (allLength - boxLength) + 'px'
      } else {
        listEl.style.left = '-' + (leftMove + 360) + 'px'
      }
    }
  }
}
</script>
<style lang="scss" scoped>
  .monitor-list {
    display: flex;
    justify-content: space-between;
    height: 95px;

    .btn {
      border: 1px solid #b3d8ff;
      width: 50px;
      height: 100px;
      line-height: 100px;
      text-align: center;
      cursor: pointer;
      background-color: #ecf5ff;
      // icon
      font-size: 24px;
      color: #409eff;

      &:hover {
        background-color: #409eff;
        color: white;
      }
    }
    .list-box {
      width: calc(100vw - 100px);
      overflow: hidden;

      .list {
        width: calc(100vw - 100px);
        display: flex;
        transform: all 2s;
        .list-item {
          width: 100px;
          height: 95px;
          text-align: center;
          padding: 10px;
          cursor: pointer;
          margin-left: 40px;
        }
        position: relative;
        left: 0;
        transition: left 1s;
      }
    }
  }
</style>
### Vue3 中通过点击按钮实现页面向下滚动 为了实现在 Vue3 项目中点击按钮使页面向下滚动的效果,可以采用多种方法来操作 DOM 元素的滚动行为。一种常见的方式是利用 JavaScript 的 `scrollIntoView` 或者直接设置元素的 `scrollTop` 属性。 对于特定区域内的内容滚动,确保目标容器具有合适的 CSS 样式以便能够显示滚动条: ```css .detailContent { width: 100%; height: calc(100% - 90px); overflow-y: scroll; background: #fff; border-radius: 15px; padding: 20px; box-sizing: border-box; } ``` 当用户点击按钮时,可以通过调用 `this.$nextTick()` 来等待 DOM 更新完成之后再执行滚动逻辑[^1]。下面是一个简单的例子说明如何在 Vue 组件内实现这一功能: ```javascript <template> <div class="container"> <!-- 假设这是要滚动的内容区 --> <div ref="contentArea" class="detailContent"></div> <!-- 按钮用于触发滚动事件 --> <button @click="handleScrollDown">向下滚动</button> </div> </template> <script> export default { methods: { handleScrollDown() { this.$nextTick(() => { const contentDiv = this.$refs.contentArea; // 获取当前 scrollTop 并增加一定距离模拟向下滑动 let newScrollTop = contentDiv.scrollTop + window.innerHeight / 2; // 设置新的 scrollTop 达到平滑滚动效果 contentDiv.scrollTo({ top: newScrollTop, behavior: 'smooth' }); }); } } }; </script> ``` 此代码片段展示了怎样创建一个带有滚动能力的 `.detailContent` 容器以及关联的按钮,当按下按钮后会触发展开更多内容并让视窗平稳地移至新位置的操作。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值