JS学习之—DOM(77~108)

187 阅读16分钟

DOM

文档document对象模型 image.png

111获取元素的方式

image.png

html,head,body非常规

直接获取的就是整个html文档页面最外层的dom节点(基于js动态计算rem) console.log(document.documentElement) 获取头部
console.log(document.head)

获取body
console.log(document.body)

常规

1.getElementById()

在文档中,获取一个元素来自id(括号里写id名)

标准方法,没有兼容性问题 console.log(document.getElementById())

变量法

 <div id="box">33333
        <ul>
            <li>222</li>
            <li>222</li>
            <li>222</li>
        </ul>
    </div>


    <ul>
        <li>222</li>
        <li>222</li>
        <li>222</li>
    </ul>

    <script>
    //获取box
    //这个只能改变box里文字,如果box里套了ul,则ul会被省略掉(不知为什么)
      var obox=document.getElementById("box")
      obox.innerHTML="11111"
</script>

2.getElementsByClassName(伪数组)

<div id="box">33333
    </div>

    <ul>
        <li class="newsitem">222</li>
        <li class="newsitem">222</li>
        <li class="newsitem">222</li>
    </ul>

    <script>
       var items =document.getElementsByClassName("newsitem")
        //是个伪数组,在控制台只是看着像数组,但是无法给数组附上数字的常用方法
        //但是特殊的:它有length这个属性。意思就是它可以当作一个对象来看
        //newsitem.innerHTML="123" 无效
        //但是这个可以按数组形式写,强制改变第一个索引内容
        items[0].innerHTML ="1234"
    </script>

但是如果你就是想把这个伪数组变成真数组,需要借助一个新变量,然后Array.from(伪数组)转成真的

这时候newitems就可以加数组的方法了

var newitems=Array.from(items)
        console,log(newitems)

3.getElementsByTagName可直接对标签设置(伪数组)

 var items =document.getElementsByTagName("li")
 console.log(items)

4.getElementsByName(伪数组)

 <input type="text" name="username">
    <button>111</button>
   <script>
    var item=document.getElementsByName("username")
    console.log(item[0])
    item[0].value="kerwin"//初始text
   </script>

呈现效果(会自动给它一个初始text)

联想截图_20231104131919.png 当然也可以直接给input设置value值

<input type="text" value="kerwin">


特殊的

(“”)写css选择器格式(id前记得写#)

5.querySelector(有兼容性问题可能)

只会返回一个对象,如果有多个,只能返回遇到的第一个

6.querySelectorAll(有兼容问题)

可以返回遇到的所有

image.png

222操作元素属性

分为 元素自带(原始)属性 自定义属性

一.操作原生属性

.innerHTML = ""改内容

.type = ""改属性

.src = ""

.........

二.操作自定义属性

不能直接给你的box这样设置tiechui的属性box.teichui = "22222"

应该

1.setAttribute 设置/修改

2.getAttribute 获取

3.removeAttribute 删除

用法例如:

        box.setAttribute("tiechui","2222")
        console.log(box.getAttribute("tiechui"))
        box.removeAttribute("tiechui")
        

4.还有一种h5新增的加自定义属性的方法 data-或dataset

写法1. data-

在html里写 image.png 获取方法(给出的是一个对象)

联想截图_20231104141324.png 写法2. dataset

直接在js里写,让它加在html上

联想截图_20231104141543.png 删除的话直接

image.png

密码可视案例

购物车全选案例

<input type="checkbox" id="allin">全选/全不选
    <hr />
    <ul class="shop">
        <li><input type="checkbox">city lights版</li>
        <li><input type="checkbox">candy版</li>
        <li><input type="checkbox">Bambi版</li>
        <li><input type="checkbox">cherry版</li>
    </ul>
    <script>
        var Oallin = document.querySelector("#allin")
        var Oitems = document.querySelectorAll(".shop input")
        //找input,而不是找li


        Oallin.onclick = function () {
            //console.log(Oallin.checked)
            //记得加.checked(说明获取了这个全选的checked)
            for (var i = 0; i < Oitems.length; i++) {
                Oitems[i].checked = Oallin.checked
            }
        }

        for(var i=0;i<Oitems.length;i++){
            Oitems[i].onclick=handler
        }
        //handler.function 写法错误
        function handler(){
            var count=0

            for(var i=0;i<Oitems.length;i++){
                if(Oitems[i].checked){
                    count++
                }
                if(count==Oitems.length){
                  
                  Oallin.checked=true
                }else{
                    Oallin.checked=false
                }
            }
        }

    </script>

333操作元素文本内容

当你获取完节点后,你需要往你的节点里放上文本或者标签

id.innerHTML

会得到整个部分 image.png

.innerText

只会得到文本信息,不解析html(也就是不会解析html里的标签)

.value

只适用于表单标签(像input之类的)

.value前不能写div的名字

渲染页面案例

444操作元素样式

1.获取行内样式的方法:style(可读可写)

1..style后面加的属性必须是你设置过的 console.log(box.style.width)

2. 如果这个属性有中间的连接符,就不能直接写在.style之后了,需要给它括上一个[“”]或者写成去掉连接符的驼峰式

console.log(box.style.["background-color"]) console.log(box.style.backgroundColor)

3. 还可以对你的css属性进行设置(可写)

直接赋值box.style.width = "200px",记得加引号

2.获取行内/内部/外部样式的方法:getComputedStyle(只可读,不能赋值写样式)

TIP:标准方法,有兼容性可能

(如果真的是低版本ie,就用obox.currentStyle.backgroundColor)

 var obox=document.getElementById("box")//先获取这个节点
        var res=getComputedStyle(obox)//这里不需要加引号,是一个函数
        console.log(res)   


//如果想拿到他的样式,直接在这个后面.属性就可以
        var res=getComputedStyle(box).height

555操作元素类名

我们的目的是实现这样的效果:高亮功能 QQ图片20231105110441.gif 而上面刚讲的那个方法只能单独设置某一个样式,如果我们的需求很多需要批量设置上面的就不再合适

TIP:这样可以既设置css,也设置js

<div id="box" class="item item2 item3"></div>

.className(可读可写)

但是这个属性没有甄别能力,不会自动去重

console.log(box.className)就可以读到你html里的box的id

写(暴力修改删除增加)box.className = "item item2" 这样直接给它重新赋值,就相当于把之前的item3删掉了

classList 得到的东西是数组

//读
      console.log(box.classList)
//增加。(但是如果不小心写重了,这个可以自动去重)
      box.classList.add("")
//删除(只能一个一个删)
      box.classList.remove("")
//切换 toggle (如果原来有就删掉,如果原来没有就加上)
      box.classList.toggle("")

选项卡案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="a选项卡.css">
    
    ______________________________________________
    <style>
    * {
    margin: 0;
    padding: 0;
}

ul {
    list-style: none;
}
.header{
    display: flex;
    width: 500px;
}
.header li{
    flex:1;
    height: 50px;
    line-height: 50px;
    text-align: center;
    flex:1 ;
    border: 1px solid black;
}
.box{
    position: relative;
}
.box li{
    position: absolute;
    left: 0;
    top: 0;
    width: 400px;
    height: 200px;
    background-color:antiquewhite;
    padding: 50px;
    display: none;
}
.header .active{
    background-color:aquamarine;
}
.box .active{
    display: block;
}
    </style>
</head>
_________________________________________________
<body>
    <ul class="header">
        <!-- 给第一个设置active让它高亮 -->
        <li class="active">英雄联盟</li>
        <li>DOTA</li>
        <li>风暴英雄</li>
        <li>300英雄</li>
    </ul>
<ul class="box">
    <li class="active">《英雄联盟》(League of Legends,简称LOL)是由美国拳头游戏(Riot Games)开发、中国内地由腾讯游戏代理运营的英雄对战MOBA竞技网游。游戏里拥有数百个个性英雄,并拥有排位系统、符文系统等特色系统。
         </li>
    <li>222</li>
    <li>《风暴英雄》 是由暴雪娱乐公司开发的一款运行在Windows和Mac OS上的在线多人竞技PC游戏。
        游戏中的英雄角色主要来自于暴雪四大经典游戏系列:《魔兽世界》、《暗黑破坏神》、《星际争霸》和《守望先锋》。它是一款道具收费的游戏,与《星际争霸Ⅱ》基于同一引擎开发。</li>
    <li><a href="https://300.jumpw.com/">300英雄</a></li>
</ul>
_______________________________________________________________
    <script>
        //获取
        var oHeaderItems = document.querySelectorAll(".header li")
        var oBoxItems = document.querySelectorAll(".box li")



        //给这个oHeaderItems部分里的每一个li(也就是这里的i)绑定onclick的事件
        for(var i=0;i<oHeaderItems.length;i++){

//这里需要注意的是"循环绑"的循环会瞬间执行完,所以你打印i的时候,并不能得到每个i事件的数字
//所以也就不能确定你点到的是哪一个

            //自定义属性data-index(会被加在每个li中)(让它不去获取i了,而是去获取自身属性)
            //为什么要这样,因为在你还没点之前,它就已经循环完了,所以你打印了只能显示个4
            oHeaderItems[i].dataset.index = i
           
            oHeaderItems[i].onclick = handler
        }
        //为了方便,易看,我们可以把上面onclick后的function单独在下面写(拆分)
        function handler(){
            console.log(this.dataset.index) //表示当前所点击的对象,可以在点击时得到相应的li
            var index = this.dataset.index


            for(var m=0;m<oHeaderItems.length;m++){
                //思路:先把他们的active全部删掉,再在每次点击的时候单独加上
                oHeaderItems[m].classList.remove("active")
                oBoxItems[m].classList.remove("active")
            }
            //这里再单独加上
            oHeaderItems[index].classList.add("active")
            oBoxItems[index].classList.add("active")
        }
    </script>
</body>
</html>

666DOM节点

分类:元素/文本/属性/注释节点

(“”)

attribute[0/1/...]全部(属性节点)

image.png

DOM节点
document根节点
html根元素节点
head/body/div/ul/...元素节点(可能是父元素也可能是子元素)
文本内容(切记:包括换行和空格)文本节点
元素属性(type...)属性节点
注释内容注释节点

获取节点的方法

childNodes属性(所有孩子节点)

vs

children(所有元素节点)


firstChild(第一个孩子节点)

vs

firstElementChild(第一个孩子元素节点)


lastChild(最后一个孩子节点)

vs

lastElementChild(最后一个孩子元素节点)


找上一个兄弟(哥哥节点)

previousSibling

vs

previousElementSibling


下一个(弟弟)

nextSibling

vs

nextElementSibling


这个区别不大

parentNode

vs

parentElement

操作DOM节点

image.png

创建一个节点

1. createElement:创建一个元素节点
 var odiv=document.createElement(`div`)
 //创建出来的就是一个可以使用的div元素
 //往里面放东西的话就是
 odiv.innerHTML=""

但是写到这里,这个div仍是无家可归,我们需要让它插到某个地方。

//(括号里都是对象,不是id)
//给box追加一个孩子(插入节点,追加)
box.appenChild(odiv)
//在某个之前插入(要插入的节点,在谁前面插入)
box.insertBefore(odiv,child)

可以给它正常加样式

联想截图_20231108151350.png

2.删除节点
//(括号里都是对象,不是id)
//删除节点(括号里是对象)
box.removeChild(child)
//删除自己以及后代
box.remove()
3.replaceChild(新的,老的)替换节点
var odiv2=document.creatElement("div")
odiv2.innerHTML="22222"
box.replaceChild(odiv2,child)
4.cloneNode()克隆节点

括号里面不写参数的话,默认false,不克隆后代

var oCloneBox = box.cloneNode()
//往页面里插入
document.body.appendChild(oCloneBox)

括号里写(true)就是克隆全部。 但是这样会造成因为完全克隆导致id相同

var oCloneBox = box.cloneNode(true)
oCloneBox.id="box2"
//往页面里插入
document.body.appendChild(oCloneBox)

动态删除案例

下面用到的这个方法相较于map的方法来说,绑事件更加方便,所以我们用这个

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
      <ul id="list">
            <!-- <li></li>
            <li></li>
            <li></li> -->
      </ul>
    <script>
      var arr=["111","222","333"]

      //循环遍历
      for(var i=0;i<arr.length;i++){
            //直接在这添加li
            var oli=document.createElement("li")
            oli.innerHTML=arr[i]

            //li是父节点,所以button应该放在li(oli)里
        
            var obutton = document.createElement("button")
            obutton.innerHTML="delete"
            //绑定一个事件
            obutton.onclick=handler
            //也就是在遍历每个i时,追加一个按钮在后面
            oli.appendChild(obutton)
            list.appendChild(oli)
      }
      function handler(){
            console.log(this)
            //用this可以避免用索引设置获取的麻烦
            this.parentNode.remove()
      }
    </script>
</body>
</html>

节点属性

找元素节点的方式:nodeType===数字 (可通过if循环找)

1为元素节点,2为属性节点,3为文本节点,8为注释节点

联想截图_20231108155802.png

联想截图_20231108155757.png

获取元素尺寸

就是元素的“占地面积”

image.png

offsetWith
offsetHeight

clientWidth
clientHeight

1.获取到的尺寸是没有单位的数字

2.如果元素display:none了,就获取不到了

3.box-sizing:border-box(设置什么宽高就是什么宽高,如果有边距就会挤压里面内容)正常使用

获取元素的偏移量(上下左右)

1. 相对于定位父级(遇到的第一个有定位的父级)

如果父级元素都没有定位,偏移量就相对于body

offsetTop
offsetBottom
offsetLeft
offsetRight

2. 其实计算的就是边框宽度

clientTop
clientBottom
clientLeft
clientRight

DOM获取可视窗口的尺寸

bom计算滚动条宽度,dom不计算 image.png

懒加载案例+另外一种渲染写法

document.documentElement.scrolltop获取滚动距离

如果是想要快到底的效果,就需要加一个isLoading。这样就不会频繁触发到底

 isLoading = false
 if(isLoading)return
            if(listHeight+listTop-Math.round(windowHeight+scrollTop)<100){
                console.log("快到底咯")
                isLoading = true
            }

一般就是

if(Math.round(windowHeight+scrollTop)===listHeight+listTop){
                console.log("到底咯")

完整代码

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .content {
            width: 500px;
            background-color: yellowgreen;
        }

        li {
            height: 150px;
            list-style: none;
            line-height: 30px;
        }

        li img {
            float: left;
            width: 100px;
        }
    </style>
</head>

<body>
    <!-- <div class="nav">
        <ul>
            <li>正在热映</li>
            <li>即将上映</li>
        </ul>
    </div> -->
    <div class="content">
        <ul id="list">
            <!-- <li></li>
        <li></li>
        <li></li> -->
        </ul>
    </div>

    <script>
        var filmList = [
            {
                url: "https://pic.maizuo.com/usr/movie/6f0850b4fc5e0ddfaac2e8146c23e21c.jpg?x-oss-process=image/quality,Q_70",
                title: "拯救嫌疑人",
                garde: "7.7",
                major: "张末 张小斐 李鸿其 惠英红 王子异",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6766e8827df785bbc5f9acc1efff8241.jpg?x-oss-process=image/quality,Q_70",
                title: "河边的错误",
                garde: "7.5",
                major: "魏书钧 朱一龙 曾美慧孜 侯天来 佟林楷",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/291ad328f0db1bb68a4386edbf3f3ab0.jpg?x-oss-process=image/quality,Q_70",
                title: "汪汪队立大功大电影2:超能大冒险",
                garde: "7.8",
                major: "卡尔·布伦克尔 天天 阿奇 莱德队长 贝贝",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6f0850b4fc5e0ddfaac2e8146c23e21c.jpg?x-oss-process=image/quality,Q_70",
                title: "拯救嫌疑人",
                garde: "7.7",
                major: "张末 张小斐 李鸿其 惠英红 王子异",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6766e8827df785bbc5f9acc1efff8241.jpg?x-oss-process=image/quality,Q_70",
                title: "河边的错误",
                garde: "7.5",
                major: "魏书钧 朱一龙 曾美慧孜 侯天来 佟林楷",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/291ad328f0db1bb68a4386edbf3f3ab0.jpg?x-oss-process=image/quality,Q_70",
                title: "汪汪队立大功大电影2:超能大冒险",
                garde: "7.8",
                major: "卡尔·布伦克尔 天天 阿奇 莱德队长 贝贝",
                region: "中国大陆|156分钟"
            }
        ]
        var filmList2 = [
            {
                url: "https://pic.maizuo.com/usr/movie/6f0850b4fc5e0ddfaac2e8146c23e21c.jpg?x-oss-process=image/quality,Q_70",
                title: "拯救嫌疑人",
                garde: "7.7",
                major: "张末 张小斐 李鸿其 惠英红 王子异",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6766e8827df785bbc5f9acc1efff8241.jpg?x-oss-process=image/quality,Q_70",
                title: "河边的错误",
                garde: "7.5",
                major: "魏书钧 朱一龙 曾美慧孜 侯天来 佟林楷",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/291ad328f0db1bb68a4386edbf3f3ab0.jpg?x-oss-process=image/quality,Q_70",
                title: "汪汪队立大功大电影2:超能大冒险",
                garde: "7.8",
                major: "卡尔·布伦克尔 天天 阿奇 莱德队长 贝贝",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6f0850b4fc5e0ddfaac2e8146c23e21c.jpg?x-oss-process=image/quality,Q_70",
                title: "拯救嫌疑人",
                garde: "7.7",
                major: "张末 张小斐 李鸿其 惠英红 王子异",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/6766e8827df785bbc5f9acc1efff8241.jpg?x-oss-process=image/quality,Q_70",
                title: "河边的错误",
                garde: "7.5",
                major: "魏书钧 朱一龙 曾美慧孜 侯天来 佟林楷",
                region: "中国大陆|156分钟"
            },
            {
                url: "https://pic.maizuo.com/usr/movie/291ad328f0db1bb68a4386edbf3f3ab0.jpg?x-oss-process=image/quality,Q_70",
                title: "汪汪队立大功大电影2:超能大冒险",
                garde: "7.8",
                major: "卡尔·布伦克尔 天天 阿奇 莱德队长 贝贝",
                region: "中国大陆|156分钟"
            }
        ]

        renderHTML(filmList)
       function renderHTML(arr) {
            list.innerHTML += arr.map(function (item) {
                return `<li>
                <img src="${item.url}">
                 <h3>${item.title}</h3>
                 <p>观众评分:${item.garde}</p>
                 <p>主演:${item.major}</p>
                <p>${item.region}</p>
                </li>`
            }).join("")
        }
        //但是到这里还不行,因为你这个map映射到页面中会自动转成字符串,所以每个之间就会有,连接
        //所以这里用到join属性


        //这种方式可以避免页面加载一页闪了一下
        /*function renderHTML(filmList){
        for(var i=0;i<filmList.length;i++){
            var oli = document.createElement("li")
            oli.innerHTML =`<li>
                <img src="${item.url}">
                 <h3>${item.title}</h3>
                 <p>观众评分:${item.garde}</p>
                 <p>主演:${item.major}</p>
                <p>${item.region}</p>
                </li>
                `
                list.appendChild(oli)
        }
    }*/







        isLoading = false
        //ul
        window.onscroll = function () {
            var listHeight = list.offsetHeight
            var listTop = list.offsetTop

            console.log(listHeight + listTop)
            //有兼容性问题
            var scrollTop = document.documentElement.scrollTop ||
                document.body.scrollTop

            var windowHeight = document.documentElement.clientHeight
            console.log(Math.round(windowHeight + scrollTop))//看是否到底
           
           
          
            if (isLoading) return
            if (listHeight + listTop - Math.round(windowHeight + scrollTop) < 50) {
                console.log("快到底咯")
                isLoading = true
                  //干正事了,渲染下一页
            //(上面map那里要改成+=,不然渲染下一页的时候会直接覆盖上一页)
            //renderHTML(filmList2)
            //但是跟后端要数据会稍微慢一点,所以我们这样写
                setTimeout(function () {
                renderHTML(filmList2)
                isLoading=false//下一次到底事件继续触发
            }, 1000)
            
            }

        
          
        }
       
    </script>
</body>

</html>

事件

image.png

绑定方式

dom0绑定方式

用dom0绑事件就必须加on

如果再次绑定,会被新的覆盖

 var oDiv=document.querySelector(`div`)
        oDiv.onclick=function(){
            //执行代码
        }

dom2 可以绑定多个,按顺序执行

有兼容,低版本6,7,8不行 box.attachEvent("onclick",function(){})

   //给box绑了一个事件处理器
        box.addEventListener("click",function(){
            console.log("111111")
        })//click是事件类型
          box.addEventListener("click",function(){
            console.log("222222")
        })
          box.addEventListener("click",function(){
            console.log("333333")
        })
        

事件解绑

原来用的是这个禁用属性,但是前端完全可以在检查中把disabled属性去掉

btn.onclick=function(){
            console.log("谢谢惠顾")
            //this拿到的是这个按钮
            this.disabled="disabled"
        }

dom0解绑

dom节点.onclick=null

 btn.onclick=function(){
            console.log("谢谢惠顾")
            
            this.onclick=null
        }

dom2解绑

兼容性btn.detachEvent("onclick",handler)在事件里写

这里我们用一下封装函数

两把钥匙,都指向一个function房间(同一个回调函数)

  function handler(){
        console.log("谢谢惠顾")
       }
       btn.addEvenListener("click",handler)
       btn.removeEventListener("click",handler)

事件类型

浏览器事件/鼠标事件/键盘事件/表单事件/触摸事件

浏览器事件

load页面全部资源加载完毕

scroll浏览器滚动的时候触发

鼠标事件

click点击事件

dblclick双击事件

contextmenu右键单击事件(常用于自定义右键菜单)

mousedown鼠标左键按下事件(按下就没有反悔的机会了,即刻触发)

mouseup鼠标左键抬起事件

mousemove鼠标移动

mouseover mouseout移入移出(孩子也会触发)

mouseenter mouseleave移入移除(孩子不会触发)

键盘事件

比如你按下回车键就可以提交,不一定非要按按钮,所以可以给键盘绑一个事件

keyup键盘抬起事件

keydown键盘按下事件

keypress键盘按下再抬起事件

表单事件

focus获取焦点

blur失去焦点

(可用于你输入完离开时,判断你输入的内容是否符合要求)

  <input type="text" id="username">
    <script>
     username.onfocus=function(){
        console.log("获取焦点")
     }
     username.onblur=function(){
        console.log("失去焦点")
     }
    </script>

change表单内容改变事件(前提是:在获取焦点与失去焦点的对比里面内容不一样才会触发)

input表单内容输入事件(每次内容不一样都触发,也就是每打一个字就触发)


这个的 前提 是body里必须有表单结构

<form action=""></form>

与上面那些给单独的input绑之外,这个不一样,因为是form要提交,form要重置,所以给form绑

submit表单提交事件(默认跳转,马上提交)

而我们如果需要对内容判断,就要想阻止它马上提交,用return false就可以

reset重置

触摸事件(只针对移动端)

touchstart触摸开始事件

touchend触摸结束事件

touchmove触摸移动事件

touchcancel

事件对象

联想截图_20231109204455.png

event,其实就是一个形参

鼠标事件

联想截图_20231109205709.png

鼠标跟随案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        #box{
            width: 200px;
            height: 50px;
            background-color: yellow;
            position: relative;
        }
        #box p{
            width: 300px;
            height: 200px;
            background-color: aquamarine;
            position: absolute;
            left: 100px;
            top: 100px;
            display: none;
            /* 法二 */
            /* 穿透,也就是鼠标放上去之后也不会到p标签上 
            “鼠标事件”*/
            pointer-events: none; 
        }
    </style>
</head>
<body>
    <div id="box">
        kerwin头像
        <p>kerwin头像kkk</p>
    </div>
    <script>
        box.onmouseover=function(){
            this.firstElementChild.style.display="block"
        }
        box.onmouseout=function(){
            this.firstElementChild.style.display="none"
        }
        box.onmousemove=function(evt){
            console.log(evt.offsetX,evt.offsetY)
// 法一,可以直接再加50距离(不太规范,但是可行)
            this.firstElementChild.style.left=evt.offsetX+"px"
            this.firstElementChild.style.top=evt.offsetY+"px"
        }
    </script>
</body>
</html>

鼠标拖拽案例

这个的问题是,当你点击鼠标的时候,box会马上移动,使你的鼠标在你写的这个左上角,但是我们其实想让鼠标点上之后一直处于中间

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 100px;
            height: 100px;
            background-color: aquamarine;
            position:absolute;
        }
    </style>
</head>
<body>
    <div id="box"></div>
    <script>
        box.onmousedown=function(){
            document.onmousemove=function(evt){
            //这里的问题!!!!!!!!
                box.style.left=evt.clientX+"px"
                box.style.top=evt.clientY+"px"
            }
        }
        box.onmouseup=function(){
            document.onmousemove=null
        }
    </script>
</body>
</html>

应该改成这样

box.onmousedown=function(){
            document.onmousemove=function(evt){
                var x=evt.clientX-box.offsetWidth/2
                var y=evt.clientY-box.offsetHeight/2
                box.style.left=x+"px"
                box.style.top=y+"px"
            }
        }

因为

联想截图_20231109231821.png 但是现在还存在的问题是你这个box如果移动到边距处,它会出去,所以我们加一个if判断

当y<=0时,给y赋值0,那么box就不会出去了

 box.onmousedown=function(){
            document.onmousemove=function(evt){
                var x=evt.clientX-box.offsetWidth/2
                var y=evt.clientY-box.offsetHeight/2


                if(y<=0)y=0
                if(x<=0)x=0
                if(x>=document.documentElement.clientWidth-
                box.offsetWidth)x=document.documentElement.clientWidth-
                box.offsetWidth
                if(y>=document.documentElement.clientHeight-
                box.offsetHeight)y=document.documentElement.clientHeight-
                box.offsetHeight

                
                box.style.left=x+"px"
                box.style.top=y+"px"
            }
        }

还有一种方法

这样可以避免嵌套,也可以不用事件解绑

 isDown=false
        box.onmousedown=function(){
           isDown=true
        }
        box.onmouseup=function(){
            //这种写法就不用写这个解绑了
            //document.onmousemove=null
            isDown=false
        }


        document.onmousemove=function(evt){
            if(!isDown)return
                var x=evt.clientX-box.offsetWidth/2
                var y=evt.clientY-box.offsetHeight/2


                if(y<=0)y=0
                if(x<=0)x=0
                if(x>=document.documentElement.clientWidth-
                box.offsetWidth)x=document.documentElement.clientWidth-
                box.offsetWidth
                if(y>=document.documentElement.clientHeight-
                box.offsetHeight)y=document.documentElement.clientHeight-
                box.offsetHeight

                
                box.style.left=x+"px"
                box.style.top=y+"px"
            }

DOM事件的传播

image.png

image.png

阻止事件传播

这里我们用的案例是动态删除,我们想做到的效果是:在你点前面的li文字时可以跳转页面,再点击后面按钮时可以删除

但是如果你此时只给li绑一个onclick事件,你点了删除之后依然会跳转,这是因为冒泡触发,所以我们需要再在下面加一个阻止传播

image.png

有低版本ie有兼容问题,具体修改方案看千锋视频p105

阻止默认行为(有校验的需求时)

之前我们在表单提交那里用过这个return false

1.dom0,这个没有兼容性

image.png

2.dom2,有兼容

image.png

右键自定义菜单

事件委托

优点: 减少多个函数的绑定的性能损耗;动态添加li,也会有事件处理

给孩子做的事,给父亲做,可以不用每一个孩子一个一个做

但是我们该如何知道是点了哪个孩子呢 image.png

target是触发事件的人

image.png

dom0写法

<body>
    <ul>
        <li>111111
            <button>add</button></li>
    </ul>
    <script>
        list.onclick=function(evt){
            console.log(evt.target)
        }
    </script>
</body>

这种方法,我们结合上面右键自定义菜单就可以实现,点哪个就知道是哪个,即

image.png

低版本ie兼容性,在事件中要写成或的形式

image.png