目录
版权申明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协定,转载请附上原文出处链接和本申明。
- 效果图
- 需要剖析
实现剖析
- 款式展现剖析
- 变量剖析
- 办法剖析
实现步骤
- 实现模板
- 实现css
- 首先获取list
- 页面挂载后监听groupBoxRef的scroll事件并获取以后的滚动地位
- 计算展现的宽度显隐箭头,当卡片宽度大于外层宽度就展现
- 管制箭头展现方向
- 监听外层宽度扭转和窗口大小扭转箭头显隐
- 残缺代码
效果图
把之前实现的一个效果图摘出来记录一下,外围代码在这里,如果我的项目中用到其余的技术,也很容易改。
需要剖析
- 展现数据
始终一行
,多余的局部能够出滚动条,同时暗藏滚动条款式。 - 反对笔记本
触控滑动
展现 - 反对
鼠标点击滑动
,多余的时候呈现箭头按钮,默认滑动3个卡片的地位,顶头就切换方向 - 当
页面呈现变动的时候要监听
及时显示或暗藏按钮
实现剖析
款式展现剖析
外层管制总体组件宽度
内层箭头区域展现,外部应用flex布局,相对定位到右侧
- 外部箭头svg图标,垂直居中
内层管制滚动区域宽度,外部应用flex布局,管制一层展现,溢出滚动展现,并暗藏滚动条
- 外部确定卡片宽高和间距,最初一个左边距为0
变量剖析
- 卡片
list:Array
- 管制箭头显隐
arrowShow:Boolean
,管制箭头方向direction:String
- 获取滚动地位
scrollPosition = {left: 0, top: 0}
- 计算宽度须要的ref:管制滚动条层
groupBoxRef
,卡片groupCardRef
办法剖析
- 获取list(能够http,也能够props,依据需要来定)
- 页面挂载之后,监听groupBoxRef的scroll事件和窗口变动的resize事件
- 箭头的显隐判断办法,扭转箭头方向的办法
- 鼠标点击箭头的办法
实现步骤
1. 实现模板
<template> <div class="index-group-box"> <!-- 左边滑动箭头 --> <div class="scrollX"> <img src='../assets/arrow-left-bold.svg'/> </div> <!-- 卡⽚ --> <div class="index-group-boxIn" ref="groupBoxRef"> <div v-for="item in groupInfo" :key="item.id" ref="groupCardRef" class="group-card" > <div class="card-name"> 名称 <span>{{ item.name }}</span> </div> </div> </div> </div></template>
2. 实现css
<style scoped> .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; }</style>
3. 首先获取list
<script>import { defineComponent, ref } from 'vue';export default defineComponent({ name: 'scroll', setup() { const groupInfo = ref([]); // 获取卡片列表 const getMyGroup = async () => { const data = [{ id: 1, name:'卡片1' },{ id: 2, name:'卡片2' },{ id: 3, name:'卡片3' },{ id: 4, name:'卡片4' },{ id: 5, name:'卡片5' }] groupInfo.value = data; } getMyGroup(); return { // data groupInfo, }; },});</script>
4. 页面挂载后监听groupBoxRef的scroll事件并获取以后的滚动地位
// 增加reactive和onMountedimport { defineComponent, ref, reactive, onMounted } ...const groupBoxRef = ref(null); // 获取外层卡⽚refconst groupCardRef = ref(null); // 获取卡⽚refconst 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
- 滚动区域宽度:
卡片数量 * (卡片宽度 + 左边距)- 最初一个左边距
<div class="scrollX" v-if="arrowShow"> <img src='../assets/arrow-left-bold.svg'/></div>
...const arrowShow = ref(false); // 滚动箭头是否显示// 获取卡⽚宽度,第⼀个参数是卡⽚个数,默认是整个数组,第⼆个参数是残余的marginconst 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就朝右,残余宽度比外层宽度小就朝左
- 残余宽度:
滚动区域宽度 - 滚动间隔
<!-- 增加点击箭头事件和箭头方向svg --><div class="scrollX" @click="groupScroll" v-if="arrowShow"> <img v-if="direction === 'left'" src='../assets/arrow-left-bold.svg'/> <img v-else src='../assets/arrow-right-bold.svg'/></div>
...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);})
残缺代码
<template> <div class="index-group-box"> <!-- 左边滑动箭头 --> <div class="scrollX" @click="groupScroll" v-if="arrowShow"> <img v-if="direction === 'left'" src='../assets/arrow-left-bold.svg'/> <img v-else src='../assets/arrow-right-bold.svg'/> </div> <!-- 卡⽚ --> <div class="index-group-boxIn" ref="groupBoxRef"> <div v-for="item in groupInfo" :key="item.id" ref="groupCardRef" class="group-card" > <div class="card-name"> 名称 <span>{{ item.name }}</span> </div> </div> </div> </div></template><script>import { defineComponent, ref, reactive, onMounted, watchEffect } from 'vue';export default defineComponent({ name: 'scroll', setup() { const groupInfo = ref([]); // 卡片list const direction = ref('right'); // 默认箭头向右 const arrowShow = ref(false); // 滚动箭头是否显示 const groupBoxRef = ref(null); // 获取外层卡⽚ref const groupCardRef = ref(null); // 获取卡⽚ref const scrollPosition = reactive({ left: 0, top: 0 }); // 滚动地位 // 获取卡片列表 const getMyGroup = async () => { const data = [{ id: 1, name:'卡片1' },{ id: 2, name:'卡片2' },{ id: 3, name:'卡片3' },{ id: 4, name:'卡片4' },{ id: 5, name:'卡片5' }] groupInfo.value = data; } // 获取卡⽚宽度,第⼀个参数是卡⽚个数,默认是整个数组,第⼆个参数是残余的margin const getWidth = (num = groupInfo.value.length, restMargin = 16) => { // 如果没有内容就返回0 if(!groupCardRef.value) return 0; return num * (groupCardRef.value.offsetWidth + 16) - restMargin; } // 扭转滚动⽅向 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 () => { // 获取滚动宽度 const getMoveWidth = getWidth(3, 0); if (direction.value === 'right') { groupBoxRef.value.scrollLeft += getMoveWidth; } else { groupBoxRef.value.scrollLeft -= getMoveWidth; } // 滚动须要工夫能力获取最新的间隔 setTimeout(() => { changeArrow(groupBoxRef.value.scrollLeft); }, 500) } // 判断arrow是否展现 const checkArrowShow = () => { arrowShow.value = getWidth() > groupBoxRef.value?.offsetWidth ? true : false; } watchEffect(() => { checkArrowShow(); }) // 获取scroll函数的地位 const handleScroll = e => { scrollPosition.left = e.target.scrollLeft; scrollPosition.top = e.target.scrollTop; changeArrow(scrollPosition.left); } getMyGroup(); onMounted(() => { // 监听scroll事件 groupBoxRef.value.addEventListener('scroll', handleScroll, true); // 监听窗⼝变动事件,判断arrow的展现 window.addEventListener('resize', checkArrowShow, true); // 首次查看箭头展现 checkArrowShow(); }) return { // data groupInfo, direction, arrowShow, // ref groupBoxRef, groupCardRef, // methods groupScroll }; },});</script><style scoped>.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;}</style>