vue3的版本也是出来了很久了,但由于实际的工作比较难用的上(现在还是用的vue2的开发模式),所以一直看vue3的学习也就慢慢忘的差不多,主要是用的少,捡起来经常写还是很快能上手的。这次真好有个公司的小项目练练手,自己负责随便用随便搞 :!(捂嘴笑) 新的技术还是要勇于尝试的,学习也是要不停止境的,这次的项目中有一个比较多的场景就是轮播图了,所以在写的时候打算是把轮播图抽离出来,在这之前也就是找找的轮子直接用,也没有仔细的研究去写出来,导致拿上来的时候一时间有点迷,在看了一些简单的示例之后呢,就仿了一个简单的,下面请看:
这是设计图给出的样子,弧形界面套壳加上里面的 png 图片组成一张图。
再说轮播图之前我们可以先回顾复习一下轮播图的简单实现,总结几点;
- 排版问题,单张的图片一定是全屏的宽度。
- 高度可以是自适应,最好做成等高。
- 如果是无缝轮播,可以拷贝一份图片插入到后面,保证循环。
- 注意定时器的使用和清除。
- 通过监听事件
touchend
来获取滚动的索引判断是左滑右滑状态。
找来的一张图表示一下无缝的感觉,但本次封装不做无缝处理,只是顺带了解下。
了解以上的知识储备和无缝介绍,那我们就开始下一项的vue3代码实践。
组件设计采用vue3的 setup
函数,这样也是为了把属于轮播部分的代码抽离,以免页面代码量过多混淆视线。
看一下代码骨架结构:
<div
class="swiper"
ref="swiperRef"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
>
<div class="item" v-for="(slider, index) in sliders" :key="index">
<div class="con">
<img :src="slider" alt="" />
</div>
</div>
</div>
<script>
import { ref } from 'vue'
import useSlider from './use-Slider'
export default {
data() {
return {
sliders: [ '1.png', '2.png', '3.png' ]
}
},
setup() {
const swiperRef = ref(null)
const { touchStart, touchMove, touchEnd, currentIndex } = useSlider(swiperRef)
return {
swiperRef,
touchStart,
touchMove,
touchEnd,
currentIndex
}
},
}
</script>
在 setup
p函数中返回所需要的函数即可在页面上直接使用。
再看一下 use-slider.js
中的代码:
import { ref, onMounted, reactive } from 'vue'
export default function(swiperRef) {
// 图片组的总宽度
const imgWidth = ref(0)
// 图片的数量
const len = ref(0)
// 当前的索引值
const currentIndex = ref(0)
// 当前是否是左右滑动的状态
const isMove = ref(false)
// 开始滑动的位置
const startOffset = ref(0)
// 开始滑动的坐标位置
const startpoint = reactive({
x: 0,
y: 0
})
// 计算的距离
const distance = reactive({
x: 0,
y: 0
})
// 初始化的时候执行轮播
onMounted(() => {
initSlider()
})
function initSlider() {
// 获取宽度
imgWidth.value = swiperRef.value.offsetWidth
len.value = swiperRef.value.querySelectorAll('.item').length - 1
}
function touchStart(e) {
const touch = e.changedTouches[0]
startpoint.x = touch.pageX
startpoint.y = touch.pageY
const translatex = currentIndex.value * -imgWidth.value
// 保存初次滑动的位置,以便第二次滑动的时候重置位置
startOffset.value = translatex
swiperRef.value.style.transition = 'none'
swiperRef.value.style.transform = `translateX(${translatex}px)`
}
function touchMove(e) {
const touch = e.changedTouches[0]
distance.x = touch.pageX - startpoint.x
distance.y = touch.pageY - startpoint.y
// 判断手指是否是横行滑动
if (Math.abs(distance.x) - Math.abs(distance.y) > 5) {
isMove.value = true
e.preventDefault()
} else if(Math.abs(distance.x) - Math.abs(distance.y) < 5){
isMove.value = false
}
if (isMove.value) {
let translatex = startOffset.value + distance.x
// 做个临界点回弹
if (translatex > 0) {
translatex = translatex > 30 ? 30 : translatex
} else {
const d = -(imgWidth.value * len.value + 30)
translatex = translatex < d ? d : translatex
}
swiperRef.value.style.transform = `translateX(${ translatex }px)`
}
}
function touchEnd() {
if (Math.abs(distance.x) > imgWidth.value * proportion) {
currentIndex.value -= distance.x / Math.abs(distance.x)
}
// 如果超出就重置
if (currentIndex.value < 0) {
currentIndex.value = 0
} else if (currentIndex.value > len.value) {
currentIndex.value = len.value
}
if (isMove.value) {
let translatex = currentIndex.value * -imgWidth.value
swiperRef.value.style.transition = 'all .3s'
swiperRef.value.style.transform = `translateX(${ translatex }px)`
isMove.value = false
}
}
return {
touchStart,
touchMove,
touchEnd,
isMove,
currentIndex
}
}