实践积累 —— 用Vue3简单写一个单行横向滚动组件

目录

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

  • 效果图
  • 需求分析
  • 实现分析

    • 样式展示分析
    • 变量分析
    • 方法分析
  • 实现步骤

      1. 实现模板
      1. 实现css
      1. 首先获取list
      1. 页面挂载后监听groupBoxRef的scroll事件并获取当前的滚动位置
      1. 计算展示的宽度显隐箭头,当卡片宽度大于外层宽度就展示
      1. 控制箭头展示方向
      1. 监听外层宽度改变和窗口大小改变箭头显隐
  • 完整代码

效果图

把之前完成的一个效果图摘出来记录一下,核心代码在这里,如果项目中用到其他的技术,也很容易改。

实践积累 —— 用Vue3简单写一个单行横向滚动组件_第1张图片

需求分析

  1. 展示数据始终一行,多余的部分可以出滚动条,同时隐藏滚动条样式。
  2. 支持笔记本触控滑动展示
  3. 支持鼠标点击滑动,多余的时候出现箭头按钮,默认滑动3个卡片的位置,顶头就切换方向
  4. 页面出现变动的时候要监听及时显示或隐藏按钮

实现分析

样式展示分析

  • 外层控制总体组件宽度

    • 内层箭头区域展示,内部使用flex布局,绝对定位到右侧

      • 内部箭头svg图标,垂直居中
    • 内层控制滚动区域宽度,内部使用flex布局,控制一层展示,溢出滚动展示,并隐藏滚动条

      • 内部确定卡片宽高和间距,最后一个右边距为0

    变量分析

  • 卡片 list:Array
  • 控制箭头显隐 arrowShow:Boolean,控制箭头方向 direction:String
  • 获取滚动位置 scrollPosition = {left: 0, top: 0}
  • 计算宽度需要的ref:控制滚动条层 groupBoxRef,卡片 groupCardRef

方法分析

  1. 获取list(可以http,也可以props,根据需求来定)
  2. 页面挂载之后,监听groupBoxRef的scroll事件和窗口变化的resize事件
  3. 箭头的显隐判断方法,改变箭头方向的方法
  4. 鼠标点击箭头的方法

实现步骤

1. 实现模板

2. 实现css

3. 首先获取list

4. 页面挂载后监听groupBoxRef的scroll事件并获取当前的滚动位置

// 添加reactive和onMounted
import { defineComponent, ref, reactive, onMounted } 
...
const groupBoxRef = ref(null); // 获取外层卡⽚ref
const groupCardRef = ref(null); // 获取卡⽚ref
const scrollPosition = reactive({
    left: 0,
    top: 0
}); // 滚动位置
...
// 获取scroll函数的位置
const handleScroll = e => {
    scrollPosition.left = e.target.scrollLeft;
    scrollPosition.top = e.target.scrollTop;
}

getMyGroup();

onMounted(() => {
    // 监听scroll事件
    groupBoxRef.value.addEventListener('scroll', handleScroll, true);
})

return {
    // data
    groupInfo,
    // ref
    groupBoxRef,
    groupCardRef,
};

5. 计算展示的宽度显隐箭头,当卡片宽度大于外层宽度就展示

  • 卡片宽度:groupCardRef.value.offsetWidth
  • 外层宽度:groupBoxRef.value.offsetWidth
  • 滚动区域宽度:卡片数量 * (卡片宽度 + 右边距)- 最后一个右边距
...
const arrowShow = ref(false); // 滚动箭头是否显示

// 获取卡⽚宽度,第⼀个参数是卡⽚个数,默认是整个数组,第⼆个参数是剩余的margin
const getWidth = (num = groupInfo.value.length, restMargin = 16) => {
    // 如果没有内容就返回0
    if(!groupCardRef.value) return 0;
    return num * (groupCardRef.value.offsetWidth + 16) - restMargin;
}

// 判断arrow是否展示
const checkArrowShow = () => {
    arrowShow.value = getWidth() > groupBoxRef.value?.offsetWidth ? true : false;
}
...
onMounted(() => {
    // 监听scroll事件
    groupBoxRef.value.addEventListener('scroll', handleScroll, true);
    // 首次检查箭头展示
    checkArrowShow();
})

6. 控制箭头展示方向

  • 初始朝右,横向滚动区域为0就朝右,剩余宽度比外层宽度小就朝左
  • 剩余宽度:滚动区域宽度 - 滚动距离

...
const direction = ref('right'); // 默认项⽬组箭头向右
...
// 改变滚动⽅向
const changeArrow = (scrollLeft) => {
    // 默认获取scoll部分整个宽度
    const getScrollWidth = getWidth();
    // 计算得出剩余宽度
    const restWidth = getScrollWidth - scrollLeft
    if (restWidth <= groupBoxRef.value.offsetWidth) {
        direction.value = 'left'
    } else if ( scrollLeft === 0 ) {
        direction.value = 'right'
    }
}

// ⿏标点击滚动
const groupScroll = async () => {
    // 计算移动宽度,现在是移动3个卡片的数量
    const getMoveWidth = getWidth(3, 0);
    // 如果方向是右边就+,左边就-
    if (direction.value === 'right') {
        groupBoxRef.value.scrollLeft += getMoveWidth;
    } else {
        groupBoxRef.value.scrollLeft -= getMoveWidth;
    }
    // 滚动需要时间才能获取最新的距离,根据新的距离看箭头的方向
    setTimeout(() => {
        changeArrow(groupBoxRef.value.scrollLeft);
    }, 500)
}

// 触摸板滑动的时候位置实时改变箭头方向
const handleScroll = e => {
    ...
    changeArrow(scrollPosition.left);
}

return {
        
    // 新加的data
    ...
    direction,
    // ref
    ...
    // 新加的methods
    groupScroll
};

7. 监听外层宽度改变和窗口大小改变箭头显隐

import { defineComponent, ref, reactive, onMounted, watchEffect } from 'vue';
...
watchEffect(() => {
    checkArrowShow();
})

onMounted(() => {
    ...
    // 监听窗⼝变化事件,判断arrow的展示
    window.addEventListener('resize', checkArrowShow, true);
})

完整代码



你可能感兴趣的:(实践积累 —— 用Vue3简单写一个单行横向滚动组件)