实践积累|实践积累 —— 用Vue3简单写一个单行横向滚动组件
目录
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
- 效果图
- 需求分析
- 实现分析
- 样式展示分析
- 变量分析
- 方法分析
- 实现步骤
-
- 实现模板
-
- 实现css
-
- 首先获取list
-
- 页面挂载后监听groupBoxRef的scroll事件并获取当前的滚动位置
-
- 计算展示的宽度显隐箭头,当卡片宽度大于外层宽度就展示
-
- 控制箭头展示方向
-
- 监听外层宽度改变和窗口大小改变箭头显隐
-
- 完整代码
文章图片
需求分析
- 展示数据
始终一行
,多余的部分可以出滚动条,同时隐藏滚动条样式。 - 支持笔记本
触控滑动
展示 - 支持
鼠标点击滑动
,多余的时候出现箭头按钮,默认滑动3个卡片的位置,顶头就切换方向 - 当
页面出现变动的时候要监听
及时显示或隐藏按钮
- 外层控制总体组件宽度
- 内层箭头区域展示,内部使用flex布局,绝对定位到右侧
- 内部箭头svg图标,垂直居中
- 【实践积累|实践积累 —— 用Vue3简单写一个单行横向滚动组件】内层控制滚动区域宽度,内部使用flex布局,控制一层展示,溢出滚动展示,并隐藏滚动条
- 内部确定卡片宽高和间距,最后一个右边距为0
- 内层箭头区域展示,内部使用flex布局,绝对定位到右侧
- 卡片
list:Array
- 控制箭头显隐
arrowShow:Boolean
,控制箭头方向direction:String
- 获取滚动位置
scrollPosition = {left: 0, top: 0}
- 计算宽度需要的ref:控制滚动条层
groupBoxRef
,卡片groupCardRef
- 获取list(可以http,也可以props,根据需求来定)
- 页面挂载之后,监听groupBoxRef的scroll事件和窗口变化的resize事件
- 箭头的显隐判断方法,改变箭头方向的方法
- 鼠标点击箭头的方法
名称
{{ item.name }}
2. 实现css
.index-group-box {
padding-right: 16px;
position: relative;
box-sizing: border-box;
width: 100%;
}.scrollX {
width: 16px;
position: absolute;
top: 0;
right: 0;
height: 100%;
background-color: #512D6D;
display: flex;
justify-content: center;
align-items: center
}.scrollX:hover {
cursor: pointer;
background-color: #65447d;
}.index-group-boxIn {
display: flex;
scroll-behavior: smooth;
white-space: nowrap;
overflow-x: auto;
flex: none;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE 10+ */
}.index-group-boxIn::-webkit-scrollbar {
display: none;
/* Chrome Safari */
}.group-card {
padding: 8px 16px;
box-sizing:border-box;
width: 200px;
height: 100px;
border-radius: 4px;
margin-right: 16px;
flex: none;
background: #71EFA3;
color: #54436B;
}.group-card span{
color: #54436B;
}.group-card:hover{
background: #ACFFAD;
}.group-card:nth-last-of-type(1){
margin-right: 0px;
}
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 = https://www.it610.com/article/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 = 'https://www.it610.com/article/left'
} else if ( scrollLeft === 0 ) {
direction.value = 'https://www.it610.com/article/right'
}
}// ?标点击滚动
const groupScroll = async () => {
// 计算移动宽度,现在是移动3个卡片的数量
const getMoveWidth = getWidth(3, 0);
// 如果方向是右边就+,左边就-
if (direction.value =https://www.it610.com/article/=='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);
})
完整代码
名称
{{ item.name }}.index-group-box {
padding-right: 16px;
position: relative;
box-sizing: border-box;
width: 100%;
}.scrollX {
width: 16px;
position: absolute;
top: 0;
right: 0;
height: 100%;
background-color: #512D6D;
display: flex;
justify-content: center;
align-items: center
}.scrollX:hover {
cursor: pointer;
background-color: #65447d;
}.index-group-boxIn {
display: flex;
scroll-behavior: smooth;
white-space: nowrap;
overflow-x: auto;
flex: none;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* IE 10+ */
}.index-group-boxIn::-webkit-scrollbar {
display: none;
/* Chrome Safari */
}.group-card {
padding: 8px 16px;
box-sizing:border-box;
width: 200px;
height: 100px;
border-radius: 4px;
margin-right: 16px;
flex: none;
background: #71EFA3;
color: #54436B;
}.group-card span{
color: #54436B;
}.group-card:hover{
background: #ACFFAD;
}.group-card:nth-last-of-type(1){
margin-right: 0px;
}
推荐阅读
- 急于表达——往往欲速则不达
- 慢慢的美丽
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 2019-02-13——今天谈梦想()
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- Ⅴ爱阅读,亲子互动——打卡第178天
- 低头思故乡——只是因为睡不着
- 取名——兰
- 每日一话(49)——一位清华教授在朋友圈给大学生的9条建议
- 广角叙述|广角叙述 展众生群像——试析鲁迅《示众》的展示艺术