向右滑动动效

一、实现效果

二、实现步骤

分两步实现

1)上面的滑动引导动画

2)下面的滑动模块

1、滑动引导动画实现

1)dom结构

html 复制代码
        <div class="hand-guide-swiper-box">
            <div class="hand-guide-swiper-progress"></div>
            <svg
                t="1706587837142"
                class="hand-guide-icon"
                viewBox="0 0 1024 1024"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
                p-id="6128"
                width="36"
                height="36"
            >
                <path
                    d="M430.08 370.688s24.064-48.128 92.672-17.92c0 0 27.136-48.64 91.136-10.24 0 0 34.816-34.816 81.92-3.584 0 0 59.392 40.448 114.688 279.552 7.168 31.232 6.144 64.512-5.12 94.72-18.944 51.712-67.072 119.296-189.952 134.144-114.688 9.216-406.528-176.64-423.424-212.992 0 0-39.936-57.856 30.208-86.528 20.992-8.192 43.52-9.728 65.536-4.608 22.016 5.12 52.736 15.872 83.968 37.888 0 0-150.528-263.68-138.24-363.52 0 0 2.56-64.512 51.2-65.024 0 0 23.04 3.584 48.128 56.32l97.28 161.792z"
                    p-id="6129"
                    fill="#000000"
                ></path>
            </svg>
        </div>

主要是两个部分,一个是引导滑动的滑动条,一个是svg手势icon

2)style部分

less 复制代码
@hand-bg-color: rgb(136, 136, 136);
.hand-guide-swiper-box {
    position: absolute;
    top: 20px;
    left: 50%;
    transform: translate(-50%, -50%);
    .hand-guide-swiper-progress {
        position: absolute;
        left: -200px;
        top: 24px;
        height: 59px;
        background: linear-gradient(to right, #ffffff00, @hand-bg-color);
        animation: hand-guide-swiper-progress 3s infinite;

        &::before {
            position: absolute;
            content: '';
            right: -38px;
            bottom: 0;
            width: 40px;
            height: 59px;
            background-image: linear-gradient(65deg, @hand-bg-color 50%, rgba(255, 255, 255, 0) 50%);
        }
    }

    .hand-guide-icon {
        position: absolute;
        left: 50%;
        transform: translate(-50%, -50%);
        animation: hand-guide-swiper-right 3s infinite;
    }
}

@keyframes hand-guide-swiper-progress {
    0% {
        width: 30px;
    }
    100% {
        width: 330px;
    }
}
@keyframes hand-guide-swiper-right {
    0% {
        transform: translateX(-200px);
    }
    100% {
        transform: translateX(100px);
    }
}

1、.hand-guide-swiper-box相对于父元素绝对定位, 居中显示,左右各200px, 所以手势icon滑动【hand-guide-swiper-right】从X的-200px开始,自身svg占位100,所以到X的100px结束

2、引导滑动的滑动条动效【hand-guide-swiper-progress】,从宽度30px开始是手势svg自带间隙,要想无缝衔接,需要滑动条初始宽度为30px然后再加上以下伪元素;

3、滑动条与手势icon直接无缝衔接之处,用before 伪元素画成一个65度三角形形成的;

4、滑动条渐变效果:background: linear-gradient(to right, #ffffff00, @hand-bg-color);

2、滑动模块

1)dom结构

html 复制代码
        <div class="swiper-right-area">
            <!-- 中间提示文字 -->
            <transition name="swiper-tips-fade">
                <div class="swiper-tips-box" v-show="!isSwiperTarget && !isSwiperActive">
                    <div class="swiper-tips">向右滑动</div>
                    <div class="to-go-app">跳转应用</div>
                </div>
            </transition>

            <!-- 右侧滑动到底目标dom -->
            <div class="swiper-target" ref="swiperTarget"></div>

            <!-- 滑动条 -->
            <div class="swiper-progress-box" :style="swiperProgressStyle">
                <!-- 滑动touch的dom -->
                <div
                    class="phone-box"
                    @touchstart="swiperRightTouchstart"
                    @touchmove="swiperRightTouchmove"
                    @touchend="swiperRightTouchend"
                    :class="{ 'swiper-active': isSwiperActive }"
                >
                    <svg
                        t="1706608994617"
                        class="phone-icon"
                        viewBox="0 0 1024 1024"
                        version="1.1"
                        xmlns="http://www.w3.org/2000/svg"
                        p-id="19103"
                        :style="phoneIconStyle"
                    >
                        <path
                            d="M735.468 0H288.532c-37.816 0-68.549 30.733-68.549 68.548v886.904c0 37.815 30.733 68.548 68.549 68.548h446.936c37.816 0 68.549-30.733 68.549-68.548V68.548C804.017 30.733 773.284 0 735.468 0z m6.855 955.452c0 3.77-3.085 6.854-6.855 6.854H288.532c-3.77 0-6.855-3.084-6.855-6.854V68.548c0-3.77 3.085-6.854 6.855-6.854h76.203V84.2c0 12.225 9.94 22.279 22.278 22.279h245.632c12.225 0 22.279-9.94 22.279-22.279V61.694h80.658c3.77 0 6.855 3.084 6.855 6.854v886.904z"
                            fill="#ffffff"
                            p-id="19104"
                        ></path>
                        <path
                            d="M467.558 877.192h84.771c17.023 0 30.847 13.824 30.847 30.847s-13.824 30.847-30.847 30.847h-84.771c-17.023 0-30.847-13.824-30.847-30.847s13.824-30.847 30.847-30.847z"
                            fill="#ffffff"
                            p-id="19105"
                        ></path>
                    </svg>
                </div>
            </div>
        </div>

大致结构

1、中间提示文字部分,使用产生淡入淡出的效果,当开始滑动的文字淡出,返回到起始滑动点则有显示出来

2、右侧滑动到底目标dom,添加ref是为了获取滑动目标的x坐标值,用于判断是否到底

3、点击滑动touch也就是手机icon,开始滑动,这里滑动条和icon在同一dom上,为了没滑动到底还原时一起回归到滑动起始点;

4、swiperProgressStyle用来动态设置滑动条dom的宽度,以此来实现滑动效果

5、滑动touch的dom也就是手机icon图标,用来处理用户touch事件,其中swiper-active动态class为了在滑动中有个手机icon旋转动画

2)js代码

js 复制代码
export default {
    name: 'swiper-right',
    data() {
        return {
            startX: 0, // 记录滑动touch开始坐标x的值
            offsetX: 0, // 记录滑动距离
            isSwiperTarget: false, // 是否滑动到目标dom
            isSwiperActive: false // 是否在滑动中
        };
    },
    computed: {
        // icon图标大小
        phoneIconStyle() {
            const width = 60;
            const height = 60;
            return {
                width: this.px2rem(width),
                height: this.px2rem(height)
            };
        },
        // 动态设置滑动条dom的宽度,以此来实现滑动效果
        swiperProgressStyle() {
            const otherStyle = {};
            if (this.isSwiperReset) {
                // 还没到100%则还原
                this.offsetX = 0;
                this.isSwiperActive = true;
                otherStyle.transition = 'width 0.6s';
                setTimeout(() => {
                    this.isSwiperActive = false;
                }, 600);
            } else if (this.isSwiperTarget) {
                // 自动到100%进度需要加动画
                otherStyle.transition = 'width 0.2s';
            }
            return {
                width: this.px2rem(92 + this.offsetX),
                ...otherStyle
            };
        },
        // 判断是否需要重新回归滑动起始点(没到目标点,没在滑动并且有滑动距离)
        isSwiperReset() {
            return !this.isSwiperTarget && !this.isSwiperActive && this.offsetX;
        },
        // 获取右侧目标dom的坐标x值
        getSwiperTargetClientX() {
            return this.$refs.swiperTarget.getBoundingClientRect()?.left || 0;
        },
        // px 转 rem
        px2rem() {
            return num => `${num / 100}rem`;
        }
    },
    methods: {
        // touch开始事件 startX用来记录滑动起始点坐标x的值
        swiperRightTouchstart(event) {
            console.log('touch开始事件', event);
            if (event.touches) this.startX = event.touches[0].clientX;
            this.isSwiperTarget = false;
            this.isSwiperActive = true;
        },
        // touch移动事件
        swiperRightTouchmove(event) {
            console.log('touch移动事件', event);
            // 如果有移动touch信息 有滑动起始点 并且移动x大于起始x
            if (event.touches && this.startX && event.touches[0].clientX > this.startX) {
                // 1 移动坐标不能小于开始坐标  2 移动坐标不能大于目标坐标
                if (event.touches[0].clientX <= this.getSwiperTargetClientX) {
                    if (event.touches[0].clientX > this.getSwiperTargetClientX - 4) {
                        // 到目标元素差不多4px之间范围内直接拉到100%
                        // 700 背景椭圆宽度 92 目标元素宽度 28 左右边距
                        this.offsetX = 700 - 92 - 28;
                        this.isSwiperTarget = true;
                    } else {
                        // 滑动距离 滑动touch中的x - 起始点x 2.8是手动调整值,为了解决手指touch距离和滑动条px距离不一致
                        this.offsetX = (event.touches[0].clientX - this.startX) * 2.8;
                        // 如果达到了目标点,当又在滑动中,则isSwiperTarget设置false
                        this.isSwiperTarget && (this.isSwiperTarget = false);
                    }
                }
            }
        },
        // touch结束事件 起始点归零 没在滑动isSwiperActive设置为false
        swiperRightTouchend(event) {
            console.log('touch结束事件', event, '拖动距离', this.offsetX);
            this.startX = 0;
            this.isSwiperActive = false;
        }
    }
};    

滑动逻辑

1、当开始滑动中,中间滑动提示文字淡出,touch手机icon开始旋转

2、当滑动结束没到目标点时,则自动回到滑动起始点

3、当滑动结束到了目标点附近(-4px),则自动与目标点吻合

3)style代码

less 复制代码
    .swiper-right-area {
    width: 700px;
    position: absolute;
    top: 200px;
    left: 50%;
    transform: translate(-50%, -50%);
    height: 120px;
    border-radius: 60px;

    background-color: rgba(102, 102, 102, 0.8);

    .swiper-active {
        animation: swiper-active-rotate 2s linear infinite;
    }
    .swiper-tips-box {
        margin: 18px 0 0 140px;
        .swiper-tips {
            color: #e1e1e1;
            margin-bottom: 6px;
            font-size: 40px;
        }
        .to-go-app {
            font-size: 30px;
            color: #bfbfbf;
        }
    }

    .swiper-target {
        position: absolute;
        right: 14px;
        top: 14px;
        width: 90px;
        height: 90px;
        border-radius: 45px;
        border: 2px dashed rgb(221, 221, 221);
    }

    .swiper-progress-box {
        position: absolute;
        top: 14px;
        left: 14px;

        z-index: 1;
        height: 92px;
        background-color: #e1e1e1;
        border-radius: 46px;

        .phone-box {
            position: absolute;
            right: 0;
            top: 0;

            width: 92px;
            height: 92px;
            background-color: #e1e1e1;
            border-radius: 46px;
            z-index: 2;

            .phone-icon {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
            }
        }
    }

    .swiper-tips-fade-enter-active,
    .swiper-tips-fade-leave-active {
        transition: opacity 0.5s;
    }

    .swiper-tips-fade-enter,
    .swiper-tips-fade-leave-to {
        opacity: 0;
    }
}

@keyframes swiper-active-rotate {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}
相关推荐
Redstone Monstrosity6 分钟前
字节二面
前端·面试
东方翱翔13 分钟前
CSS的三种基本选择器
前端·css
Fan_web36 分钟前
JavaScript高级——闭包应用-自定义js模块
开发语言·前端·javascript·css·html
yanglamei196244 分钟前
基于GIKT深度知识追踪模型的习题推荐系统源代码+数据库+使用说明,后端采用flask,前端采用vue
前端·数据库·flask
千穹凌帝1 小时前
SpinalHDL之结构(二)
开发语言·前端·fpga开发
冯宝宝^1 小时前
基于mongodb+flask(Python)+vue的实验室器材管理系统
vue.js·python·flask
dot.Net安全矩阵1 小时前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
叫我:松哥1 小时前
基于Python flask的医院管理学院,医生能够增加/删除/修改/删除病人的数据信息,有可视化分析
javascript·后端·python·mysql·信息可视化·flask·bootstrap
Hellc0071 小时前
MacOS升级ruby版本
前端·macos·ruby
前端西瓜哥1 小时前
贝塞尔曲线算法:求贝塞尔曲线和直线的交点
前端·算法