JS中一些经常遇到的错误

无法给动态创建的元素绑定事件,通过事件委托解决

瀑布流效果

<style type="text/css"></style>
    <script>
        let df = document.createDocumentFragment()
            for (let i = 1; i < 43; i++) {
                let oDiv = document.createElement("div")
                oDiv.classList.add("item")
                oDiv.innerHTML = `<img src='./images/img (${i}).jpg'/>`
                df.appendChild(oDiv)
            }
            document.body.appendChild(df)
    </script>
</head>

Uncaught TypeError: Cannot read properties of null (reading 'appendChild')

原因:

script在头部,html文件还未解析到body.所以目前无法获取到document.body(null),所以没办法在空属性上添加元素

造成下图效果的原因

let df = document.createDocumentFragment()
            for (let i = 1; i < 43; i++) {
                let oDiv = document.createElement("div")
                oDiv.classList.add("item")
                oDiv.innerHTML = `<img src='./images/img (${i}).jpg'/>`
                df.appendChild(oDiv)
            }
            document.body.appendChild(df)

            let oItems = document.querySelectorAll(".item")
            let oArr = []
            oItems.forEach((item,index)=>{
                console.log(item.offsetHeight);
            })
            oItems.forEach((item, index) => {
                if (index < 3) {
                    oArr[index] = item.offsetHeight
                } else {
                    item.style.position = 'absolute'
                    let minIndex = getMinIndex(oArr)
                    item.style.left = minIndex * item.offsetWidth + 'px'
                    item.style.top = oArr[minIndex] + 'px'
                    oArr[minIndex] = oArr[minIndex] + item.offsetHeight
                }
            })

console.log(item.offsetHeight); -->31

为什么会是31?

div已经创建好了,但是里面的img还没有加载出来,所以这是div的自带样式高度,以及未加载完成的图片的高度,所以都是31px,所以导致这种局面

解决方案:

DOMContentLoaded 页面结构加载完成就触发

window.onload 页面结构加载完成,外部的src也要加载完成-

window.addEventListener("DOMContentLoaded", () => {
            let df = document.createDocumentFragment()
            for (let i = 1; i < 43; i++) {
                let oDiv = document.createElement("div")
                oDiv.classList.add("item")
                oDiv.innerHTML = `<img src='./images/img (${i}).jpg'/>`
                df.appendChild(oDiv)
            }
            document.body.appendChild(df)
        })
        
        window.onload = () => {
            let oItems = document.querySelectorAll(".item")
            let oArr = []
            oItems.forEach((item,index)=>{
                console.log(item.offsetHeight);
            })
            oItems.forEach((item, index) => {
                if (index < 3) {
                    oArr[index] = item.offsetHeight
                } else {
                    item.style.position = 'absolute'
                    let minIndex = getMinIndex(oArr)
                    item.style.left = minIndex * item.offsetWidth + 'px'
                    item.style.top = oArr[minIndex] + 'px'
                    oArr[minIndex] = oArr[minIndex] + item.offsetHeight
                }
            })
        }

        function getMinIndex(arr) {
            return arr.findIndex(item =>  item == Math.min(...arr))
        }

Ajax的同步与异步

如果是Ajax的同步,在点击按钮的时候,移动的盒子会停顿,直到服务器把数据传给浏览器,盒子才继续移动

使用利用Ajax的异步来解决这个问题

<button id="btn">click</button>
        <div class="mes">xxxx</div>
        <script>
                function createXHR() {
                    if (window.XMLHttpRequest) {
                        return new XMLHttpRequest()
                    }
                    return ActiveXObject("Msxml2.XMLTTP")
                }
                function ajax(url) {
                // function ajax(url,callback) {
                    //得到xhr核心对象
                    let xhr=createXHR()
                    //准备请求参数
                    xhr.open('get',url)//第三个参数不写,默认为true 异步
                    //发送请求
                    xhr.send(null)
                    xhr.onreadystatechange=function(){
                        if (xhr.readyState==4&&xhr.status==200) {
                            return xhr.response
                        }
                    }
                    //设置监听的事件,所有的事件都是小写
                }
                //调用Ajax
                document.querySelector('#btn').onclick=function(){
                    let res=ajax('http://useker.cn/getusers')
                    console.log(res);
                }

                let oMes=document.querySelector(".mes")
                setInterval(()=>{
                    oMes.style.left=oMes.offsetLeft+10+'px'
                    if (oMes.offsetLeft>document.documentElement.clientWidth) {
                        oMes.style.left=0
                    }
                },100)
        </script>

为什么第28行console.log(res)打印的结果是undefined

首先在ajax方法中xhr.onreadystatechange=function(){}这个事件,只是将一个匿名函数function(){}赋给xhr的

onreadystatechange事件,内部代码在ajax这个方法中并不会执行,在第27行调用ajax方法,按理会把实参带入ajax方法中执行内部代码,但是onreadystatechange是一个事件,事件是异步的,只有当事件被触发的时候才会执行内部代码,我们不知道事件会在什么时候执行,所以ajax内部的同步代码顺序执行,跳过异步事件

xhr.onreadystatechange=function(){

if (xhr.readyState==4&&xhr.status==200) {

return xhr.response

}

}

到第24行结束ajax方法,执行第28行console.log(res);由于没有执行事件,在ajax方法中函数并没有return,所以打印的是undefined,而可能在打印之后在执行xhr的事件,获取到res的值

解决方法:

利用回调函数解决异步

回调函数会在事件执行完后返回数据

作用类似:A找B借钱,但是B此时没钱,过了一段事件B有钱了,再找B借钱就是另外一件事件了,如果A在B没钱的时候给B一张卡,让B有钱的时候就往卡里打钱,这样就还是一个事件,并且解决了时间的问题,所以回调函数就类似这里的银行卡

function ajax(url,callback) {
                    //得到xhr核心对象
                    let xhr=createXHR()
                    //准备请求参数
                    xhr.open('get',url)//第三个参数不写,默认为true 异步
                    //发送请求
                    xhr.send(null)
                    //设置监听的事件,所有的事件都是小写
                    xhr.onreadystatechange=function(){
                        //如如果状态发生变化,就在这里判断状态
                        if (xhr.readyState==4&&xhr.status==200) {
                            callback(xhr.response)
                        }
                    }
                }
                //调用Ajax
                document.querySelector('#btn').onclick=function(){
                    ajax('http://useker.cn/getusers',function(res){
                        console.log(res);
                    })
                }

闭包

//5个button
let oBtns=document.querySelectorAll("button")
                for (var i = 0; i < oBtns.length; i++) {
                    oBtns[i].onclick=function(
                      {
                        console.log(i)
                      }
                      }

打印的i永远是5,因为点击事件是异步的,所以永远等待同步代码for循环执行结束后再执行,此时的i为5,

可以使用let/const关键字代替var关键字,或者提前将i的值存储起来,或者使用高阶函数,或者闭包

let oBtns=document.querySelectorAll("button")
  for (let i = 0; i < oBtns.length; i++) {
    oBtns[i].onclick=fn(i)
    }
  function fn(n) {
   return function (e) {
   for (let i = 0; i < oBtns.length; i++) {
  oBtns[i].style.backgroundColor=''
  }
 oBtns[n].style.backgroundColor='green'
 }
  }

在oBtns[i].onclick=fn(i)中,fn(i)会立即执行,不受点击事件影响,放回第6行的函数,这个函数将在点击事件执行的时候触发执行,这个函数的事件e是点击事件,它的this指向事件触发对象OBox

节流

oBox.onmousemove=throttle(function (e) {
            console.log('zhouhaha');
        },2500)
        function throttle(callback,delay=500) {
            let startTime=Date.now()
            return function (e) {
                let currentTime=Date.now()
                if (currentTime-startTime>=delay) {
                    startTime=currentTime
                    callback.bind(this)(e)
                }
            }
        }

防抖

oBox.onmousemove=debounce(function(e){
                    console.log('zhouhaha');
                },2500)
                function debounce(callback,delay) {
                    let timer
                    return function(e){
                        let self=this
                        clearTimeout(timer)
                        timer=setTimeout(function () {
                            callback.bind(self)(e)
                        },delay)
                    }
                }

动态属性

checked selected disabled ed结尾的都是动态属性

动态属性不能用attribute(attr)操作,要使用property(prop)操作

attr 如果未设置或者删除就无法获取

$(function () {
//     $('button').eq(0).click(function () {
//         $(":input").attr('checked',true)
//     })
//     $('button').eq(1).click(function () {
//         console.log($('input:checkbox').attr('checked'));
//     })
//     $('button').eq(2).click(function () {
//         $('input:checkbox').removeAttr('checked')
//     })
// })
    $(function () {
      $('button').eq(0).click(function () {
         $(":input").prop('checked',true)
       })
      $('button').eq(1).click(function () {
          console.log($('input:checkbox').prop('checked'));
       })
       $('button').eq(2).click(function () {
            $('input:checkbox').removeProp('checked')
       })
   })

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值