元素的属性和特性
我们知道,一个元素除了有开始标签、结束标签、内容之外,还有很多的属性(attribute)
浏览器在解析HTML元素时,会将对应的attribute也创建出来放到对应的元素对象上。
- 比如id、class就是全局的attribute,会有对应的id、class属性;
- 比如href属性是针对a元素的,type、value属性是针对input元素的;
attribute的分类
属性attribute的分类:
- 标准的attribute:某些attribute属性是标准的,比如id、class、href、type、value等;
- 非标准的attribute:某些attribute属性是自定义的,比如abc、age、height等;
attribute的操作
对于所有的attribute访问都支持如下的方法:
- elem.hasAttribute(name) — 检查特性是否存在。
- elem.getAttribute(name) — 获取这个特性值。
- elem.setAttribute(name, value) — 设置这个特性值。
- elem.removeAttribute(name) — 移除这个特性。
- attributes:attr对象的集合,具有name、value属性;
attribute具备以下特征:
- 它们的名字是大小写不敏感的(id 与 ID 相同)。
- 它们的值总是字符串类型的。
<!-- 属性:attribute(特性) -->
<!--
attribute的分类:
1.如果是 HTML 标准制定的attribute,称之为标准Attribute
2.而自定义的Attribute,称之为非标准Attribute
-->
<div id="abc" class="box" title="box" age="18" height="1.88">
我是box
</div>
<a href="https://www.baidu.com">百度一下</a>
<input type="checkbox" checked="checked">
<script>
var boxEl = document.querySelector('.box')
// 1.所有的attribute的操作
console.log(boxEl.hasAttribute('age'), boxEl.hasAttribute('abc'), boxEl.hasAttribute('id')) // true false true
console.log(boxEl.getAttribute('AGE'), boxEl.getAttribute('abc'), boxEl.getAttribute('id')) // 18 null abc
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')) // 这里我们希望拿到的是boolean类型,但是实际上最好是boolean
</script>
元素的属性(property)
对于标准的attribute,会在DOM对象上创建与其对应的property属性:
在大多数情况下,它们是相互作用的
- 改变property,通过attribute获取的值,会随着改变;
- 通过attribute操作修改,property的值会随着改变;
- 但是input的value修改只能通过attribute的方法;
除非特别情况,大多数情况下,设置、获取attribute,推荐使用property的方式:
- 这是因为它默认情况下是有类型的;
<!-- 元素中的属性称之为attribute -->
<!-- 标准的attribute在对应的对象模型中都有对应的property -->
<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>
<script>
/* 对象中的属性称之为 property
var obj = {
// property
name:'what'
}
*/
// 1.通过property获取attribute的值
// 获取 box 元素
var boxEl = document.querySelector('.box')
console.log(boxEl.id, boxEl.className, boxEl.title, boxEl.age, boxEl.height)
// input 元素
var inputEl = document.querySelector('input')
/* if (inputEl.getAttribute('checked')) {
console.log('checked 处于选中状态')
} */
if (inputEl.checked) {
console.log('checked 处于选中状态')
}
console.log(typeof inputEl.checked)
// 2.attribute 和 property 是相互影响的
boxEl.id = 'aaa'
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.value = 'what' // 优先级更高
// accountInputEl.setAttribute('value', 'kobe')
}
HTML5的data-*
自定义属性
HTML5的data-*
自定义属性,它们也是可以在dataset属性中获取到的:
<div id="a" class="box" title="标题" data-age="18" data-height="1.88">我是box</div>
<script>
var boxEl = document.querySelector('.box')
console.log(boxEl.dataset)
console.log(boxEl.dataset.age)
console.log(boxEl.dataset.height)
</script>
JavaScript动态修改样式
有时候我们会通过JavaScript来动态修改样式,这个时候我们有两个选择:
- 选择一:在CSS中编写好对应的样式,动态的添加class;
- 选择二:动态的修改style属性;
开发中如何选择呢?
- 在大多数情况下,如果可以动态修改class完成某个功能,更推荐使用动态class;
- 如果对于某些情况,无法通过动态修改class(比如精准修改某个css属性的值),那么就可以修改style属性;
<div class="box">我是box</div>
<script>
// 1.获取 boxEl
var boxEl = document.querySelector('.box')
// 2.监听点击
var counter = 1
boxEl.onclick = function () {
/* 直接修改style
boxEl.style.color = 'red'
boxEl.style.fontSize = '24px'
boxEl.style.backgroundColor = 'skyblue'
*/
// 2.动态添加样式
boxEl.className = 'active'
// 3.动态修改boxEl的宽度
boxEl.style.width = 100 * counter + 'px'
counter++
}
</script>
元素的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进行遍历
<div class="box">我是box</div>
<button class="btn">切换</button>
<script>
var boxEl = document.querySelector('.box')
// 1.方法一:className
// boxEl.className = 'abc'
// 2.方法二:classList
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')
}
</script>
元素的style属性
如果需要单独修改某一个CSS属性,那么可以通过style来操作:
- 对于多词(multi-word)属性,使用驼峰式 camelCase
如果我们将值设置为空字符串,那么会使用CSS的默认样式:
多个样式的写法,我们需要使用cssText属性:
- 不推荐这种用法,因为它会替换整个字符串;
<div class="box" style="background-color: aqua;color: white;">
我是box
</div>
<script>
var boxEl = document.querySelector('.box')
// 1.在 property 中使用的是小驼峰模式
console.log(boxEl.style)
// 2.将一个属性的值设置为空,使用的是浏览器的默认样式
/*
boxEl.style.display = ''
boxEl.style.fontSize = ''
*/
// 3.设置多个样式
/* boxEl.style.fontSize = '30px'
boxEl.style.fontSize = '30px' */
boxEl.style.cssText = 'font-size:30px;color:red;'
元素style的读取 - getComputedStyle
如果我们需要读取样式:
- 对于内联样式,是可以通过
style.*
的方式读取到的; - 对于style、css文件中的样式,是读取不到的;
这个时候,我们可以通过getComputedStyle的全局函数来实现:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
font-size: 20px;
}
</style>
</head>
<body>
<div class="box" style="background-color:red;">我是box</div>
<script>
var boxEl = document.querySelector('.box')
console.log(boxEl.style.backgroundColor)
console.log(boxEl.style.fontSize)
console.log(getComputedStyle(boxEl).fontSize)
</script>
</body>
</html>
创建元素
使用 document.write 方法写入一个元素:
- 这种方式写起来非常便捷,但是对于复杂的内容、元素关系拼接并不方便;
- 它是在早期没有DOM的时候使用的方案,目前依然被保留了下来;
那么目前我们想要插入一个元素,通常会按照如下步骤:
- 步骤一:创建一个元素;
- 步骤二:插入元素到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>11111</span>
<div class="box">
<span class="box-frist">hhhh</span>
<p>呵呵呵呵</p>
</div>
<script>
var boxEl = document.querySelector('.box')
// 1.通过innerHTML(不推荐)
/*
boxEl.innerHTML = `<h2 class='title'>我是标题</h2>`
setTimeout(function () {
var titleEl = document.querySelector('.title')
titleEl.classList.add('active')
}, 2000)
*/
// 2.真实创建一个 DOM 对象
var h2El = document.createElement('h2')
h2El.className = 'title'
h2El.classList.add('active')
h2El.textContent = '我是标题'
// 将元素插入 boxEl
// boxEl.append(h2El)
// boxEl.prepend(h2El)
// boxEl.after(h2El)
// boxEl.replaceWith(h2El)
// 插入到 span和p元素之间
// var spanEl = document.querySelector('span')
// var spanEl = boxEl.children[0]
var spanEl = boxEl.querySelector('span')
spanEl.after(h2El)
</script>
移除和克隆元素
移除元素我们可以调用元素本身的remove方法:
如果我们想要复制一个现有的元素,可以通过cloneNode方法:
-
可以传入一个Boolean类型的值,来决定是否是深度克隆;
-
深度克隆会克隆对应元素的子元素,否则不会;
<button class="remove-btn">移除box</button>
<button class="clone-btn">复制box</button>
<div class="box">
我是box
<h2>我是标题</h2>
<p>我是文本 呵呵哈哈哈</p>
</div>
<script>
// 1.获取元素
var boxEl = document.querySelector('.box')
var removeBtnEl = document.querySelector('.remove-btn')
var cloneBtnEl = document.querySelector('.clone-btn')
// 2.监听removeBtnEl点击事件
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++
}
</script>
旧的元素操作方法
在很多地方我们也会看到一些旧的操作方法:
- parentElem.appendChild(node):
- 在parentElem的父元素最后位置添加一个子元素
- parentElem.insertBefore(node, nextSibling):
- 在parentElem的nextSibling前面插入一个子元素;
- parentElem.replaceChild(node, oldChild):
- 在parentElem中,新元素替换之前的oldChild元素;
- parentElem.removeChild(node):
- 在parentElem中,移除某一个元素;
元素的大小、滚动
-
clientWidth:contentWith+padding(不包含滚动条)
-
clientHeight:contentHeight+padding
-
clientTop:border-top的宽度
-
clientLeft:border-left的宽度
-
offsetWidth:元素完整的宽度
-
offsetHeight:元素完整的高度
-
offsetLeft:距离父元素的x
-
offsetHeight:距离父元素的y
-
scrollHeight:整个可滚动的区域高度
-
scrollTop:滚动部分的高度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
padding: 100px;
}
.box {
width: 100px;
height: 100px;
padding: 20px;
border: 10px solid red;
/* box-sizing: border-box0 */
background-color: orange;
overflow: auto;
}
</style>
</head>
<body>
<div class="box">
We’ve started making a tradition of rounding up the latest front-end research at the end of each year. We did it in
2020 and again in 2021. Reports are released throughout the year by a bunch of different companies and organizations
researching everything from web design trends to developer skills to popular coding languages and […]
</div>
<script>
var boxEl = document.querySelector('.box')
// 1.获取样式(局限性强)
var boxStyle = getComputedStyle(boxEl)
console.log(boxStyle.width, boxStyle.height)
// 2.获取更多信息
console.log(boxEl.clientWidth)
console.log(boxEl.clientHeight)
console.log(boxEl.clientTop)
console.log(boxEl.clientLeft)
console.log(boxEl.offsetWidth)
console.log(boxEl.offsetHeight)
console.log(boxEl.offsetLeft)
console.log(boxEl.offsetHeight)
// windows 对象
window.onclick = function () {
console.log(boxEl.scrollTop)
}
</script>
</body>
</html>
window的大小、滚动
window的width和height
- innerWidth、innerHeight:获取window窗口的宽度和高度(包含滚动条)
- outerWidth、outerHeight:获取window窗口的整个宽度和高度(包括调试工具、工具栏)
- documentElement.clientHeight、documentElement.clientWidth:获取html的宽度和高度(不包含滚动条)
window的滚动位置:
- scrollX:X轴滚动的位置(别名pageXOffset)
- scrollY:Y轴滚动的位置(别名pageYOffset)
也有提供对应的滚动方法:
- 方法 scrollBy(x,y) :将页面滚动至 相对于当前位置的 (x, y) 位置;
- 方法 scrollTo(pageX,pageY) 将页面滚动至 绝对坐标;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
/* width: 3000px; */
height: 200px;
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><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 scrollBtn = document.querySelector('.scroll-btn')
scrollBtn.hidden = true
window.onscroll = function () {
var scrollY = window.scrollY
if (scrollY > 600) {
// scrollBtn.style.display = 'block'
scrollBtn.hidden = false
} else {
// scrollBtn.style.display = 'none'
scrollBtn.hidden = true
}
}
// 点击按钮后滚动到某个位置
scrollBtn.onclick = function () {
// window.scrollBy(0, 100)
window.scrollTo(0, 0)
}
</script>
</body>
</html>
练习
计数器
<button class="add">+</button>
<button class="sub">-</button>
<h2 class="counter">0</h2>
<script>
// 1.获取按钮
var addEl = document.querySelector('.add')
var subEl = document.querySelector('.sub')
var h2El = document.querySelector('.counter')
// 2.监听 btnEl 的点击
var counter = 0
addEl.onclick = function () {
h2El.textContent = counter++
}
subEl.onclick = function () {
h2El.textContent = counter--
}
</script>
输入动态列表
<h1>动态创建列表</h1>
<ul class="list"></ul>
<script>
var listEl = document.querySelector('.list')
var isFlag = true
while (isFlag) {
var message = prompt('请输入信息:')
if (!message) {
isFlag = false
} else {
var liEl = document.createElement('li')
liEl.textContent = message
listEl.append(liEl)
}
}
</script>
动态显示时间
<h1 class="time">2022-12-24 11:13:57</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>
倒计时
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.countdown {
color: orange;
font-size: 30px;
}
.countdown .time {
background-color: orange;
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">26</span>
<span class="split">:</span>
<span class="time second">45</span>
</div>
<script>
// 封装工具函数
function padLeft (content, count, padStr) {
count = count || 2
padStr = padStr || '0'
content = String(content)
return content.padStart(count, padStr)
}
// 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 => 24:00
var nowDate = new Date()
var intervalTime = Math.floor((endDate.getTime() - nowDate.getTime()) / 1000)
console.log(intervalTime)
// 25926: x小时x分钟x秒钟
var hour = Math.floor(intervalTime / 3600)
var minute = Math.floor(intervalTime / 60) % 60
var second = Math.floor(intervalTime % 60)
// 2.设置内容
hourEl.textContent = padLeft(hour)
minuteEl.textContent = padLeft(minute)
secondEl.textContent = padLeft(second)
})
// 123:x百x十x个
/*
var num = 125
console.log(Math.floor(num / 100))
console.log(Math.floor(num / 10) % 10)
console.log(Math.floor(num % 10))
*/
</script>
</body>
</html>
Q.E.D.