vue3实现div左右滑动

<template>
    <div class="container">
        <!-- 大盒子 -->
        <div class="father_box">
            <!-- 滚动盒子 -->
            <div class="scroll_box" ref="scrollBox" @mousedown="mousedown" @mousemove="mousemove" @mouseup="mouseup"
                @mouseleave="mouseleave">
                <div class="scroll_box_item" :class="{'scroll_box_item_active':index == item}" ref="scrollBoxItem" @click="change(item)" v-for="(item) in 20" :key="item">{{ item }}</div>
            </div>
        </div>
    </div>
</template>

<script lang="ts" setup>
import { ref,onMounted } from "vue";
let scrollBox = ref();
let scrollBoxItem = ref();
let index = ref(0);
let maxNum = ref(0);  //最大移动位置
let upFlag = ref(false);  //鼠标是否弹起,用于判断是否执行mouseleave的代码
let isMove = ref(false); //控制图片是否能执行选中代码,避免移动的时候,会选中图片 true执行选中代码,false不执行,在mousedown时设置为true,mousemove设置为false,这样就能分辨出当前是移动还是点击
let flag = ref(false); // 鼠标按下
let downX = ref(0); // 鼠标点击的x下标
let scrollLeft = ref(0); // 当前鼠标移动距离
let leftOld = ref(0); //上一次偏移量
const change = (item:any) =>{
    if(!isMove.value){  //如果当前是在移动,那就不执行点击事件的代码,isMove值会在mouseup和mouseleave时,赋值为false
        index.value = item;
    }
}
const mousedown = (e: any) => {
    isMove.value = false;
    flag.value = true;
    downX.value = e.clientX; // 获取到点击的x下标
};
const mousemove = (e: any) => {
    if (flag.value) {   //只有鼠标按下了,才能执行滑动
        isMove.value = true;
        upFlag.value = false;
        // 判断是否是鼠标按下滚动元素区域
        // 获取移动的x轴
        var moveX = e.clientX;
        // 当前移动的x轴下标减去刚点击下去的x轴下标得到鼠标滑动距离
        scrollLeft.value = moveX - downX.value;
        // 上一次移动距离减去当前鼠标的滑动距离
        scrollBox.value.style.transform = `translateX(${leftOld.value + scrollLeft.value
            }px)`;
    }
};
// 鼠标抬起时,不执行mousemove
const mouseup = () => {
    upFlag.value = true;
    flag.value = false;
    if (isMove.value) {  //必须有移动才能执行这里,不然只点击然后鼠标弹起都执行的话,这个移动距离就会一直加
        leftOld.value += scrollLeft.value; //记录上一次的鼠标偏移距离
    }
    if (leftOld.value > 0) {
        scrollBox.value.style.transform = `translateX(0px)`;
        leftOld.value = 0;
    } else if (leftOld.value < maxNum.value) {
        scrollBox.value.style.transform = `translateX(${maxNum.value}px)`;
        leftOld.value = maxNum.value;
    }
};
// 鼠标离开元素,不执行mousemove
const mouseleave = () => {
    if (!upFlag.value && isMove.value) {  //鼠标没有弹起并且有移动才能执行这里
        leftOld.value += scrollLeft.value; //记录上一次的鼠标偏移距离
        if (leftOld.value > 0) {  //leftOld如果大于0了,那就是盒子往右移动了,那就必须复原,这里的往右移动和往右滑动不一样,
            scrollBox.value.style.transform = `translateX(0px)`;
            leftOld.value = 0;
        } else if (leftOld.value < maxNum.value) {
            scrollBox.value.style.transform = `translateX(${maxNum.value}px)`;
            leftOld.value = maxNum.value;
        }
    }
    isMove.value = false;
    upFlag.value = false;
    flag.value = false;
};
onMounted(() =>{
    // 这个20就是盒子的个数,scrollBoxItem.value[0].offsetWidth是盒子的宽度和margin之和,这个距离慢慢调整
    maxNum.value = -((20 - 8) * scrollBoxItem.value[0].offsetWidth);
});
</script>

<style lang="scss" scoped>
.father_box {
    width: 100%;
    overflow: hidden;
    user-select: none;  //字体不能被选中
    .scroll_box {
        display: inline-block; //不会继承父元素的宽高
        white-space: nowrap; //子元素不换行

        .scroll_box_item {
            width: 200px;
            height: 150px;
            background-color: red;
            display: inline-block;
            cursor: pointer;
            margin-right: 10px;
            text-align: center;
            line-height: 150px;
            font-size: 20px;
            color: #fff;
        }
        .scroll_box_item_active{
            background-color: black;
        }
    }
}
</style>

整体思路:一共有三层,第一层是最外层盒子,固定宽度,超出隐藏,第二层盒子宽高由子盒子决定,然后移动盒子来实现滑动,第三层就是子盒子咯。首先第二层盒子上面绑定mousedown,mousemove,mouseup,mouseleave事件,当鼠标mousedown时,记录当前鼠标点击的位置(downX),然后mousemove的时候获取鼠标的位置(scrollLeft),通过这两个位置来获取鼠标移动的距离,然后上一次的移动距离(leftOld) + 这次的移动距离(scrollLeft),然后scrollBox.value.style.transform = translateX(${leftOld.value + scrollLeft.value }px),来移动第二层盒子,再加上一些判断就ok了
这里有一个小瑕疵,就是刷新页面后,直接点击子元素,会执行一次mousemove,导致选不中子元素,但是先点击一次空白地方,就不会执行mousemove了,可能是浏览器的安全策略,但是我没听过

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用vue-awesome-swiper插件来实现左右滑动切换分页。下面是一个简单的例子: 1. 安装vue-awesome-swiper插件 ```bash npm install vue-awesome-swiper --save ``` 2. 在Vue组件中引入vue-awesome-swiper插件 ```javascript import Vue from 'vue' import 'swiper/dist/css/swiper.css' import VueAwesomeSwiper from 'vue-awesome-swiper' Vue.use(VueAwesomeSwiper) ``` 3. 在Vue组件中使用vue-awesome-swiper插件 ```html <template> <div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide">Page 1</div> <div class="swiper-slide">Page 2</div> <div class="swiper-slide">Page 3</div> </div> <div class="swiper-pagination"></div> </div> </template> <script> export default { data() { return { swiperOption: { pagination: '.swiper-pagination', paginationClickable: true, spaceBetween: 30, centeredSlides: true, autoplay: 2500, autoplayDisableOnInteraction: false } } } } </script> <style> .swiper-slide { text-align: center; font-size: 18px; background: #fff; /* Center slide text vertically */ display: flex; justify-content: center; align-items: center; } </style> ``` 4. 样式调整 可以根据实际需求调整样式,例如: ```css /* 设置容器宽度和高度 */ .swiper-container { width: 100%; height: 400px; } /* 设置分页器位置和颜色 */ .swiper-pagination { position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%); } .swiper-pagination-bullet-active { background-color: #007aff; } ``` 这样,就可以通过左右滑动切换分页了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值