首页 > 其他分享 >原生js实现轮播图与抖音短视频滑动

原生js实现轮播图与抖音短视频滑动

时间:2024-11-21 12:43:40浏览次数:3  
标签:box const 轮播 father value js 抖音 滑动 ref

        这是我防抖音项目的第一篇文章,我也会在后面做项目的过程中不断总结知识点,添加到这个专栏。感谢张大大的项目来源:https://github.com/zyronon/douyin


  基础结构(template与style)

        我们先设置father为视窗,内嵌box作为放置轮播图的容器,box的长度为轮播图数量乘以father宽度,接着在father设置css属性overflow:hidden;截掉box里除了第一个轮播图多出的部分,再将装载轮播图片的son类div放入box

视窗father:设置超出隐藏属性overflow:hidden

轮播图容器box:根据轮播数量设宽度为n*100%

为什么需要一个box:如果没有box直接father嵌套son,轮播图会自动分割father宽度无视css属性

<template>
<div @pointerdown="onPointerdown" class="father">
    <div class="box" :style="{ transform: 'translateX(' + translateX + '%)' }">
        <div class="son" style="background-color: yellow;">请左右滑动1</div>
        <div class="son" style="background-color: blue;" >请左右滑动2</div>
        <div class="son" style="background-color: gray;" >请左右滑动3</div>
        <div class="son" style="background-color: #5b2c6f ;" >请左右滑动4</div>
        <div class="son">
            <div class="short-video-container" :style="{ transform: 'translateY(' + videoTranslateY + '%)' }">
                <div class="video">请上下滑动1</div>
                <div class="video">请上下滑动2</div>
                <div class="video">请上下滑动3</div>
                <div class="video">请上下滑动4</div>
                <div class="video">请上下滑动5</div>
                <div class="video">请上下滑动6</div>
                <div class="video">请上下滑动7</div>
            </div>
        </div>
        <div class="son" style="background-color: red ;">请左右滑动5</div>
    </div>
</div>
</template>

<style lang="scss" scoped>
.father{
    font-size: 20px;
    width: 600px;
    height: 60vh;
    margin: 0 auto;
    overflow: hidden;
    display: flex;
    .box{
        width: 3600px;
        background-color: green;
        display: flex;
        transition: transform 0.3s ease;
        height: 100%;
        .son{
            line-height: 50vh;
            text-align: center;
            user-select: none;
            width: 600px;
            height: 100%;
            overflow: hidden;
            .short-video-container{
                height: 400%;
                transition: transform 0.3s ease;
                width: 600px;
                .video{
                    height: 25%;
                }
            }
        }
    }
}
</style>

     拖动实现(js部分)

        我通过指针事件pointermove,pointerup,pointerdown监听指针(鼠标)在轮播图上的事件,根据每次pointermove移动的距离去加或减box的translateX值,改变box的x轴位置,实现短视频切换的效果

pointerdown:绑定在father上,对全局添加鼠标抬起与移动事件,并记录按下的时间time,坐标startX与startY

pointermove:计算本次移动触发的坐标与上次触发的坐标差,投影到box的translateX上,同时如果是第一次移动,额外判断是竖向还是横向移动

pointerup:三个事件中最复杂的逻辑。需要计算触发时与抬起事件time的时间差,还有抬起坐标与按下坐标的差,判断能否满足跳转视频的临界条件。我将临界条件设置为滑动父容器十分之n的距离或者滑动时间小于400毫秒,如果超过了临界条件就切换到下一个视频,未能到达临界条件则回到当前

<script setup>
import  { ref, onMounted } from 'vue'
const currentPage = ref(5) // 当前页数
const currentVideo = ref(0) // 当前视频
const videoHeight = ref(0)
const translateX = ref(-200/3) // box的唯一
const isDown = ref(false) // 是否按下
const currentX = ref(0) // 迭代的X
const currentY = ref(0) // 迭代的Y
const startX = ref(0) // 起始的X
const startY = ref(0) // 起始的Y
const prevTX = ref(0) 
const prevTY = ref(0)
const time = ref(0) // 起始的时间
const witchWay =ref(false) // 界面切换方向
const activeTopTab = ref(4)  // 默认选中第五页
const videoTranslateY = ref(0) // 短视频div的位移
const onPointerdown = (e) => {
    // 记录一开始的    
    time.value = performance.now() //获取高精度时间
    prevTX.value = translateX.value
    prevTY.value = videoTranslateY.value
    startX.value = currentX.value = e.clientX
    startY.value = currentY.value = e.clientY
    
    isDown.value = true
    // 暂时去掉三个动画效果
    document.querySelector('.box').style.transition = 'none'
    document.querySelector('.short-video-container').style.transition = 'none'
    // 往视窗增加抬起和移动事件监听
    document.addEventListener('pointerup', onPointerup)
    document.addEventListener('pointermove', onPointermove)
}

const onPointermove = (e) => {
    if (isDown.value === true){
        if ( !witchWay.value ){
            // 判断滑动方向
            if (Math.abs(e.clientX - currentX.value) > Math.abs(e.clientY - currentY.value))
                witchWay.value = 'HORIZONTAL'
            else if(Math.abs(e.clientX - currentX.value) < Math.abs(e.clientY - currentY.value) && currentPage.value === 5){
                witchWay.value = 'VERTICAL'
            }
        }else{
            if (witchWay.value === 'HORIZONTAL'){
                // 边界处理
                const disBetMove = e.clientX - currentX.value
                if ((disBetMove > 0 && currentPage.value === 1) || 
                (disBetMove < 0 && currentPage.value === 6) ) return

                translateX.value += disBetMove / 24
            }
            else videoTranslateY.value += 100 * (e.clientY - currentY.value) / videoHeight.value
            currentX.value = e.clientX
            currentY.value = e.clientY
        }
    }
}
const onPointerup = () => {
    const horizontalGap = translateX.value - prevTX.value
    const verticalGap = videoTranslateY.value - prevTY.value
    isDown.value = false
    const nowTime = performance.now()
    // 解除动画限制
    document.querySelector('.box').style.transition = 'transform 0.3s ease'
    document.querySelector('.short-video-container').style.transition = 'transform 0.3s ease'
    // 根据方向决定去留
    if (witchWay.value === 'HORIZONTAL'){
        // 向左or向右
        if ( (nowTime - time.value < 400 && horizontalGap )  || Math.abs( horizontalGap ) > 100/18){
            currentPage.value += (horizontalGap > 0 ? -1 : 1)
            activeTopTab.value += (horizontalGap > 0 ? -1 : 1)
            translateX.value = prevTX.value +( horizontalGap > 0 ? 100/6 : -100/6 );
            // 判断下划线的临界条件 进行临界移动
        }
        // 归位
        else translateX.value = prevTX.value
    }else if(witchWay.value === 'VERTICAL'){
        if ( (nowTime - time.value < 400 && verticalGap )  || Math.abs( verticalGap ) > 100 / 12 ){
            videoTranslateY.value = prevTY.value + ( verticalGap > 0 ? 25 : -25 );
            currentVideo.value += (verticalGap > 0 ? -1 : 1)
        }
        else videoTranslateY.value = prevTY.value
    }
    witchWay.value = ''

    // 移除两个增加的事件
    document.removeEventListener('pointerup', onPointerup)
    document.removeEventListener('pointermove', onPointermove)
}
onMounted( () => {
    videoHeight.value = document.querySelector('.short-video-container').clientHeight
})
</script>

为什么不用touch或mouse事件:指针事件可双端兼容

为什么不直接在father绑定所有指针事件:防止鼠标滑动到容器之外失去判断

为什么需要在pointermove移动时解除动画:不解除的话,拖动会有延迟,但是最后的视频切换有需要动画,所以在pointerup中又加回来

标签:box,const,轮播,father,value,js,抖音,滑动,ref
From: https://blog.csdn.net/violeteverdack/article/details/143866678

相关文章

  • 你会手写原生js代码吗?
    是的,我会手写原生JavaScript代码。我可以创建各种功能的代码,包括:DOM操作:我可以创建、修改和删除HTML元素,以及处理事件,例如点击、鼠标悬停和表单提交。数据处理:我可以处理JSON数据、执行数组操作、使用正则表达式进行模式匹配,以及进行各种数据转换。异步操作:我......
  • GIS开发怎么离得开CesiumJS呢,一旦用上效果立马不一样
    CesiumJS在GIS开发中有着至关重要的地位。它就像是一把神奇的钥匙,开启了地理信息可视化的新大门。在GIS开发中使用CesiumJS,能够实现超逼真的三维地球场景渲染。无论是起伏的山脉、广袤的海洋还是繁华的城市,都能以极其精细的面貌呈现。而且,它支持海量地理数据的加载和动......
  • node.js毕设小额贷款公司贷后管理系统(程序+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于小额贷款公司贷后管理系统的研究,现有研究多集中于小额贷款公司的整体运营或贷前管理方面[4] 。专门针对小额贷款公司贷后管理系统的研究较少。在国......
  • node.js毕设幼儿园管理系统(程序+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容一、选题背景关于幼儿园管理系统的研究,现有研究多侧重于部分功能模块或者特定技术框架下的实现,专门针对包含教师、幼儿信息、班级分配、用户、工作日志、教师考核、......
  • vuejs日期操作辅助类DateUtils
    code//日期戳转日期字符串:yyyy-MM-ddHH:mm:ssexportconstformatDate=(v:string|number|Date)=>{if(v==null){return'';}else{constdateObj=newDate(v);//创建Date对象constyear=dateObj.getFullYear();......
  • nodejs获取ts媒体文件的时间长度
    nodejs获取ts媒体文件的时间长度在Node.js中,你可以使用ffprobe,这是FFmpeg套件中的一个工具,来获取TS媒体文件的时长。首先,确保你已经安装了FFmpeg,然后可以通过Node.js的child_process模块运行ffprobe命令。以下是一个简单的Node.js脚本示例,它使用child_process执行ffpro......
  • 【web】Gin+Go-Micro +Vue+Nodejs+jQuery+ElmentUI 用户模块之前端vue商城项目构建
    构建一个Vue商城项目涉及到多个技术栈的整合。我们将逐步探讨使用Gin、Go-Micro、Vue、Node.js、jQuery和ElementUI来实现用户模块的构建,分为初级、中级、高级阶段。初级用法介绍初级阶段主要关注基础功能实现,如商品展示和简单的购物车逻辑。使用Vue进行前端构建,结合Elem......
  • js案例1. expanding-cards
    效果图: <!DOCTYPEhtml><html><head><metacharset="utf-8"/><title>expanding-cards</title><metaname="viewport"content="width=device-width,initial-scale=1.0"/><......
  • 【开源免费】基于SpringBoot+Vue.JS在线文档管理系统(JAVA毕业设计)
    本文项目编号T038,文末自助获取源码\color{red}{T038,文末自助获取源码}......
  • 【开源免费】基于SpringBoot+Vue.JS网上订餐系统(JAVA毕业设计)
    本文项目编号T039,文末自助获取源码\color{red}{T039,文末自助获取源码}......