javaScript开发中的细节

314 阅读7分钟

前言:为了能够加深和方便以后查阅,自己记录了一些我在开发中遇到的各种千奇百怪的bug和问题。 格言:即使代码虐我千万遍,我依旧带它如初恋。 留步:如我写的有不对的地方或者你有更好的解决方法,欢迎留言纠正。

javaScript开发中的细节

top变量在全局中声明报错

在全局中声明top变量会报错,是因为top已经在window中定义过,属于关键字系列。

let top = "无法使用";
console.log(top);
// Uncaught SyntaxError: Identifier 'top' has already been declared

onload事件只执行一次

定义一个onload事件后,该事件在页面中只会执行一次,你之后再多次调用onload事件是不会在去执行的了。

window.onload = function () {
   console.log("只执行一次")
}

js中获取不到图片宽高

在js中获取图片标签的宽高,你获取的宽高值却一直都是0。

  • 原因:因为在游览器中图片标签的渲染是异步执行的,在你通过js获取图片宽高的时候,图片在这时候是还没有加载出来的。

  • 解决:只需要在页面加载完毕之后在去执行获取图片标签宽高的代码块,定义代码块在onload事件中执行,如下

window.onload = function () {
   let imgW = imgObj.offsetWidth; // 获取宽高
}

淘宝放大镜效果中鼠标移动时小块出现闪动

在做图片放大镜效果时,通过event.offsetX获取鼠标在元素中移动时鼠标相对图片元素的坐标值后,黄色标记显示在的鼠标的下方。在这里出现了一个问题,就是当鼠标移动的时候,黄色标记会时不时的出现闪动。

  • 原因:当你鼠标在元素中移动的时候,获取的鼠标坐标是相对于该元素的位置,而这里是根据冒泡原理中的event.target来判定鼠标是相对那个元素的坐标值。于是当你鼠标不小心移动到黄色标志上的的时候,这时获取的鼠标坐标值就是相对于黄色标记的坐标值,而不是相对图片元素的坐标值了。可以想象一下,你开始相对元素的坐标是(230,50),突然变成了(20,5),当然会出现闪动的效果了。

  • 解决:我们可以通过event.pageX & event.pageY获取鼠标相对文档的坐标值,用这个坐标值减去图片的offsetLeft & offsetTop值,就可以得到鼠标相对于这个元素的坐标值。

let imgX = event.pageX - imgObj.offsetLeft;  // left坐标
let imgY = event.pageY - imgObj.offsetTop; // top坐标

js设置图片宽高没有效果

场景:假设在你的css样式中你可能已经设置过了图片标签的宽高,你想根据父级的宽高通过js动态生成图片的宽高,而在js中你是通过图片的属性来设置图片的宽高的。

问题:在你设置上了图片属性的宽高之后,图片实际宽度还是你在样式中设置的宽高。

原因:样式中设置值的优先级高于属性中设置值,就是说属性中设置的宽高会被样式中设置的宽高覆盖掉,最后只显示样式的宽高。

解决:以后js设置标签样式是尽量全部用style来设置值。

// 操作如下
imgObj.style.width = 100+'px';

我遇到的场景bug,是在做图片放大镜效果中,通过比例设置右侧图片的绝对定位时,图片放大的位置老是不对,最后找到的就是这个原因。bug往往藏在于细节之中,这种bug找到后还得不到成就感,真是毙了豆豆了,开发中还是得细心呀。

可视窗口大小发生改变时重复执行很多次代码

产生问题的场景

做瀑布流效果时,在onload事件发生时,js中会重复执行多次更改图片显示的列数和重新设置图片的定位。

产生问题的原因

部分游览器是当你正在更改窗口大小的时候就会触发onload事件,而不是当你窗口大小改变完成之后才触发onload事件,所以在你拖动窗口变化时,会重复执行很多次你定义的代码块。

我解决的办法

我是用延时器来解决的,就是当你的窗口大小发生改变时,触发事件后,你定义一个延时器,让其在150ms之后,再去执行你所定义的代码块。这里有个小细节,你要在每次进去执行的时候,先清除掉你定义的延时器。这样做的好处就是当用户一直在拖动窗口发生改变时,你的功能代码块还是一次都没有去执行的。这是因为用户持续改变窗口大小时,还没有到达时间延时器就已经被清除了。

下面就是我解决问题的最终代码啦。

// 窗口大小改变重新设置所有图片的定位
this.timeOut = '';  // 唯一标识符要定义在全局中,方便清除掉
window.onresize = () => {
    // 定义延时器,窗口改变150ms后执行,防止窗口在改变中多次执行函数体
    clearTimeout(this.timeOut); // 先清除
    this.timeOut = setTimeout(() => {
        imgPlace(); // 需要执行的功能代码
        clearTimeout(this.timeOut); // 清除
    }, 150)
}

懒加载中,快到达底部时没加载指定数量的图片

产生问题的场景

在懒加载功能中,监听滚动条快滑动到底部的时候,把指定数量的图片追加到最后面,而我这里每次快到达底部时都会加载指定数量图片的几倍出来。

产生问题的原因

onscroll滚动事件中,每次滚轮滑动的距离都是不同的,当你每滚动一次,事件就会触发一次。当滚动的距离大于你设定的条件时,还会触发多次滚动事件,就像刹不住车一样,有时刚刚好触发一次,有时又触发很多次,这样就太不可控了。

我解决的办法

用延时器来解决,用延时器延时执行要更改的状态。先在全局定义个默认状态为false,到达底部的条件后把状态更改为true,把图片追加到容器后面。定义延时器,500ms之后把状态更改为false。在到达底部条件之后,在500ms之前你滚动多少次,都不会在执行后面的语句了。

这样子就会在下次滑动到达底部时,500ms时间已过,条件已经更改为false了,这时就又能够执行后面的语句了。

具体怎么操作呢,看我下面的代码。

/**
我这里的代码是在class类里面定义的,下面的是我的部分代码,主要代码部分我用多行注释符注释出来了。
**/

/*首先定义一个是否到达底部的状态,默认没有到达底部,重点就是状态的更改时机*/
this.nextState = false; 

// 鼠标滚动事件
document.onscroll = this.scrollFn.bind(this);

// 执行函数鼠标滚动快到底部的时候在加载10张图片出来
scrollFn() {
        /*判断到达底部没,到达了就直接return,不去执行下面的代码了*/
    if (this.nextState) return;
    // 可视区的高
    let clientH = window.innerHeight || window.clientHeight;
    // 获取最后一张图片距离顶部的高
    let imgNextTop = this.img[this.img.length - 1].offsetTop;
    // 封装的方法,获取滑动的距离
    let scrollH = this.getscrollTop(); 
    // 条件:最后图片的顶部距离-可视区的高
    let nextIf = imgNextTop - clientH;

    // 滚动距离到达底部之后加载图片
    if (scrollH > nextIf) {
        /* 更新状态为true,已经到达底部 */
        this.nextState = true;

        /* 定义延时器500ms之后更改到达底部状态为false,解决滚动重复追加图片 */
        let timeout = setTimeout(() => {
            this.nextState = false;
            clearTimeout(timeout);
        }, 500)

        // 到达最底部之后再次加载15张图片,不能超过120张
        if (this.img.length < 120) {
            for (let i = 1; i <= 15; i++) {
                // 封装的追加图片节点函数
                this.createNode(i + 1);
            }
            // 重新设置所有图片的位置
            this.imgPlace(); // 封装的方法
        }
        else {
            document.onscroll = ''; // 清除滚动事件
            alert('已经到达底部啦,滚动事件已被清除')
        }
    }
}

最后我想说

在之后开发中遇到的bug和细节问题我都会把它添加到这篇博客里面来,方便记忆和后期看一看以前的那个自己,留个深刻的记忆。 回不去的永远是青春呀。