JavaScript-0824

发布于:2023-01-05 ⋅ 阅读:(488) ⋅ 点赞:(0)
1、解构赋值
    用于简化变量赋值
    1、对象解构
        let {属性名称1:别名,属性名称2} = 对象
        一旦解构完成,可以直接使用变量
    2、数组解构
        let [变量1,变量2...] = 数组
        数组解构存在顺序问题
2、展开与合并运算符
    形参使用...表示合并,将多个数据合并为一个数组 其他的位置表示展开
3、对象简写
    当属性名称与变量名称同名 可以省略一个
    let  obj = {
        //msg:msg
        msg,
        //fn:function(){}
        fn(){}
        //fn:()=>{}
    }
4this指向
    1this当函数调用时系统会自动设置来表示调用函数的对象(箭头函数除外)2、箭头函数中this  箭头函数没有this,可以从上下文中继承使用
    3、修改this指向
        都是可以修改函数中this指向的,但是call与apply两个方法 可以将函数调用起来,但是在调用函数时所传递的参数形式不一样,call方法第一个参数表示修改的this对象 后续其他参数 表示函数的传递参数。apply方法 第一个参数表示要修改this对象。第二个参数 要求是数组 并且是按照顺序 逐个传递
        bind方法 会修改this指向但是 不会调用函数 调用bind方法返回的结果是一个新的函数
5JSON
    就是数据交互格式,JSON格式是字符串
    JSON.parse()JSON格式的字符串转换为内置的数组或者对象,一旦格式不是JSON格式 就会报错
    JSON.stringfiy 将内置数组或者对象转换为JSON格式的字符串
6、检查类型
    Object.prototype.toString.call(变量) 
7、深浅拷贝
    浅拷贝  直接赋值 一个变量修改 影响到另外一个变量
    深拷贝  使用其他方式 保证两个变量直接相互不影响
8、伪数组转换真数组
    Array.from()    

typora-root-url: img

动画概述

平常见到的动画是一帧一帧的构成,每一帧都是一个静止状态。当快速的将每一帧组合起来 就形成了一个连续动

画。使用js实现动画最核心最关键的就是使用定时器反复修改元素的状态。一般是修改一些数值类型的状态,例如

宽度、高度、透明度、left等

运动函数

简单运动

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        div {
            width: 100px;
            height: 100px;
            background-color: green;
            position: absolute;
            top: 0;
            left: 0
        }
    </style>
</head>

<body>
    <div></div>
    <script src="common.js"></script>
    <script>
        let timer;
        document.querySelector('div').onclick = function () {
            // this.style.left = '300px'
            timer = setInterval(() => {
                // 获取现在的left值  此次使用箭头函数 this从上面继承 表示div的dom对象
                let currentStyle = parseInt(getStyle(this, 'left'));
                if (currentStyle == 300) {
                    clearInterval(timer)
                } else {
                    this.style.left = currentStyle + 5 + 'px'
                }

            }, 10);
        }
    </script>
</body>

</html>

简单运动封装函数

/**
 * 简单运动函数
 * @param {Document} elem 运动元素的dom对象
 * @param {String} attr 运动的样式名称
 * @param {Number} target 运动的目标
 */
function singleSport(elem,attr,target){
    let timer = setInterval(() => {
        // 获取现在运动样式值
        let currentStyle = parseInt(getStyle(elem, attr));
        if (currentStyle == target) {
            clearInterval(timer)
        } else {
            elem.style[attr] = currentStyle + 5 + 'px'
        }
    }, 10);
}

多属性运动封装

/**
 * 多属性运动
 * @param {Document} elem 
 * @param {Object} options  要求使用属性名称表示样式名称 属性值表示终止点
 */
function moreAttrSportV1(elem, options) {
    // 使用一个定时器控制多个样式的运动。所以在定时器中需要控制到每次执行能够同时修改需要运动样式的值
    let timer = setInterval(() => {
        for (let key in options) {
            let current = parseInt(getStyle(elem, key));
            console.log(key+'属性运动,当前样式:'+current)
            if (current == options[key]) {
                // 判断已经达到目标
                // 目前可能是多个样式需要修改,所以只有等到所有的样式全部运动完毕 才可以停下定时器
                // 只有执行这个if判断满足 就证明现在运动的样式已经达到了目标 就不需要在参与到定时器中实现修改
                delete options[key];
                // clearInterval(timer);
                // 判断options中是否存在元素 如果没有元素。就证明所有的样式运动就结束
                Object.keys(options).length == 0 && clearInterval(timer);
            } else {
                
                elem.style[key] = current + 5 + 'px';
            }
        }
    }, 10)
}

运动不均匀问题

原因

由于有top与left两个样式运动,但是两个样式的目标值不一样,但是每次运行的速度是一样(5px),导致其中一个先执行完毕,后续还会继续执行另外一个样式的修改

解决方案

一定要保证不论存在多少个样式需要修改,都能够同时到达目标
1、计算速度
	可以假设 1秒完成整个动画 只需要计算出速度就可以  使用距离/时间 = 速度
2、使用百分比计算,每次执行剩余距离的百分之10
	例如 top需要从0 运行到1000px
    第一次运行 距离 100px top = 100px 剩余 900px
    第二次运行 距离 90px top = 190px 剩余 810px
    第三次运行 距离 81px  top = 271px 剩余 729px
    ....
    最终会发现 可以无限接近 但是又不能到达

使用百分比方式解决

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QFtenIfm-1661338578332)(/1661311375607.png)]

解决到达终点问题

1、问题分析

left从0运动到400px
当前运行到381.95px,根据计算公式(400-381.95)*0.05 = 0.95,所以定时器中会执行修改操作,但是浏览器中单位以px为单位。计算出的数字小于1 所以浏览器放弃了修改操作

2、解决

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NbzIbyM1-1661338578333)(/1661321393710.png)]

解决反向运动问题

1、问题的演示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9StnyMuq-1661338578333)(/1661321545866.png)]

2、结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTOde8pK-1661338578334)(/1661321559503.png)]

3、分析原因

目标0  当前19px 按照公式(0-19)*0.05=-0.95 ,将结果向上取整 0 所以没有任何的修改

4、修复

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gydnQzr3-1661338578335)(/1661321869581.png)]

透明度问题

1、透明度只有0-1之间的小数,在运动过程中 值会非常小。
2、每次执行修改操作都会添加px单位导致错误

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PrRwbI6q-1661338578336)(/1661322814800.png)]

运动结束

1、修改函数增加参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f3W1A0iF-1661338578336)(/1661323622315.png)]

2、运动执行完毕后

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6CXsuDg-1661338578337)(/1661323640101.png)]

3、调用函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mXhP7Phh-1661338578337)(/1661323708286.png)]

解决多次调用运动函数的问题

如果一个动画还未执行完毕 可能在该元素上继续触发执行另外一个动画,就可以能导致 运动抖动

/**
 * 多属性运动 多次调用问题
 * @param {Document} elem 
 * @param {Object} options  要求使用属性名称表示样式名称 属性值表示终止点
 * @param {Function} callback 回调的函数
 */
 function animate(elem, options,callback) {
    //  当每次在同一个元素上触发动画时需要将原有的动画清除
    elem.timer && clearInterval(elem.timer);
    elem.timer = setInterval(() => {
        for (let key in options) {
            // 获取当前的样式值 如果样式是透明度 就将值放大1000倍
            let current = (key == 'opacity') ? parseFloat(getStyle(elem, key) * 1000) : parseInt(getStyle(elem, key));
            // 针对目标放大1000倍
            let target = (key == 'opacity') ? options[key] * 1000 : options[key];
            let speed = (target - current) > 0 ? Math.ceil((target - current) * 0.05) : Math.floor((target - current) * 0.05);
            if (current == target) {
                // 判断已经达到目标
                delete options[key];
                if(Object.keys(options).length == 0){
                    clearInterval(elem.timer);
                    // 判断传递的参数如果是函数 就可以调用函数
                    Object.prototype.toString.call(callback) == '[object Function]' && callback();
                }
            } else {
                if (key == 'opacity') {
                    elem.style[key] = (current + speed) / 1000;
                } else {
                    elem.style[key] = current + speed + 'px';
                }

            }
        }
    }, 10)
}

轮播图

功能分析

无缝轮播图功能实现起来需要在图片本身前后分别来添加图片.一旦显示到最后一个图片之后,立马将图片定位到

显示原本的第一个图片

1、根据现有图片li标签创建小圆点

2、针对图片的li标签前后进行追加

3、实现自动切换图片(小圆点也需要跟着改变)

4、鼠标划入划出 控制自动画图的暂停与开始

5、小圆点的点击事件 需要更换为对应的图片

代码实现轮播图

创建小圆点

1、获取到相关的dom对象

// 1、获取到一些使用的dom对象
    const wrapDom = document.querySelector('.wrap');
    const leftDom = document.querySelector('.left');
    const rightDom = document.querySelector('.right');
    const dotBarDom = document.querySelector('.dotBar');
    const slideBarDom = document.querySelector('.slideBar');
    // 获取到轮播图的宽度
    const wrapWidth = wrapDom.clientWidth;

2、创建小圆点

// 2、根据图片的个数创建小圆点
function createDot() {
for (let i = 0; i < slideBarDom.children.length; i++) {
    let liDom = document.createElement('li');
    // 如果是第一个小圆点 就需要额外的增加特殊样式
    i == 0 && (liDom.className = 'active')
    dotBarDom.appendChild(liDom)
}
}
createDot();

追加图片

// 3、追加图片
    function createLiTag() {
        // 在最后一张图片后追加第一个图片,  第一个图片前追加最后一个图片(注意 先克隆 后面在追加)
        // 克隆第一个li标签
        let firstLiClone = slideBarDom.firstElementChild.cloneNode(true);
        // 克隆最后一个li标签
        let lastLiClone = slideBarDom.lastElementChild.cloneNode(true);
        // 将克隆的第一个li加入到末尾
        slideBarDom.appendChild(firstLiClone);
        // 将最后一个加入到前面
        slideBarDom.insertBefore(lastLiClone, slideBarDom.firstElementChild);
        // 修改slideBarDom的left值控制 默认显示原本的第一个图片
        slideBarDom.style.left = -wrapWidth + 'px'

    }
    createLiTag();

自动切换图片

1、创建全局变量保存数据

// 4、自动切换图片
// 保存自动轮播的定时器标识
let timer;
// index表示现在显示的7张图片的序号 index的范围只有0-6
let index = 1;

2、创建自动切换的函数

// 自动切换图片函数
    function autoPlay() {
        timer = setInterval(() => {
            index++;
            move();
        }, 3000);
    }

3、实现move函数

// 每次切换图片的处理函数
    function move() {
        // 修正index的值
        // 如果现在的index为7,上一次index为6 
        if (index > slideBarDom.children.length - 1) {
            index = 2;
        }
        // 小圆点跟随
        // 先将所有小圆点上的特殊样式取消
        for (let i = 0; i < dotBarDom.children.length; i++) {
            dotBarDom.children[i].className = '';
        }
        let activeIndex;
        /*
            index的取值范围为0-6 有7张图片  小圆点 只有5个
            index = 0  显示的第1张图 原图为5 activeIndex = 4;
            index = 1  显示的第2张图 原图为1 activeIndex = 0;
            index = 2  显示的第3张图 原图为2 activeIndex = 1;
            index = 3  显示的第4张图 原图为3 activeIndex = 2;
            index = 4  显示的第5张图 原图为4 activeIndex = 3;
            index = 5  显示的第6张图 原图为5 activeIndex = 4;
            index = 6  显示的第7张图 原图为1 activeIndex = 0;
        */
        if (index == 0) {
            activeIndex = 4;
        } else if (index == 6) {
            activeIndex = 0;
        } else {
            activeIndex = index - 1;
        }
        dotBarDom.children[activeIndex].className = 'active';
        // 修改为下一张图片
        animate(slideBarDom, {
            left: -index * wrapWidth
        }, playEnd);
    }
    

4、处理回调

// 动画执行完毕的回调
function playEnd() {
    if (index == slideBarDom.children.length - 1) {
        index = 1;
        // 动画执行完毕之后瞬间拉回前面的图片
        slideBarDom.style.left = -index * wrapWidth + 'px'
    }
}
autoPlay();

划入划出暂停与继续

// 5、划入划出暂停与继续
wrapDom.addEventListener('mouseover',()=>{
    clearInterval(timer);
})
wrapDom.addEventListener('mouseout',()=>{
    autoPlay();
})

左右箭头切换

1、绑定点击事件

// 6、左右箭头切换
    rightDom.addEventListener('click', function () {
        index++;
        move();
    })
    leftDom.addEventListener('click', function () {
        index--;
        move();
    })

2、修改move方法处理上一张图片的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BHBkDfEz-1661338578338)(/1661333306901.png)]

3、修改playEnd 拉回图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jwu9vNmo-1661338578338)(/1661333330305.png)]

小圆点点击切换

1、增加序号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PMIihiel-1661338578339)(/1661333901188.png)]

2、绑定点击事件

// 使用事件委托 绑定小圆点的点击事件
dotBarDom.addEventListener('click', (event) => {
if (event.target.nodeName == 'LI') {
    // 获取到当前点击小圆点的序号
    let dataIndex = event.target.getAttribute('data-index');
    // 修改index  在切换图片
    index = dataIndex - 0 + 1;
    console.log(index);
    move();
}
})

swiper

官网:https://www.swiper.com.cn/index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="./swiper-5.4.5/package/css/swiper.min.css">
    <script src="./swiper-5.4.5/package/js/swiper.min.js"></script>
    <style>
        html,
        body {
            position: relative;
            height: 100%;
        }

        body {
            background: #eee;
            font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
            font-size: 14px;
            color: #000;
            margin: 0;
            padding: 0;
        }

        .swiper-container {
            width: 100%;
            height: 100%;
        }

        .swiper-slide {
            text-align: center;
            font-size: 18px;
            background: #fff;

            /* Center slide text vertically */
            display: -webkit-box;
            display: -ms-flexbox;
            display: -webkit-flex;
            display: flex;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            -webkit-justify-content: center;
            justify-content: center;
            -webkit-box-align: center;
            -ms-flex-align: center;
            -webkit-align-items: center;
            align-items: center;
        }
    </style>
</head>

<body>
    <div class="swiper-container">
        <div class="swiper-wrapper">
            <div class="swiper-slide">Slide 1</div>
            <div class="swiper-slide">Slide 2</div>
            <div class="swiper-slide">Slide 3</div>
            <div class="swiper-slide">Slide 4</div>
        </div>
        <div class="swiper-pagination"></div>
        <div class="swiper-button-prev"></div>
        <div class="swiper-button-next"></div>
    </div>
    <script>
        var swiper = new Swiper('.swiper-container', {
            direction: 'vertical',
            loop: true,
            pagination: {
                el: '.swiper-pagination',
            },
            navigation: {
                nextEl: '.swiper-button-next',
                prevEl: '.swiper-button-prev',
            },

        });
    </script>
</body>

</html>
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到