前言:
近期我在我的项目中就接到了一个实现轮播图组件的需要。最开始我也像大家一样,间接抉择应用了出名的开源我的项目 "Swiper",然而起初发现它在挪动端我的项目中某些测试环境下会白屏一段时间。无论如何调试都不能修复这个问题,于是就本人上手写了个轮播图组件,实现代码其实也只有 200 行,很少然而完满解决了咱们我的项目的问题。
尽管曾经 2023 年了,然而轮播图组件的实现依然是考验前端基本功的经久不衰的题目,于是来分享一下实现思路。
tips: 本文次要目标不是一上来就贴代码,而是会一步一步带你理清细节局部,即便你当初没有轮播图这个需要。
一. 应用 overflow-scroll 实现根底框架
- 大家在我的项目中必定接触到溢出滚动的需要,其实就是用到了 overflow-auto 等相干属性。
- 留神:款式方面,在这里我应用的是
UnoCSS
,将款式內联在了标签里,如果你还不理解这种写法,你能够点击下方的文章学习。不过即便你之前从未理解过UnoCSS
,也不会影响你上面的浏览,因为款式不是本文的重点,并不影响整体浏览。
手把手教你如何创立一个代码仓库 - 让咱们疾速制作一个溢出的场景来实现筹备工作。其实非常简单,就是简略的发明一个容器,容器里放着三个和容器宽高雷同的 div。而后给父容器一个 overflow-auto 属性,让它能够在内容溢出的时候产生滚动。
成果如下:
二. 实现适合地位主动切换
- 当初咱们仅仅实现了一个能够滚动的容器而已,然而轮播图最次要的事件就是用户滚动的地位不适合,那么咱们也要主动调整到适合的地位显示。
- 更具体来讲,就是当咱们拖动图片到了两头这样的地位松手时,轮播图最重要一个性能就是能够主动切换到上一张或者下一张,精确的显示适合的内容给用户。(因为展现内容区域展现一半一半的内容毫无意义嘛。)
这里就须要用到两个至关重要的 CSS 属性,
- snap-type
- snap-align
- 咱们先看 snap 这个单词的意思。在这里它的意思我认为 “咔嚓一声,折断” 更合乎这个属性的含意,不要焦急,你能够临时先带着这个含糊的概念来缓缓了解接下来的内容。
- 咱们先看 snap-type 是用来干什么的。
这里 MDN 的解释不是特地好懂,接下来我会用人话翻译一下它想表白的含意。 - 回到咱们的代码局部,咱们创立了一个容器 div,并且这个容器因为溢出,并且设置了 overflow-滚动 相干属性。
其实咱们的 scroll-type 是用来给滚动容器的!这里特地留神,它肯定是用在设置了 overflow-auto 等属性的那个元素上的。 - 对于属性值,咱们采纳 snap-type: x mandatory。
在这里x
的含意代表着横轴产生的滚动,那么聪慧的你能够猜到,它也有一个y
属性,代表着竖轴产生滚动时的设置。 - 这里还有一个关键字
mandatory
代表着强制的意思。因为在某些状况下,浏览器会认为用户滑到上面这种地位是被迫的,然而咱们的场景是不须要思考这种状况的,所以要通知浏览器咱们须要你帮我 “强制咔嚓折断”。 - 至于 proximity ,这个属性的算法有点奇怪,我也没太搞懂它的含意,不过咱们的需要不须要用到这个关键字,大家有趣味也能够自行查阅。
- 接下来给咱们的容器设置这个属性,让咱们先看看成果。
- 什么状况?怎么没成果呢?目前为止咱们仅仅给容器设置了滚动的需要还是不够的,还得通知子元素滚动到什么地位停下才行。这里就须要用到
snap-align
属性了。它是给滚动容器的子元素设置的。 snap-align
,这个属性有三个值能够设置,none
,center
和end
。
其实从这个属性的名字就能够猜到,它其实设置的是子元素的地位是绝对于滚动容器的右边对齐还是左边对齐。怎么了解呢?咱们将滚动容器的宽度调大,让它能够漏出一点点其它元素的内容。并且只给数字2的元素设置 scroll-align 相干属性。(tips: 这里须要重点留神,咱们只给了一个元素设置了这个属性,另外两个元素是没有设置这个属性的。)
- snpa-align: start (元素2无论如何都会在松开鼠标的时候紧贴着滚动容的右边,也就是滚动容器的 start 地位
- snap-align: center (元素2无论如何都会紧贴着滚动容器两头地位
- snap-align: end (元素2的左边无论如何都会紧贴着滚动容器
- snpa-align: start (元素2无论如何都会在松开鼠标的时候紧贴着滚动容的右边,也就是滚动容器的 start 地位
- 晓得了这三个属性的区别,那么接下来还原咱们的容器样子,因为咱们实际上轮播图的每一项的宽高和滚动容器的内容区是恰好相等的,所以咱们给子元素无论设置怎么的三个值的成果都是一样的。
让咱们看一下成果:
看起来成果还不错~
三. 实现上一项和下一项切换性能
- 咱们筹备两个按钮,当用户点击这两个按钮的时候,能够进行手动的切换上一张和下一张。
- 这里咱们须要用到滚动容器的 scroll 事件,须要给滚动容器绑定绝对的回调函数。
这里通过e.target
就能够拿到咱们滚动容器自身。容器本身存在一个 scollLeft 属性,你须要晓得一个知识点其实产生滚动的实质就是 scrollLeft 值的变动。
留神观看上面滚动容器的 scrollLeft 属性值的变动。 - 晓得了这个关键点,那么咱们的
pre
和next
函数就能够很明确的书写了。
首先通过 ref 拿到元素自身。 - 而后在
pre
函数外部获取以后滚动元素的scollLeft
值。 紧接着,你须要晓得的是,这个值即是一个可读属性,也是一个可写属性。那么咱们就能够进行判断,如果以后照片不是第一张的话。,那么我就让 scrollLeft 的值 -300。这里有两个要害的知识点。
- 第一张对应的 scrollLeft 等于0
- 这里的 300 是咱们写死的宽度,你能够依据前面本人的我的项目优化这个值。
- 让咱们看一下成果,先让咱们手动滚动到第三张,而后点击上一张切换。
- 这里如同有一点点不对劲,咱们不是平缓适度到上一张的而是间接切换到上一张的,这里很简略,须要给滚动容器设置一个
scroll-behavior:smooth
即可。
咱们看一下成果: - 下一张按钮的实现同理,这里不过多赘述,代码如下:
- 最终的成果:
四. 源码
<script setup lang="ts">import { ref, computed } from "vue";const box = [ { number: 1, bg: "blue", }, { number: 2, bg: "pink", }, { number: 3, bg: "red", },];const containerEl = ref<HTMLDivElement>();function scrollEvent(e: UIEvent) { const containerEl = e.target as HTMLDivElement;}// 上一张function pre() { const el = containerEl.value; if (!el) return; const scrollLeft = el?.scrollLeft; if (scrollLeft > 0) { el.scrollLeft = scrollLeft - 300; }}function next() { const el = containerEl.value; if (!el) return; const scrollLeft = el?.scrollLeft; const max = (box.length - 1) * 300; //轮播图的数量 -1 if (scrollLeft < max) { el.scrollLeft = scrollLeft + 300; }}</script><template> <div class="w-100vw h-100vh text-14px text-black flex justify-center items-center" > <div @click.stop="pre" class="w-60px h-60px rounded-full bg-black flex items-center justify-center" > <span class="text-white">上一张</span> </div> <div ref="containerEl" @scroll="scrollEvent" class="w-300px h-300px overflow-auto flex snap-x snap-mandatory scroll-smooth" > <div v-for="(item, index) in box" class="w-300px h-300px shrink-0 leading-300px text-center snap-center" :style="{ backgroundColor: item.bg }" > <span class="text-100px text-white">{{ item.number }}</span> </div> </div> <div @click="next" class="w-60px h-60px rounded-full bg-black flex items-center justify-center" > <span class="text-white">下一张</span> </div> </div></template>
五. 结语
在真正的我的项目上,其实我还实现了从最初一张到第一张,或者从第一张到最初一张的无缝切换,然而解说起来略微有点简单,会让文章变得简短。所以打算本文只是解说根底框架,如果有读者心愿学习思路的话,我会在之后更新相干知识点。