01-认识DOM
JavaScript是一门编程语言,它的运行环境有两个,一个是浏览器,一个是node,前面我们学的JS必于ECMAScript中的语法,浏览器的JS有三部分组成:
- ECMAScript
- DOM
- BOM
01-document对象
<!-- document 文档 html文档 -->
<script>
console.log(document); // document代表整个文档
console.log("------------");
console.log(document.documentElement); // 得到html元素
console.log("------------");
console.log(document.body); // body元素
console.log("------------");
console.log(document.head); // head元素
console.log("------------");
console.log(document.doctype); // 文档声明
</script>
02-节点介绍
// 元素节点
// 文本节点
// 属性节点 // 在DOM树上没有属性节点
// 注释节点
// 换行节点
// 节点就是对象,操作节点就是操作对象
03-节点关系
节点关系一
-
获取到一个节点(Node)后,可以根据这个节点去获取其他的节点,我们称之为节点之间的关系
-
父节点:parentNode
-
前兄弟节点:previousSibling
-
后兄弟节点:nextSibling
-
子节点:childNodes
-
第一个子节点:firstChild
-
最后一个子节点:lastChild
<!-- 我是一个注释 --> 我是一个文本 <div class="box"> 我是一个孤独的DIV </div> <ul> <li>One</li> <li>Two</li> <li>Three</li> </ul> <script> // 获取body的元素节点 let bodyEle = document.body; console.log(bodyEle.firstChild); // 子 #text 换行节点 console.log(bodyEle.firstChild.nextSibling); // 兄弟 注释 console.log(bodyEle.parentNode); // 父 html </script> // 通过节点关系去获取某些节点,非常麻烦,因为需要考虑换行节点和注释节点
节点关系二
-
获取到一个节点(Node)后,可以根据这个节点去获取其他的节点,我们称之为节点之间的关系
-
父节点:parentElement
-
前兄弟节点:previousElementSibling
-
后兄弟节点:nextElementSibling
-
子节点:children
-
第一个子节点:firstElementChild
-
最后一个子节点:lastElementChild
<body> <!-- 我是一个注释 --> 我是一个文本 <div class="box"> 我是一个孤独的DIV </div> <ul> <li>One</li> <li>Two</li> <li>Three</li> </ul> <script> let bodyEle = document.body; console.log(bodyEle.firstElementChild); console.log(bodyEle.firstElementChild.nextElementSibling); // 得到一个伪数组 console.log(bodyEle.firstElementChild.nextElementSibling.children); </script> </body>
02-获取元素节点的方法
// ID是唯一的,getElementById获取的是唯一元素
// 即使ID值一样,也只会得到第1个元素
// console.log(document.getElementById("box1")); // 拿box1
// 伪数组
// let divs = document.getElementsByTagName("div"); // 通过标签名
// console.log(divs);
// 判断一个数据是否是真数组
// console.log(Array.isArray(divs)); // false
// console.log(Array.from(divs)); // 把伪数组转成真数组
// console.log(Array.isArray(Array.from(divs))); // true
// console.log(divs[0]); // 第一个div
// console.log(divs[1]); // 第二个div
// querySelectorAll里面放选择器 选择器和css选择器是一样的
// let divs = document.querySelectorAll("#box1"); // 所有box1的选择器
// console.log(divs);
// console.log(Array.isArray(divs)); // false
// console.log(Array.from(divs)); // 变成真数组
let li = document.querySelector("li") // 第一个li
console.log(li);
03-元素节点的属性
结构:下同
01-nodeType
- commentNode.nodeType 8
- textNode.nodeType 3
- elementNode.nodeType 1
02-nodeName和tagName
- nodeName:获取node节点的名字;
- tagName:获取元素的标签名词;
tagName 和 nodeName 之间有什么不同呢?
- tagName 属性仅适用于 Element 节点;
- 对于元素来说,nodeName与 tagName 的意义相同,所以使用哪一个都是可以的;
03-innerHTML
// 获取div标签中的内容
console.log(divNode.innerHTML); // <h2>...</h2> <p>...</p>
// 设置div标签中的内容
divNode.innerHTML = "<strong>我是一个Strong标签</strong>"
04-outerHTML
// 获取div标签中的内容 outerHTML相比innerHTML来说,带上自己本身div
console.log(divNode.outerHTML); // <div> <h2>...</h2> <p>...</p> </div>
// 对于设置来说,使用innerHTML多一点
divNode.outerHTML = "<strong>我是一个Strong标签</strong>"
05-textContent
// 只能获取文本节点
console.log(divNode.textContent); // 我是一个H2 我是内容
// 设置也是针对文本节点,如果写了标签,也不会解析
divNode.textContent = "<strong>我是一个Strong标签</strong>";
06-nodeValue
-
用于获取非元素节点的文本内容
// 获取注释节点中的内容 console.log(commentNode.nodeValue); // 我是一个注释 // 获取文本节点中的内容 console.log(textNode.nodeValue); // 我是文本 // 元素节点的nodeValue是null console.log(divNode.nodeValue); // null
07-hidden
-
用于设置元素隐藏
<button id="btn">Toggle</button> // Toggle切换 <div class="box" style="color: red;"> Hello DOM~ </div> <script> let btn = document.getElementById("btn"); let div = document.getElementsByTagName("div")[0]; // console.log("start..."); // 给btn绑定点击事件 btn叫事件源 click叫点击事件(事件类型) // function(){} 事件处理程序,也叫监听器 // 事件绑定是异步任务,是宏任务 btn.onclick = function(){ // console.log("click..."); // 隐藏div // div.style.display = "none"; // 隐藏方式一 // div.hidden = true; // 隐藏方式二 // if(div.hidden === false){ // div.hidden = true; // }else{ // div.hidden = false; // } // 经典 div.hidden = !div.hidden } // console.log("end..."); </script>
04-创建和挂载节点
- 先创建后挂载 创建节点:
- createElement 创建元素节点
- createTextNode 创建文本节点
- createComment 创建注释节点
- createAttribute 创建属性节点
挂载节点:
-
node.append(...nodes or strings) —— 在 node 末尾 插入节点或字符串,
-
node.prepend(...nodes or strings) —— 在 node 开头 插入节点或字符串,
-
node.before(...nodes or strings) —— 在 node 前面 插入节点或字符串,
-
node.after(...nodes or strings) —— 在 node 后面 插入节点或字符串,
-
node.replaceWith(...nodes or strings) —— 将 node 替换为给定的节点或字符串。
<div class="father"> <div class="son"> SON </div> </div> <script> // 创建对象 let father = document.querySelector(".father"); // 使用innerHTML也可以添加元素,不推荐 // father.innerHTML = "<h2>我是一个H2标签</h2>"; let h2Ele = document.createElement("h2"); // 添加元素 h2Ele.textContent = "我是H2标签"; // 给H2添加文本节点 console.log(h2Ele); // 页面中没有h2 // 需要把h2挂载到DOM树上 father.append(h2Ele); // father.prepend(h2Ele) // father.before(h2Ele) // father.after(h2Ele) // father.replaceWith(h2Ele) let spanEle = document.createElement("span"); spanEle.textContent = "我是一个孤独的span"; h2Ele.append(spanEle) </script>
05-删除、替换、克隆节点
结构:
<div class="father">
<div class="son">
son
</div>
</div>
01-删除节点
-
removeChild 只有父元素才有资格删除一个子元素
-
remove 移除元素我们可以调用元素本身的remove方法:
// 想要做什么事,先把节点拿到 let father = document.querySelector(".father"); let son = document.querySelector(".son"); // son.remove, 自己移除自己 // son.remove(); // 父也有能力去移除它里面的元素 father.removeChild(son)
02-替换节点
-
replaceChild
let father = document.querySelector(".father"); let son = document.querySelector(".son"); let pEle = document.createElement("p"); pEle.textContent = "GrandSon"; father.replaceChild(pEle,son) // 用pEle去替换son
03-克隆节点
-
可以传入一个Boolean类型的值,来决定是否是深度克隆;
-
深度克隆会克隆对应元素的子元素,否则不会;
let father = document.querySelector(".father"); let son = document.querySelector(".son"); // 默认是浅copy 只copy一个节点,内部的其它节点不会copy // let newFather = father.cloneNode(); // console.log(newFather); // 如果传递一个true表示深copy 如果不传或传一个false表示浅copy let newFather = father.cloneNode(true); console.log(newFather);
06-属性节点操作
01-属性节点操作之atrribute
attribute的分类(标准、非标准)
- 标准的attribute:某些attribute属性是标准的,比如id、class、href、type、value等;
- 非标准的attribute:某些attribute属性是自定义的,比如abc、age、height等;
- attrbute是HTML标签中的属性
对于所有的attribute访问都支持如下的方法:
-
elem.hasAttribute(name) — 检查特性是否存在。
-
elem.getAttribute(name) — 获取这个特性值。
-
elem.setAttribute(name, value) — 设置这个特性值。
-
elem.removeAttribute(name) — 移除这个特性。
-
attributes:attr对象的集合,具有name、value属性;
<div class="father" title="hehe" score="88" id="box"> <div class="son" abc="abc" age="18"> son </div> </div> <script> // 先拿到节点 let boxEle = document.querySelector("#box"); // 所有的盒子 // 可以判断标准的、也可以判断非标准的 // console.log(boxEle.hasAttribute("class")); // true // console.log(boxEle.hasAttribute("title")); // console.log(boxEle.hasAttribute("name")); // 标准 // console.log(boxEle.hasAttribute("score")); // 非标准 // 通过Attribute的属性名,获取属性值 // console.log(boxEle.getAttribute("class")); // 设置Attribute // boxEle.setAttribute("adress","bj") // 删除Attribute // boxEle.removeAttribute("title") // 得到所有的Attribute console.log(boxEle.attributes); </script>
02-属性节点操作之property## (打点拿属性)
-
property是对象obj里的属性(name,age)
let obj = { name:"wc", age:18 }
在大多数情况下,它们是相互作用的
-
改变property,通过attribute获取的值,会随着改变;
-
通过attribute操作修改,property的值会随着改变;
-
建议使用property 默认情况下有类型
<div class="father" title="hehe" score="88" id="box"> <div class="son" abc="abc" age="18"> son </div> </div> <input type="text" class="ipt" value="我是默认值"> <hr> <!-- checked="checked" --> <input type="checkbox" class="ipt2"> <script> let boxEle = document.querySelector("#box"); let iptEle = document.querySelector(".ipt") let iptEle2 = document.querySelector(".ipt2") // obj是对象 对象是属性(property)的无序集合 // 所谓的property就是对象的中的属性 // let obj = { // name:"wc", // age:18 // } // boxEle.setAttribute("title","xixi"); // 改变了attribute // console.log(boxEle.title); // property // boxEle.title = "heihei"; // 改变了propety // console.log(boxEle.getAttribute("title")); // iptEle.setAttribute("value","lala") // iptEle.value = "hehe" // 建议使用property console.log(iptEle2.checked); // 默认情况下有类型 console.log(iptEle2.getAttribute("checked")); // null </script>
-
通过property设置数据时,优先级是高于attribute
<div class="father" id="abc" title="hehe" age="18" score="88"> 我是一个DVI </div> <!-- <input type="checkbox" checked="checked"> --> <input type="checkbox" checked> <hr> <input type="text" class="account"> <button class="btn">设置input的值</button> <script> // 拿div let divEle = document.getElementById("abc"); console.log(divEle.getAttribute("id")); console.log(divEle.getAttribute("age")); console.log("-----------------"); console.log(divEle.id); // property // 对于非标准的attribute 是没有 对应的property console.log(divEle.age); // undefined console.log("-------------------"); let iptEle = document.getElementsByTagName("input")[0]; // 拿到input框 // if(iptEle.getAttribute("checked")){ // attrbute // console.log("处于选中状态"); // } if(iptEle.checked){ // property console.log("处于选中状态"); } console.log(typeof iptEle.checked); // 类型boolean console.log("-------------------"); let iptEle2 = document.getElementsByTagName("input")[1]; // 通过标签名拿输入框 let btnEle = document.getElementsByClassName("btn")[0]; // 通过class拿<button> btnEle.onclick = function(){ // 通过property设置数据时,优先级是高于attribute iptEle2.value = "66666"; // 通过property来设置 iptEle2.setAttribute("value",88888); // 通过attribute来设置 } </script>
04-H5中的自定义属性
-
以data-打头的,叫html5中的自定义属性
<div class="father" age="18" data-score="88" data-address="bj"> 我是一个孤独的DIV </div> <script> // 拿属性 let boxEle = document.querySelector(".father"); console.log(boxEle.dataset); // 收集所有的自定义属性 data开头的 console.log(boxEle.dataset.score); console.log(boxEle.dataset.address); </script>
07-动态操作样式
01-操作class和style
元素的class attribute,对应的property并非叫class,而是className
<style>
.active{
color: red;
font-size: 30px;
background-color: gold;
}
</style>
</head>
<body>
<div class="box">
我是一个box
</div>
<script>
let boxEle = document.querySelector(".box");
boxEle.onclick = function(){
// 1)操作行内样式 style
// boxEle.style.color = "red";
// boxEle.style.fontSize = "30px";
// boxEle.style.backgroundColor = "gold";
// 2)操作class类
// class的attribute 对应的 property是 className
boxEle.className = "active"
}
</script>
02-操作class
<style>
.active{
color: red;
font-size: 30px;
background-color: gold;
}
</style>
</head>
<body>
<div class="box">
我是box
</div>
<button>切换</button>
<script>
let boxEle = document.querySelector(".box");
// 把人家本身的覆盖掉了
// boxEle.className = "active"
// boxEle.classList.add("active") // 添加一个类
// boxEle.classList.remove("box") // 添加/移除类
// 点击
let btn = document.getElementsByTagName("button")[0];
btn.onclick = function(){
// boxEle.classList.add("active")
// boxEle.classList.toggle("active") // 没有就添加类,有就移除类
console.log(boxEle.classList.contains("box")); // 判断有没有包含某个类 返回true和false
}
</script>
03-操作stlye
-
对于内联样式,是可以通过style.*的方式读取到的
-
对于style、css文件中的样式,是读取不到的
-
通过getComputedStyle的全局函数来实现
<div class="box" style="background-color: gold; color: white;"> 我是一个孤独的DIV </div> <script> let boxEle = document.querySelector(".box"); // 获取 console.log(boxEle.style.backgroundColor); console.log(boxEle.style.color); // 设置 // boxEle.style.fontSize = "30px" // boxEle.style.color = "red" // 使用cssText 了解 boxEle.style.cssText = "background-color: pink; font-size:30px; color:red;"; </script>
08-深入事件
事件 + 事件的反馈 = 前端交互(前端的核心)
01-鼠标事件
- onclick 点击事件 = onmousedown + onmouseup
- ondbclick 双击事件
- onmousedown 鼠标按下去
- onmouseup 鼠标抬起来
- onmouseover 鼠标移到某元素上面
- onmouseout 鼠标离开某元素上面
- onmousemove 鼠标在元素上面的移动
02-键盘事件
- onkeydown 键盘按下去
- onkeyup 键盘抬起来
- onkeypress 键盘抬住
keydown与keypress区别:
- keydown按任意键都触发;keypress按字符键(1234..)才触发,像alt、ctrl、shift等不会触发
03-加载事件
-
load 加载 浏览器不仅加载完成了 HTML,还加载完成了所有外部资源,像图片、css。 事件源是window
-
unload 加载 退出页面 此事件不好捕获到 也没有什么用
-
DOMContentLoaded:浏览器已完全加载 HTML,并构建了 DOM 树,但像 img 和样式表之类的外部资源可能尚未加载 完成。
<script> // 当网页中所有的资源全部加载完毕,会触发load事件 // 事件源是window // window.onload = function () { // let btn = document.getElementById("btn"); // let img = document.getElementsByTagName("img")[0]; // console.log(btn); // console.log(img); // 可以加载所有资源,图片、css // } // DOMContentLoaded 当HTMLDOM元素加载完毕就触发 // 不会等到页面中其它的资源加载完毕 window.addEventListener("DOMContentLoaded",function(){ let btn = document.getElementById("btn"); console.log(btn); }) </script> <body> <button id="btn">登录</button> <img src="https://img1.baidu.com/it/u=592570905,1313515675&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" alt=""> </body>
04-表单事件
- focus: 获取焦点
- blur: 失去焦点
- change: 改变输入框中的内容,并失去焦点时触发
- input:内部发生变化,立即触发,不等到失去焦点
- submit: 当点击了提交按钮,会触发submit事件
- reset: 当点击了重置按钮,会触发reset事件
05-其他事件
- resize: 改变了浏览器窗口大小时,会触发resize事件
- scroll: 页面滚动时,会触发scroll事件
06-HTML级别的事件绑定
可以在HTML开始标签上,去绑定事件,这种绑定基本不用
<!-- button叫事件源 click叫事件类型 -->
<!-- ()必须加,不加不行 -->
<button onclick="fn()">点我</button>
<script>
function fn(){
console.log("fn...");
}
</script>
07-DOM0的事件绑定
DOM0事件绑定,就是给DOM元素的onxxxx属性赋值,是基于属性赋值的操作
<style>
.loading{
background-color: #ccc;
color: #424242;
outline: 0px;
border: none;
}
</style>
</head>
<body>
<button id="btn">加载更多</button>
<script>
let btn = document.getElementById("btn");
// onclick 本质就是属性 property
// DOM0的事件绑定,是基于属性赋值的,不能绑定多个监听器
// 绑定多个会打印出后边,因为后边的会覆盖前面
// btn.onclick = function(){
// console.log("onclick1...");
// }
btn.onclick = function(){
// console.log("onclick2...");
this.textContent = "加载中...";
// this.className = "loading";
this.classList.add("loading"); // 加载load类
let that = this; // that表示btn
setTimeout(function(){
console.log(this); // this表示window
that.textContent = "加载更多"
that.classList.remove("loading")
},2000)
}
</script>
<script>
let btn = document.getElementById("btn");
btn.onclick = function(){
this.textContent = "加载中...";
this.classList.add("loading");
// 如果是箭头函数
setTimeout(()=>{
// 如果是箭头函数,this就正常了
this.textContent = "加载更多"
this.classList.remove("loading")
},2000)
}
</script>
08-DOM0的事件和HTML级别事件绑定的优先级
DOM0的事件绑定 优先级 高于HTML级别的事件绑定
<style>
.loading{
background-color: #ccc;
color: #424242;
outline: 0px;
border: none;
}
</style>
</head>
<body>
<button id="btn" onclick="test()">加载更多</button>
<script>
function test(){
console.log("HTML级别的事件绑定");
}
let btn = document.getElementById("btn");
// DOM0的事件绑定 优先级 高于HTML级别的事件绑定
btn.onclick = function(){
console.log("DOM0的事件绑定");
}
</script>
09-DOM2的事件绑定
-
DOM2的事件绑定 是基于事件池的 可以绑定多个监听器
-
两次点击事件,绑定同一个监听器。当点击时,监听器只出触发一次
<style> .loading{ background-color: #ccc; color: #424242; outline: 0px; border: none; } </style> </head> <body> <button id="btn">加载更多</button> <script> let btn = document.getElementById("btn"); // DOM2的事件绑定 是基于事件池的 可以绑定多个监听器 btn.addEventListener("click",function(){ // Event事件 Listener监听器 // console.log("click1..."); this.innerHTML = "加载中..." this.className = "loading"; // 两秒之后加载更多 箭头函数 setTimeout(()=>{ this.innerHTML = "加载更多" this.className = ""; },2000) }) // btn.addEventListener("click",function(){ // console.log("click2..."); // }) </script> <script> let btn = document.getElementById("btn"); // 能不能两次点击事件,绑定同一个监听器? // 答:可以的 function fn(){ console.log("我是一个监听器..."); } // 表示两次点击事件,绑定同一个监听器 // 当点击时,监听器只出触发一次 // 一般情况下只会绑定一个 btn.addEventListener("click",fn) btn.addEventListener("click",fn) </script>
10-DOM2的事件解绑
<style>
button{
outline: none;
border: none;
width: 100px;
height: 30px;
background-color: red;
color: #fff;
text-align: center;
line-height: 30px;
}
.got{
background-color: #ddd;
}
</style>
</head>
<body>
<button id="btn">领取优惠劵</button>
<script>
let btn = document.getElementById("btn");
btn.onclick = function(){ // DOM0级别的事件绑定
this.innerHTML = "已领取";
this.className = "got" // 加上got类
console.log("已领取");
// 解绑
this.onclick = null; // 点一下,再点就点不动了
}
</script>
11-DOM的事件解绑
<style>
button {
outline: none;
border: none;
width: 100px;
height: 30px;
background-color: red;
color: #fff;
text-align: center;
line-height: 30px;
}
.got {
background-color: #ddd;
}
</style>
</head>
<body>
<button id="btn">领取优惠劵</button>
<script>
let btn = document.getElementById("btn");
function fn(){
this.innerHTML = "已领取";
this.className = "got"
console.log("已领取");
// 监听器执行完毕后才可以解绑
btn.removeEventListener("click",fn);
}
btn.addEventListener("click", fn)
</script>
-
第二种写法:
<button id="btn">领取优惠劵</button> <script> let btn = document.getElementById("btn"); btn.addEventListener("click", function fn() { this.innerHTML = "已领取"; this.className = "got" console.log("已领取"); // 监听器执行完毕后才可以解绑 btn.removeEventListener("click", fn); }) </script>
12-事件传播
- 1)从里向外传播 冒泡传播 需要掌握 默认的
- 2)从外向里传播 捕获传播 基本上用不到
DOM0的事件绑定,只能冒泡,不能捕获
<style>
.wraper{
width: 300px;
height: 300px;
background-color: green;
}
.outer{
width: 200px;
height: 200px;
background-color: gold;
}
.inner{
width: 100px;
height: 100px;
background-color: orchid;
}
</style>
</head>
<body>
<div class="wraper">
<div class="outer">
<div class="inner"></div>
</div>
</div>
<script>
let wraper = document.getElementsByClassName("wraper")[0]; // getElements要加0
let outer = document.getElementsByClassName("outer")[0];
let inner = document.getElementsByClassName("inner")[0];
// 点击inner,事件会传播,传播方向?
// 1)从里向外传播 冒泡传播 需要掌握 默认的
// 2)从外向里传播 捕获传播 基本上用不到
// DOM0的事件绑定,只能冒泡,不能捕获
wraper.onclick = function(){
console.log("wraper...");
}
outer.onclick = function(){
console.log("outer...");
}
inner.onclick = function(){
console.log("inner...");
}
</script>
-
使用DOM2的事件绑定 默认也是冒泡
-
addEventListener可以接收第三个参数
-
如果第三个参数不写或为false表示冒泡
-
如果第三个参数为true表示捕获
// 结构同上 使用DOM2的事件绑定 默认也是冒泡 wraper.addEventListener("click",function(){ console.log("wraper..."); }) outer.addEventListener("click",function(){ console.log("outer..."); }) inner.addEventListener("click",function(){ console.log("inner..."); }) addEventListener可以接收第三个参数 如果第三个参数不写或为false表示冒泡 如果第三个参数为true表示捕获 wraper.addEventListener("click",function(){ console.log("wraper..."); },true) outer.addEventListener("click",function(){ console.log("outer..."); },true) inner.addEventListener("click",function(){ console.log("inner..."); },true)
-
如果有捕获 也有 冒泡,先进行捕获,后进行冒泡
wraper.addEventListener("click",function(){ console.log("捕获 wraper..."); },true) outer.addEventListener("click",function(){ console.log("捕获 outer..."); },true) inner.addEventListener("click",function(){ console.log("目标 inner..."); },true) wraper.addEventListener("click",function(){ console.log("冒泡 wraper..."); },false) outer.addEventListener("click",function(){ console.log("冒泡 outer..."); },false) inner.addEventListener("click",function(){ console.log("目标 inner..."); },false)
13-阻止事件冒泡
-
通过事件对象来阻止冒泡
-
event对象中,有很多事件发生时的信息。浏览器帮你创建的,如:事件类型 鼠标点击的位置
// 样式同 12-事件传播 <script> let wraper = document.getElementsByClassName("wraper")[0]; let outer = document.getElementsByClassName("outer")[0]; let inner = document.getElementsByClassName("inner")[0]; DOM2阻止事件冒泡 wraper.addEventListener("click",function(event){ // 浏览器调的函数 console.log("wraper..."); console.log(event); }) outer.addEventListener("click",function(){ console.log("outer..."); }) inner.addEventListener("click",function(){ console.log("inner..."); // 阻止事件冒泡 event.stopPropagation(); }) DOM0阻止事件冒泡 wraper.onclick = function(event){ console.log("wraper..."); } outer.onclick = function(event){ console.log("outer..."); } inner.onclick = function(event){ console.log("inner..."); event.stopPropagation(); // stopPropagation阻止冒泡,写inner里 因为冒泡是从里往外 } </script>
14-阻止默认事件
- 鼠标右键默认事件
- a标签默认事件
- form表单默认事件
利用preventDefault或return false去阻止
-
DOM2的事件绑定,只能使用e.preventDefault();来阻止默认事件
<!-- a标签有默认事件 --> <!-- 如果给a标签绑定了事件,绑定的事件也会触发 --> <a href="http://www.abc.com">我是一个孤独的A标签</a> <!-- form表单也有默认的提交事件 submit事件 --> <!-- action表示把表单提交到什么地方 --> <form action="http://www.abc.com"> <input type="text"> <br> <input type="submit"> </form>
-
默认的鼠标右键弹出菜单事件
<script> // 事件源document 整个文档 document.oncontextmenu = function(e){ // e就表示event console.log("点击鼠标右键~"); // prevent阻止的意思 Default是默认的意思 // e.preventDefault(); // return false也可以阻止默认事件 return false; }
-
a标签的默认事件
-
如果给a标签绑定了事件,绑定的事件也会触发
DOM0的事件绑定 let a = document.getElementsByTagName("a")[0]; // a.onclick = function(e){ // console.log("点击了a标签"); // // e.preventDefault(); // return false; // 也可以阻止 // } DOM2的事件绑定 a.addEventListener("click",function(e){ console.log("点击了a标签"); // e.preventDefault(); // 如果是DOM2的事件绑定,只能使用e.preventDefault();来阻止默认事件 // return false; })
-
form表单默认事件
let form = document.getElementsByTagName("form")[0]; form.onsubmit = function(e){ console.log("form submit ..."); // e.preventDefault(); return false; } </script>
15-事件委托
-
e.target.innerHTML
<button id="btn">添加li</button> <ul> <li>1</li> <li>2</li> <li>3</li> </ul> <script> let btn = document.getElementById("btn"); let ul = document.getElementsByTagName("ul")[0]; let lis = document.getElementsByTagName("li"); btn.onclick = function(){ let li = document.createElement("li"); li.innerHTML = lis.length + 1; // 4567.. ul.append(li) // 把li放在ul里的后面 } // 这个for循环,只能给已经存在的li绑定点击事件 // 新添加的li是不能绑定点击事件的 for(let i=0; i<lis.length; i++){ lis[i].onclick = function(){ console.log(this.innerHTML); // 点li打印出li里的内容123 } } </script> <script> let btn = document.getElementById("btn"); let ul = document.getElementsByTagName("ul")[0]; let lis = document.getElementsByTagName("li"); // 给ul点击绑定事件 // 点li也能触发ul的冒泡原理 ul.onclick = function(e){ // 如何知道你点击了哪一个li // e.target 表示你点击的目标 // console.log(e); console.log(e.target.innerHTML); } btn.onclick = function(){ let li = document.createElement("li"); li.innerHTML = lis.length + 1; ul.append(li) } </script>
09-JS操作盒子模型
js操作盒子模型:
- 操作盒子模型的位置
- 操作盒子模型的大小
不管是操作盒子模型的位置,还是盒子模型的大小,一共有13个api: 说明:需要记的没几个,三类:
- client系列 width height top left
- offset系列 width height top left parent
- scroll系列 width height top left
01-clint家族
client系列:
- clientWidth(可视区域宽度): 获取盒子的内容width+左右的padding
- clientHeight(可视区域高度): 获取盒子的内容height+上下的padding
- clientTop:获取盒子的上边框的粗细,了解
- clientLeft:获取盒子的左边框的粗细,了解
获取一屏
<script>
// 获取一屏的宽度
console.log(document.body.clientWidth);
console.log(document.documentElement.clientWidth); // documentElement html元素
// 获取一屏的高度
console.log(document.body.clientHeight);
console.log(document.documentElement.clientHeight);
</script>
可以得到多屏的高度
console.log(document.body.clientHeight);
client系列的注意点:
-
不能获取,不能设置,它们是只读的
-
得到的是一个数值,没有单位
-
得到的是一个整数,不是小数,及时测试量出来是小数,也会转化成整数
-
不管你的内容是否溢出,得到的是可视区的大小
<script> // clientHeight 不管你的内容是否溢出 // 它一直是 内容的height + 上下的padding let div = document.getElementsByClassName("box")[0]; console.log(div.clientWidth); // 内容加左右padding console.log(div.clientHeight); // 设置无用 只能获取,不能设置 div.clientHeight = 666; // 获取 console.log(div.clientHeight); </script>
02-offset家族
offset系列:
-
offsetWidth: box.offsetWidth 在clientWidth的基础上加了border 不常用
-
offsetHeight: box.offsetHeight 在clientHeight的基础上加了border 不常用
-
offsetTop: 获取一个绝对定位元素相对于参考点的上面的距离
-
offsetLeft: 获取一个绝对定位元素相对于参考点的左面的距离
-
offsetParent: 获取一个定位元素的参考点
<script> let sonEle = document.getElementsByClassName("son")[0]; // offsetTop和offsetLeft获取绝对定位元素相对于参考点的偏移量 console.log(sonEle.offsetTop); // top: 50px console.log(sonEle.offsetLeft); // left: 60px // offsetParent 获取参考点元素 console.log(sonEle.offsetParent); // father是参考点 </script>
03-scroll家族
scrollWidth:
- 在没有内容溢出(水平方向上的溢出)的情况下:scrollWidth == clientWidth
- 在内容溢出的情况下:scrollWidth的值约等于真实内容的宽度
- overflow属性会影响scrollWidth。 只能获取值,不能设置值
scrollHeight:
- 在没有内容溢出的情况下:scrollHeight = clientHeight
- 在内容溢出的情况下:scrollHeight的值约等于真实内容的高度,不同浏览器中得到的值可能不一样
- overflow属性会影响scrollHeight。
- 只能获取值,不能设置值
scrollTop:
-
获取垂直滚动条滚动的距离(获取垂直滚动条卷去的高度)
-
特殊:不只可以获取,也可以设置(可读可写) 重要
<script> let box = document.getElementsByClassName("box")[0]; // 绑定scroll事件 box.onscroll = function(){ // console.log("scroll"); // 滚动的时候触发scroll console.log("scrollTop(内容卷上去的高度):", box.scrollTop); } // 设置 box.scrollTop = 600 </script>
-
一张网页卷上去最大高度:scrollHeight - clientHeight
-
获取当前页面卷上去高度
-
1)document.body.scrollTop 2)document.documentElement.scrollTop
<script> window.onscroll = function(){ // 获取当前网页卷上去的高度 console.log(document.documentElement.scrollTop); // 一张网页卷上去的最大高度 console.log(document.documentElement.scrollHeight - document.documentElement.clientHeight); // 整个内容的高度 - 一屏的高度 } </script>
scrollLeft: 没什么用
- 特殊:不只可以获取,也可以设置(可读可写)
- 获取水平滚动条滚动的距离(获取水平滚动条卷去的距离) 基本上用不到
需要记的三个常用高度:
- 获取一张网页可视区的高度:document.body.clientHeight
- 获取一张网页真实的高度:document.body.scrollHeight
- 获取一张网页卷去的高度:document.body.scrollTop
10-DOM操作案例练习
01过渡动画
- transition
- linear匀速
<style>
/* 默认样式 */
.box{
width: 200px;
height: 200px;
background-color: gold;
/* 在默认样式上添加过渡动画 */
/* 从200到400需要1s linear匀速 */
/* transition: width 1s linear, height 1s linear; */
/* all表示只要有突变属性(针对数值),都有过渡动画 */
/* 颜色和背景图片也有过渡动画 */
transition: all 1s linear;
}
/* 突变样式 */
.box:hover{
width: 400px;
height: 400px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="box"></div>