<script>
var htmlEl=document.documentElement
var bodyEl=document.body
var headEl=document.head
var doctype=document.doctype
console.log(htmlEl,bodyEl,headEl,doctype)
</script>
ul>li{$}*5
节点之间的关系(极少用)
空行+注释+没标签包括的文字也算是一个节点
子节点:
// 1.获取节点的导航
var bodyEl = document.body
// 1.1.获取body所有的子节点
// console.log(bodyEl.childNodes)
// 1.2.获取body的第一个子节点
var bodyElFirstChild = bodyEl.firstChild
// 1.3.获取body中的注释
var bodyElCommentChild = bodyElFirstChild.nextSibling
console.log(bodyElCommentChild)
// 1.4.获取body的父节点
var bodyParent = bodyEl.parentNode
console.log(bodyParent)
此处 text指的是body下的第一个换行符,如果写成这样,text消失,第一个节点内容为注释
<body><!-- 我是注释, 哈哈哈 -->
我是文本, 呵呵呵
输出所有子节点:
console.log(bodyEl.childNodes)
console.log(bodyEl.firstChild)
var bodyELTextChild=bodyElFirstChild.nextSibling
console.log(bodyELTextChild)
元素之间的关系
.children[0]=.firstElementChild
firstchild用于节点而不是元素导航
children[index]比firstElementChild更常用
var bodyEl = document.body
// 根据body元素去获取子元素(element)
var childElements = bodyEl.children
console.log(childElements)
// 获取box元素
var boxEl1 = bodyEl.firstElementChild
var boxEl2 = bodyEl.children[0]
console.log(boxEl1, boxEl2, boxEl1 === boxEl2)
// 获取ul元素
var ulEl = boxEl1.nextElementSibling
console.log(ulEl)
// 获取li元素
var liEls = ulEl.children
console.log(liEls)
注意这里是children不是child不是childelement
var childElements=bodyEL.children
里面的第四个script是live server给浏览器注入的,无视掉
var boxEl=bodyEL.firstElementChild
console.log(boxEl)
console.log(bodyEL.children[0])
注意这里是firstElementChild不是firstchild
输出body第一个元素boxdiv的下一个元素 ul
console.log(boxEl.nextElementSibling)
form和table之间的导航
var tableEl=document.body.firstElementChild
console.log(tableEl.tHead)
得到表格的第三行
var tableEl=document.body.firstElementChild
// console.log(tableEl.tHead,tableEl.tBodies,tableEl.tFoot)
// console.log(tableEl.rows)
console.log(tableEl.rows[2])
打印出第三行的第一列内容
var tableEl=document.body.firstElementChild
console.log(tableEl.rows[2].cells[0])
确定是第几列以及位于thead/tbody/tfoot中的索引
var tableEl=document.body.firstElementChild
var rowEl=tableEl.rows[2]
console.log(rowEl.rowIndex)
console.log(rowEl.sectionRowIndex)
获取form元素
formEl=document.body.firstElementChild
// console.log(formEl)
// console.log(document.forms[0])
var inputEl=formEl.children[0]
var inputEl1=formEl.elements.password
console.log(inputEl,inputEl1)
获取input输入的value
formEl=document.body.firstElementChild
// console.log(formEl)
// console.log(document.forms[0])
var inputEl=formEl.children[0]
var inputEl1=formEl.elements.password
// console.log(inputEl,inputEl1)
setTimeout(function(){
console.log(inputEl1.value)
},2000)
element导航的实际运用(表格)
要求:将表格的对应格子设置为bgc为红色,字体为白色
var tableEl = document.body.firstElementChild
for (var i = 0; i < tableEl.rows.length; i++)
{
var rowEl1 = tableEl.rows[i]
var cellEl1 = rowEl1.cells[i]
cellEl1.style.backgroundColor="red"
cellEl1.style.color="white"
}
易错:backgroundColor此处C大写且red被双引号包裹起来
任意地获取元素
按照原来的思维,每一步都是固定死的
当嵌套太深时,导航非常不方便
ByName常见于input,ByTag用于统一标签,几乎不用
用的最多的是queryselector与类/id选择器
可以在元素上调用指的是不仅支持document.xxx,同时还支持bodyEl.xxx(此处bodyEl是元素)
实时指的是如果修改后是否会动态修改
按照之前的写法,一步步查找
var bodyEl = document.body
var boxEl = bodyEl.firstElementChild
var containerEl = boxEl.children[1]
var pEl = containerEl.children[0]
var spanEl = pEl.children[0]
spanEl.style.color = "red"
通过类名获取元素
// 1.通过className获取元素
var keywordEls = document.getElementsByClassName("keyword")
// // 修改第一个
// keywordEls[0].style.color = "red"
// 修改所有的
for (var i = 0; i < keywordEls.length; i++) {
keywordEls[i].style.color = "red"
}
通过id名获取元素
var titleEl=document.getElementById("title")
titleEl.style.color="orange"
通过选择器查询querySelector
var keywordEl = document.querySelector(".keyword")
keywordEls是对象, 可迭代的
// 可迭代对象: String/数组/节点的列表
var keywordEls = document.querySelectorAll(".keyword")
for (var el of keywordEls) {
el.style.color = "red"
}
console.log(keywordEls)
var titleEl = document.querySelector("#title")
titleEl.style.color = "orange"
querySelector只查找第一个,selectorAll是查找所有
(".keyword")与("#title")
var keywordEl = document.querySelector(".keyword")
// keywordEls是对象, 可迭代的,所以支持for of循环
// 可迭代对象: String/数组/节点的列表
节点的属性
nodeType属性:返回数值
注释节点/元素节点/文字节点的nodeType返回值不同
nodeType属性返回值是数值
console.log(commentNode.nodeType,textNode.nodeType,divNode.nodeType)
左侧常量使用方式:
默认Node.ELELMENT_NODE=8
nodeName与TagName属性:返回文本
console.log(commentNode.nodeName, textNode.nodeName, divNode.nodeName)
console.log(commentNode.tagName, divNode.tagName)
TagName只针对元素,如果不是元素,返回undefined
Iinner/outHTML属性与textContent属性-元素类节点获取内容
console.log(divNode.innerHTML)
innerHTML会把元素的标签名也拿到
console.log(divNode.outerHTML)
console.log(divNode.textContent)
textContent只拿文本内容
如果想要使用这两个进行替换文本
divNode.innerHTML = "<h2>呵呵呵呵</h2>"
此处h2会被浏览器解析
divNode.textContent = "<h2>嘿嘿嘿嘿</h2>"
此处h2默认为文本,不会解析
data属性-非元素节点获取内容
console.log(commentNode.data, textNode.data, divNode.data)
data属性针对于非元素节点的内容
元素的特性/属性(attribute)
全局属性-hidden属性
全局属性,id,class,style,hidden
hidden属性为true即意为display=none
使用hidden属性实现点击按钮切换显示与隐藏功能
<button class="btn">切换</button>
<!-- hidden属性 -->
<div id="box" class="cba" title="aaa" style="color: red">
哈哈哈哈哈
</div>
<script>
// 1.获取元素
var boxEl = document.querySelector("#box")
var btnEl = document.querySelector(".btn")
btnEl.onclick=function()
{
boxEl.hidden=!boxEl.hidden
}
// 2.监听btn的点击
btnEl.onclick = function() {
// 1.只是隐藏
// boxEl.hidden = true
// boxEl.style.display = "none"
// 2.切换
// boxEl.hidden = false
// if (boxEl.hidden === false) {
// boxEl.hidden = true
// } else {
// boxEl.hidden = false
// }
// 3.直接取反
// boxEl.hidden = !boxEl.hidden
// }
浏览器在解析HTML元素时,会将对应的attribute也创建出来放到对应的元素对象上。
比如id、class就是全局的attribute,会有对应的id、class属性;
比如href属性是针对a元素的,type、value属性是针对input元素的;
属性attribute的分类:
标准的attribute:某些attribute属性是标准的,比如id、class、href、type、value等;
非标准的attribute:某些attribute属性是自定义的,比如abc、age、height等;
元素属性的操作
◼对于所有的attribute访问都支持如下的方法:
elem.hasAttribute(name) — 检查特性是否存在。
elem.getAttribute(name) — 获取这个特性值。
elem.setAttribute(name, value) — 设置这个特性值。
elem.removeAttribute(name) — 移除这个特性。
attributes:attr对象的集合,具有name、value属性;
<div id="abc" class="box" title="box"
age="18" height="1.88">
我是box
</div>
<input type="checkbox" checked="checked">
var boxEl=document.querySelector(".box")
// 1.所有的attribute都支持的操作
console.log(boxEl.hasAttribute("AGE"), boxEl.hasAttribute("abc"), boxEl.hasAttribute("id"))
console.log(boxEl.getAttribute("AGE"), boxEl.getAttribute("abc"), boxEl.getAttribute("id"))
boxEl.setAttribute("id", "cba")
boxEl.removeAttribute("id")
var boxAttributes = boxEl.attributes
for (var attr of boxAttributes) {
console.log(attr.name, attr.value)
}
// 2.通过getAttribute()一定是字符串类型
var inputEl = document.querySelector("input")
console.log(inputEl.getAttribute("checked"))
◼ attribute具备以下特征:
它们的名字是大小写不敏感的(id 与 ID 相同)。
它们的值总是字符串类型的。
↑但是checked这种我们更希望获得布尔类型,所以字符串类型不太合适
对象属性的操作(更多使用)
元素属性叫attribute,对象属性叫property
var boxEl = document.querySelector(".box")
此处的boxEl是对象,boxEl.id是property
对于标准的attribute,会在DOM对象上创建与其对应的property属性:
◼ 在大多数情况下,它们是相互作用的
改变property,通过attribute获取的值,会随着改变;
通过attribute操作修改,property的值会随着改变;
✓ 但是input的value修改只能通过attribute的方法;
◼ 除非特别情况,大多数情况下,设置、获取attribute,推荐使用property的方式:
这是因为它默认情况下是有类型的;
这是因为它默认情况下是有类型的,比如checked是布尔类型的true
<div id="abc" class="box" title="标题"
age="18" height="1.88">
我是box
</div>
<input type="checkbox" checked>
账号: <input class="account" type="text">
<button class="btn">设置input的值</button>
var boxEl = document.querySelector(".box")
console.log(boxEl.id, boxEl.title, boxEl.age, boxEl.height)
// input元素
var inputEl = document.querySelector("input")
// if (inputEl.getAttribute("checked")) {
// console.log("checkbox处于选中状态")
// }
if (inputEl.checked) {
console.log("checkbox处于选中状态")
}
console.log(typeof inputEl.checked)
// 2.attribute和property是相互影响的
boxEl.id = "aaaaa"
console.log(boxEl.getAttribute("id"))
boxEl.setAttribute("title", "哈哈哈")
console.log(boxEl.title)
// 3.比较特殊的情况, input设置值(了解)
var accountInputEl = document.querySelector(".account")
var btnEl = document.querySelector(".btn")
btnEl.onclick = function() {
accountInputEl.setAttribute("value", "kobe")
// 优先级更高
accountInputEl.value = "coderwhy"
}
JS动态修改样式
// 1.直接修改style
// boxEl.style.color = "red"
// boxEl.style.fontSize = "24px"
// boxEl.style.backgroundColor = "green"
此处bgc与fz都是小驼峰形式,即fZ与bC
◼ 有时候我们会通过JavaScript来动态修改样式,这个时候我们有两个选择:
选择一:在CSS中编写好对应的样式,动态的添加class;
选择二:动态的修改style属性;←此法需要写多个style语句添加,较为麻烦
◼ 开发中如何选择呢?
在大多数情况下,如果可以动态修改class完成某个功能,更推荐使用动态class(提前写好class的css样式);
如果对于某些情况,无法通过动态修改class(比如精准修改某个css属性的值),那么就可以修改style属性;
◼ 接下来,我们对于两种方式分别来进行学习。
// 2.动态的添加某一个class
boxEl.className = "active"
但是此处className添加的类名会覆盖原类名!!!
<div class="box">
我是box
</div>
// 1.获取boxEl
var boxEl = document.querySelector(".box")
// 2.监听点击
var counter = 1
boxEl.onclick = function() {
// 1.直接修改style
// boxEl.style.color = "red"
// boxEl.style.fontSize = "24px"
// boxEl.style.backgroundColor = "green"
// 2.动态的添加某一个class
boxEl.className = "active"
// 3.动态的修改boxEl的宽度
boxEl.style.width = 100 * counter + "px"
counter++
}
元素的className与classList
元素的class attribute,对应的property并非叫class,而是className:
这是因为JavaScript早期是不允许使用class这种关键字来作为对象的属性,所以DOM规范使用了className;
虽然现在JavaScript已经没有这样的限制,但是并不推荐,并且依然在使用className这个名称;
◼ 我们可以对className进行赋值,它会替换整个类中的字符串。
◼ 如果我们需要添加或者移除单个的class,那么可以使用classList属性。
◼ elem.classList 是一个特殊的对象:
elem.classList.add (class) :添加一个类
elem.classList.remove(class):添加/移除类。
elem.classList.toggle(class) :如果类不存在就添加类,存在就移除它。
elem.classList.contains(class):检查给定类,返回 true/false。
◼ classList是可迭代对象,可以通过for of进行遍历
<style>
.active {
color: #fff;
background-color: #f80;
font-size: 25px;
}
</style>
<div class="box">
我是box
</div>
<button class="btn">切换</button>
var boxEl = document.querySelector(".box")
// 1.方法一: className
// boxEl.className = "abc"
// 2.方法二: classList操作class
boxEl.classList.add("abc")
boxEl.classList.add("active")
boxEl.classList.remove("abc")
// 需求: box在active之间切换
var btnEl = document.querySelector(".btn")
btnEl.onclick = function() {
// if (boxEl.classList.contains("active")) {
// boxEl.classList.remove("active")
// } else {
// boxEl.classList.add("active")
// }
boxEl.classList.toggle("active")
}
元素的style属性
<div class="box" style="background-color: aqua; color: white;">
我是box
</div>
// 2.如果将一个属性的值, 设置为空的字符串, 那么是使用默认值
// boxEl.style.display = ""
// boxEl.style.fontSize = ""
// 3.设置多个样式
// boxEl.style.fontSize = "30px"
// boxEl.style.color = "red"
boxEl.style.cssText = "font-size: 30px; color: red;"
多个样式的写法,我们需要使用cssText属性:
不推荐这种用法,因为它会替换整个字符串
读取元素的style
var boxEl = document.querySelector(".box")
console.log(boxEl.style.backgroundColor)
// console.log(boxEl.style.fontSize)
console.log(getComputedStyle(boxEl).fontSize)
第一种读取的是内联样式
第二种是获取全局样式
HTML5的data-*自定义属性
<div id="abc" class="box"
data-age="18" data-height="1.88"></div>
<script>
var boxEl = document.querySelector(".box")
// 小程序开发中使用
console.log(boxEl.dataset.age)
console.log(boxEl.dataset.height)
</script>
data-*自定义属性可以避免调用getAttribute
创建/插入元素
// 1.通过innerHTML(非常不推荐)
// boxEl.innerHTML = `
// <h2 class="title">我是标题</h2>
// `
l浏览器需要额外解析字符串,性能不高
且如果后序进行操作,仍需 再次获取var boxEl = document.querySelector(".title")
那么目前我们想要插入一个元素,通常会按照如下步骤:
步骤一:创建一个元素;
步骤二:插入元素到DOM的某一个位置;
◼ 创建元素: document.createElement(tag)
插入元素的方式如下:
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 替换为给定的节点或字符串。
<span>111111</span>
<div class="box">
<span class="box-first">呵呵呵呵</span>
<p>哈哈哈哈哈</p>
</div>
var boxEl = document.querySelector(".box")
// 1.通过innerHTML(不推荐)
// boxEl.innerHTML = `
// <h2 class="title">我是标题</h2>
// `
// 2.真实创建一个DOM对象
var h2El = document.createElement("h2")
h2El.className = "title"
h2El.classList.add("active")
h2El.textContent = "我是标题"
// 3.将元素插入boxEl
// boxEl.append(h2El)
// boxEl.prepend(h2El)
// boxEl.after(h2El)
// boxEl.before(h2El)
// boxEl.replaceWith(h2El, "abc")
// 4.插入到span和p元素之间
// var spanEl = document.querySelector("span")
// var spanEl = boxEl.children[0]
var spanEl = boxEl.querySelector("span")
spanEl.after(h2El)
移除与复制元素
<button class="remove-btn">移除box</button>
<button class="clone-btn">复制box</button>
<div class="box">
<h2>我是标题</h2>
<p>我是文本, 哈哈哈哈哈</p>
</div>
// 1.获取元素
var boxEl = document.querySelector(".box")
var removeBtnEl = document.querySelector(".remove-btn")
var cloneBtnEl = document.querySelector(".clone-btn")
// 2.监听removeBtn的点击
removeBtnEl.onclick = function() {
boxEl.remove()
}
// 3.复制box
var counter = 0
cloneBtnEl.onclick = function() {
var newNode = boxEl.cloneNode(true)
newNode.children[0].textContent = "我是标题" + counter
// boxEl.after(newNode)
document.body.append(newNode)
counter++
}
这里因为不是深度的,所以只有box的外面结构,里面内容一点都没有
var newNode = boxEl.cloneNode(true)
加上true之后就是深度的,会有子结构
// 3.复制box
var counter = 0
cloneBtnEl.onclick = function() {
var newNode = boxEl.cloneNode(true)
newNode.children[0].textContent = "我是标题" + counter
// boxEl.after(newNode)
document.body.append(newNode)
}
现在的方法不需要知道多个元素即可使用,旧方法了解即可
元素的大小与滚动
// 1.获取样式(局限性很强)
// var boxStyle = getComputedStyle(boxEl)
// console.log(boxStyle.width, boxStyle.height)
可以获取的内容很少,只能获取我们设置的东西并且有单位如px,但是如元素滚动条长度和滚动到了哪里是获取不到的
<div class="box">
你去过国内最美的地方是哪# 我去过国内最美的地方是新疆喀纳斯。喀纳斯是一个美丽而神秘的地方,这里群山环抱,森林密布,湖水清澈,风景奇特。为国家级5A级景区,国家地质公园,国家森林公园。
</div>
var boxEl = document.querySelector(".box")
// 1.获取样式(局限性很强)
var boxStyle = getComputedStyle(boxEl)
console.log(boxStyle.width)
// 2.获取更多信息
console.log(boxEl.clientWidth)
console.log(boxEl.clientHeight)
console.log(boxEl.clientLeft)
console.log(boxEl.clientTop)
console.log(boxEl.offsetWidth)
console.log(boxEl.offsetHeight)
console.log(boxEl.offsetLeft)
console.log(boxEl.offsetTop)
console.log(boxEl.scrollHeight)
console.log(boxEl.scrollTop)
// window对象
window.onclick = function() {
console.log(boxEl.scrollTop)
}
window大小与滚动
<style>
.box {
/* width: 2000px; */
height: 100px;
background-color: orange;
}
.scroll-btn {
position: fixed;
right: 20px;
bottom: 20px;
/* display: none; */
}
</style>
</head>
<body>
<div class="box"></div>
<button class="scroll-btn">回到顶部</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<script>
// window大小
console.log(window.outerWidth)
console.log(window.outerHeight)
console.log(window.innerWidth)
console.log(window.innerHeight)
console.log(document.documentElement.offsetWidth)
console.log(document.documentElement.offsetHeight)
// 获取window的滚动区域
window.onclick = function() {
console.log(window.scrollX)
console.log(window.scrollY)
}
var scrollBtnEl = document.querySelector(".scroll-btn")
scrollBtnEl.hidden = true
window.onscroll = function() {
var scrollY = window.scrollY
if (scrollY > 600) {
// scrollBtnEl.style.display = "block"
scrollBtnEl.hidden = false
} else {
// scrollBtnEl.style.display = "none"
scrollBtnEl.hidden = true
}
}
// 点击按钮后滚动到某个位置
scrollBtnEl.onclick = function() {
// window.scrollBy(0, 100)
window.scrollTo(0, 0)
}
</script>
全局变量的使用细节
如果此处counter初始化在函数内部,则每次点击都是从1,不会增加,故要写在外面作为全局变量
addEl.onclick = function() {
var counter = 0
counter++
h2El.textContent = counter
}
<button class="add">+</button>
<button class="sub">-</button>
<h2 class="counter">0</h2>
// 1.获取按钮
var addEl = document.querySelector(".add")
var subEl = document.querySelector(".sub")
var h2El = document.querySelector(".counter")
// 2.监听btnEl的点击
var counter = 0
addEl.onclick = function() {
counter++
h2El.textContent = counter
}
subEl.onclick = function() {
counter--
h2El.textContent = counter
}
// var age = 18
// function foo() {
// age++
// }
// foo()
// foo()
// foo()
// foo()
// console.log(age)
案例:动态创建列表
<h1>动态创建列表</h1>
<ul class="list"></ul>
<script>
var ulEl = document.querySelector(".list")
var isFlag = true
while (isFlag) {
var message = prompt("请输入信息:")
if (!message) { // 没有输入内容
isFlag = false
} else {
var liEl = document.createElement("li")
liEl.textContent = message
ulEl.append(liEl)
}
}
</script>
案例:完成倒计时案例
<style>
.countdown {
color: #f00;
font-size: 20px;
}
.countdown .time {
background-color: #f00;
color: #fff;
display: inline-block;
padding: 5px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="countdown">
<span class="time hour">03</span>
<span class="split">:</span>
<span class="time minute">25</span>
<span class="split">:</span>
<span class="time second">43</span>
</div>
<script src="./js/format.js"></script>
<script>
// 1.获取元素
var hourEl = document.querySelector(".hour")
var minuteEl = document.querySelector(".minute")
var secondEl = document.querySelector(".second")
var endDate = new Date()
endDate.setHours(24)
endDate.setMinutes(0)
endDate.setSeconds(0)
endDate.setMilliseconds(0)
setInterval(function() {
// 获取倒计时的小时-分钟-秒钟
// 11:53:22 => 24:00:00
var nowDate = new Date()
var intervalTime = Math.floor((endDate.getTime() - nowDate.getTime()) / 1000)
// console.log(intervalTime)
// 43324: x小时x分钟x秒钟
var hour = Math.floor(intervalTime / 3600)
var minute = Math.floor(intervalTime / 60) % 60
var second = intervalTime % 60
// 2.设置内容
hourEl.textContent = formatPadLeft(hour)
minuteEl.textContent = formatPadLeft(minute)
secondEl.textContent = formatPadLeft(second)
}, 1000)
// 125: x百x十x个
// var num = 125
// console.log(Math.floor(num / 10 * 10))
// console.log(Math.floor(num / 10) % 10)
// console.log(num % 10)
</script>
案例:动态显示时间
且即刻变化
<body>
<h1 class="time">2022-05-19 11:14:30</h1>
<script>
// 封装了工具函数
function padLeft(content, count, padStr) {
count = count || 2
padStr = padStr || "0"
content = String(content)
return content.padStart(count, padStr)
}
// 1.获取时间的元素
var timeEl = document.querySelector(".time")
setInterval(function() {
// 2.获取具体的时间并且进行格式化
var date = new Date()
var year = date.getFullYear()
var month = padLeft(date.getMonth() + 1)
var day = padLeft(date.getDate())
var hour = padLeft(date.getHours())
var minute = padLeft(date.getMinutes())
var second = padLeft(date.getSeconds())
// 3.将时间放到timeEl中
timeEl.textContent = `${year}-${month}-${day} ${hour}:${minute}:${second}`
}, 1000);
// 补充String方法
// var str = "124"
// console.log(str.padStart(4, "0"))
</script>
</body>