Web API(六)动画函数封装

Web API(六)动画函数封装

一、动画函数封装

1、缓动动画原理

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来。

思路:

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
  2. 核心算法: (目标值 - 现在的位置) / 10 做为每次移动的距离步长
  3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
  4. 注意步长值需要取整

2、 动画函数多个目标值之间移动

注意:当动画函数从800移到500时,要判断步长是正值还是负值

​ 1.如果是正值,则步长往大了取整

​ 2.如果是负值,则步长 向小了取整

3、缓动函数添加回调函数

回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。

回调函数写的位置:定时器结束的位置。

4、封装缓动动画函数animate()★;

// 封装动画函数 animate(参数)
// 参数:obj 要做动画的元素对象;target 最终的目标位置
function animate(obj, target, callback) {
    // 先销毁定时器
    clearInterval(obj.timeID)

    // 开启一个定时器 setInterval()
    obj.timeID = setInterval(function() {

        if (obj.offsetLeft == target) {
            // 到达了目标位置,发出通知, 调用传过来的函数
            // 当 callback 不为 undefinded 的时候,才去调用 (利用逻辑中断构建单条件)
             // 回调函数写到定时器结束里面
            // if (callback) {
            //     // 调用函数
            //     callback();
            // }
            callback && callback()
                // 销毁定时器
            clearInterval(obj.timeID)
            return
        }
        // 缓动动画的步长 = (目标位置 - 当前位置) / 10 
        var step = (target - obj.offsetLeft) / 15

        // step 取整操作: 如果 step 步长大于 0, 采取向上取整;如果 step 步长小于 0,采取向下取整
        step = step > 0 ? Math.ceil(step) : Math.floor(step)

        // 设置盒子的 left = 当前盒子的位置 + 每次移动的距离 + px
        obj.style.left = obj.offsetLeft + step + 'px'
    }, 15)
}

二、案例:轮播图

1、js思路:

  1. 获取元素

  2. 鼠标经过焦点图,显示左右按钮,鼠标离开隐藏它

  3. 创建小圆圈,个数要和图片张数保持一致

  4. 点击小圆圈,让当前点击的小圆圈高亮,其他保持不变

  5. 点击小圆圈后,移动焦点图到指定的位置

  6. 排他思想设置小圆圈的过程抽取出来作为一个单独的函数

  7. 点击右侧按钮,播放下一张图片

  8. 实现一个无缝滚动(通过在 ul 最后添加一张图片)

  9. 播放对应的小圆圈

  10. 解决小圆圈的播放和按钮的播放不同步的问题

  11. 点击左侧按钮,播放上一张图片

  12. 自动播放轮播图(1.5s)

  13. 解决点击按钮播放速度过快的问题(上一张还没有播放完,下一张已经开始) 节流阀


document.addEventListener('DOMContentLoaded', function() {
    console.log(123);
    // 获取元素
    var focus = document.querySelector('.focus');
    var left = document.querySelector('.arrow-l');
    var right = document.querySelector('.arrow-r');
    var ul = document.querySelector('.slider');
    var ol = document.querySelector('.circle');
    // 获取focus的宽度, 也就是一张图片的宽度
    var w = focus.offsetWidth;
    var num = 0; //计数
    var flag = true; //增添节流阀
    // console.log(w);
    // console.log(focus, left, right, ul, ol);

    // 鼠标经过,左右侧按钮显示
    focus.addEventListener('mouseover', function() {
        left.style.display = 'block';
        right.style.display = 'block';
        // 鼠标进过,轮播图停止
        clearInterval(timeID);

    });

    // 鼠标经过,左右侧按钮隐藏
    focus.addEventListener('mouseout', function() {
        left.style.display = 'none';
        right.style.display = 'none';
        // 鼠标离开,轮播图开始
        clearInterval(timeID); //先清除之前
        timeID = setInterval(function() {
            right.click();
        }, 1000)
    });

    // 优化操作,将点击的小圆圈高亮抽取出来
    function setCircle(index) {
        // 利用排他思想将点击的小圆圈高亮
        for (var i = 0; i < ol.children.length; i++) {
            ol.children[i].className = '';
        }
        ol.children[index].className = 'current';
    }

    // 为ol添加li
    for (var i = 0; i < ul.children.length; i++) {
        var li = document.createElement('li');
        ol.appendChild(li);
        //  ol.innerHTML += "<li></li>";
        // 为ol中每个小li添加自定义属性index, 方便ul中图片的转换
        li.setAttribute('index', i);

        // 为li标签添加点击事件
        li.addEventListener('click', function() {

            // 获取ol中每个li对应的index值
            var index = this.getAttribute('index');
            setCircle(index);
            // 点击ol中li后,调用缓动动画函数,根据每个li对应的index值,ul移动相应的距离,显示对应的图片,注意向左移动应该是负值
            animate(ul, -index * w);
            // 解决小圆圈的播放和按钮的播放不同步的问题
            // 问题:先点击小圆圈再点击右侧按钮,图片播放的顺序会乱掉
            // 解决:每次去点击小圆圈时,把index值赋值给num,进行同步
            num = index;
        })
    }
    ol.children[0].className = 'current';

    // 为右侧点击按钮添加点击事件
    right.addEventListener('click', function() {
        // console.log(flag);
        // 每次点击之后,先判断当前阀门是否打开
        if (flag == false) {
            return; //当阀门关闭,终止函数
        }
        flag = false;
        // 判断当前是否播放到了最后这一张
        if (num == ol.children.length) {
            console.log('播放到最后一张');
            // 瞬间把ul拉到第一张图片位置
            ul.style.left = 0;
            // 将num重置为0
            num = 0;
        }
        // 播放下一张
        num++;
        // 调用缓动函数
        animate(ul, -num * w, function() {
            // 当动画结束后,将阀门打开
            flag = true;
        });
        // 播放小圆圈, num % ol.children.length,当到达最后这一张时,求余为0,调到第一张
        setCircle(num % ol.children.length);
        // num == 3 ? setCircle(0) : setCircle(num)

    })

    // 点击左侧按钮,播放上一张图片
    left.addEventListener('click', function() {
        // 每次点击之后,先判断当前阀门是否打开
        if (flag == false) {
            return; //当阀门关闭,终止函数
        }
        flag = false;
        // 判断当前是否播放到了第一张
        if (num == 0) {
            console.log('播放到第一张');
            // 将num重置为最后一张图片的索引
            num = ol.children.length;
            // 瞬间把ul拉到最一张图片位置
            ul.style.left = -num * w + 'px';

        }
        // 播放上一张
        num--;
        // 调用缓动函数
        animate(ul, -num * w, function() {
            // 当动画结束后,将阀门打开
            flag = true;
        });
        // 播放小圆圈, num % ol.children.length,当到达最后这一张时,求余为0,调到第一张
        setCircle(num % ol.children.length);
        // num == 3 ? setCircle(0) : setCircle(num)
    })
    // 克隆ul第一个li到末尾,目的:当ul移动到最后一张时,同时把ul位置重置到原始位置,使播放更加流畅
    var firstli = ul.children[0].cloneNode(true);
    ul.appendChild(firstli);

    // 自动播放轮播图,开启定时器(1.5s)
    var timeID = setInterval(function() {
        right.click(); //自动触发右击事件
    }, 1000)
})

2、节流阀

防止轮播图按钮连续点击造成播放过快。

节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。

开始设置一个变量var flag= true;

If(flag){flag = false; do something} 关闭水龙头

利用回调函数动画执行完毕, flag = true 打开水龙头

三、触屏事件

1、触屏事件概述

移动端兼容性相对较好,H5、C3都可以放心使用,不用考虑 IE 浏览器兼容性。

移动端事件是通过手指触发的,触屏事件 touch

touchstart 手指触摸到元素时触发 (mousedown)

​ touchmove 手指在元素上移动时触发 (mousemove)

​ touchend 手指离开元素时触发 (mouseup)

2、触摸事件对象

  • touchevent 事件对象主要属性
  1. targetTouches: 触摸当前元素的手指集合 (主要记住)
  2. touches:触摸屏幕的所有手指集合
  3. changedTouches: 当前元素上的触摸状态(从有到无,从无到有)发生变化时触发
  • 获取当前触摸手指的页面坐标

    ​ 横坐标:e.targetTouches[0].pageX

    ​ 纵坐标:e.targetTouches[0].pageY

  • 手指移动元素时防止整个页面进行滚动

    ​ 阻止事件默认行为, 添加 e.preventDefault()

3、案例:移动端的拖拽事件

 var box = document.querySelector('.box');
        var x, y;
        box.addEventListener('touchstart', function(e) {
            x = e.targetTouches[0].pageX - this.offsetLeft;
            y = e.targetTouches[0].pageY - this.offsetTop;

        })
        box.addEventListener('touchmove', function(e) {
            var left = e.targetTouches[0].pageX - x;
            var top = e.targetTouches[0].pageY - y;

            box.style.left = left + 'px';
            box.style.top = top + 'px';
            e.preventDefault();

        })

拓展:

屏幕可用工作区高度:window.screen.availHeight

屏幕可用工作区宽度:window.screen.availWidth

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱对恨错

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值