1.DOM 树 :
文档:一个页面就是一个文档,DOM 中使用 document 表示
元素:页面中的所有标签都是元素,DOM 中使用 element 表示
节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示
2. 获取元素
操作元素的前提是 获取元素
/* 1 获取元素 */
// 1.2 使用 getElementsById() 方法可以返回带有指定id的元素对象
let box = document.getElementById('BOX')
// console.dir() 是一种在控制台中查看指定 JavaScript 对象的所有属性的方法
// console.dir(box)
// 1.2 使用 getElementsByTagName() 方法可以返回指定标签名的对象的集合(伪数组。
let box2 = document.getElementsByTagName('div')
console.log(box)
// 1.2.1 还可以链式调用,获取某个父元素内所有指定标签名的子元素
console.log(box.getElementsByTagName('div'))
// 1.3 通过 HTML5 新增的方法获取
// 1.3.1 document.getElementsByClassName(‘类名’) 根据'类名'返回元素对象集合
console.log(document.getElementsByClassName('boxSon'), 'getElementsByClassName')
// 1.3.2 document.querySelector('选择器') 根据选择器匹配'第一次'出现的元素
console.log(document.querySelector('.boxSon'))
// 1.3.3 document.querySelector('选择器') 根据选择器匹配出现的元素返回元素'对象集合'
console.log(document.querySelectorAll('.boxSon'))
// querySelector 和 querySelectorAll里面的选择器需要加'选择器符号'
// 1.4 获取body元素
console.log(document.body, 'body')
// 1.5 获取html中所有元素
console.log(document.documentElement, 'html')
3.事件基础
摁遥控器键 电视开机 就是一个事件
3.1 事件三部曲
- 事件源:谁 => 遥控器
- 事件类型:什么类型的动作 => 摁
- 事件处理函数::引发的事 => 电视开机了
3.2 事件绑定
注册事件同上:找事件源绑定想要的事件类型 赋值 处理函数
3.3 常见事件
4. 修改元素
DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内
容 、属性等。以下都是针对元素属性
4.1 修改内容
//改变元素内容
// innerText/innerHTML都可以修改元素内容和查看元素内容
// 1.1 innerText
// 修改时,内容如果含有标签则标签按字符串解析,不会被解析成标签元素
// 查看元素内容,会删除空格回车以及标签元素
// 1.2 innerHTML
// 修改时,内容如果含有标签则标签按字符串解析,'会被解析成标签元素'
// 查看元素内容,保留空格回车以及标签
两种方式获取元素内容的区别
两种方式设置内容的区别
4.2 常用元素的属性操作
1. innerText、innerHTML 改变元素内容
2. src、href
3. id、alt、title
4.3 表单元素的属性操作
type / value / disabled/ checked / selected
// 切换密码框
<body>
密码框:<input type="password" value="" id="psdInput">
<button id="lookPsdBtn">看看密码</button>
</body>
<script>
let psdInput = document.querySelector("#psdInput")
let lookPsdBtn = document.querySelector("#lookPsdBtn")
let ok = true
// 通过ok判断输入框的'type'以及按钮的innerText
// 按钮的值和输入框的类型相反,当输入框类型切换为密码时按钮提示看看密码
lookPsdBtn.onclick = () => {
ok = !ok
if (ok) {
lookPsdBtn.innerHTML = '看看密码'
psdInput.type = 'password'
} else {
lookPsdBtn.innerHTML = '不看密码了'
psdInput.type = ''
}
}
</script>
// 全选/反选
<style>
* {
padding: 0;
margin: 0;
}
.wrap {
width: 300px;
margin: 100px auto 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #c0c0c0;
width: 300px;
}
th,
td {
border: 1px solid #d0d0d0;
color: #404060;
padding: 10px;
}
th {
background-color: #09c;
font: bold 16px "微软雅黑";
color: #fff;
}
td {
font: 14px "微软雅黑";
}
tbody tr {
background-color: #f0f0f0;
}
tbody tr:hover {
cursor: pointer;
background-color: #fafafa;
}
</style>
</head>
<body>
<div class="wrap">
<table>
<thead>
<tr>
<th>
<!-- 全选按钮 -->
<input type="checkbox" id="j_cbAll" value="" />
</th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPhone8</td>
<td>8000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Pro</td>
<td>5000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>iPad Air</td>
<td>2000</td>
</tr>
<tr>
<td>
<input type="checkbox" />
</td>
<td>Apple Watch</td>
<td>2000</td>
</tr>
</tbody>
</table>
</div>
<script>
let j_cbAll = document.querySelector("#j_cbAll")
let checks = document.querySelectorAll("#j_tb input")
// 主按钮控制其他按钮
j_cbAll.onclick = function () {
let isChecked = this.checked
for (let i = 0; i < checks.length; i++) {
checks[i].checked = isChecked
}
}
// 其他按钮全选后,主按钮激活;其他按钮只要有一个没选上,主按钮失活;
for (let i = 0; i < checks.length; i++) {
checks[i].onclick = function () {
// flag控制主按钮激活
let flag = true
// 遍历每个按钮的checked,如果当前按钮checked为false,flag失效且退出遍历
for (let i = 0; i < checks.length; i++) {
if (!checks[i].checked) {
flag = false
break // 退出for循环 这样可以提高执行效率 因为只要有一个没有选中,剩下的就无需循环判断了
}
}
// 提交主按钮状态
j_cbAll.checked = flag
}
}
</script>
4.4 样式属性操作
1.element.style
修改元素行内样式(权重高
样式属性驼峰命名法 比如 fontSize、 backgroundColor
2.element.className
修改元素样式类,当修改样式多时采用
<style>
.box {
width: 250px;
height: 250px;
background-color: pink;
}
.uNameInput {
margin-top: 10px;
}
.uNameCheckSuccees {
color: greenyellow;
}
.uNameCheckErro {
color: rgb(241, 51, 21);
}
.paitBoxLi {
list-style: none;
background-color: palegoldenrod;
width: 60px;
text-align: center;
margin-top: 1px;
}
.AtivePaitBoxLi {
list-style: none;
background-color: rgb(220, 96, 79);
width: 60px;
text-align: center;
margin-top: 1px;
}
</style>
<body>
<div class="box"></div>
<input type="text" class="uNameInput">
<span class="uNameCheck"></span>
<div class="paitBox">
<p>排他思想</p>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
</body>
<script>
// 1 点击更改盒子大小
// 通过元素style属性修改其行内样式
let box = document.querySelector('.box')
box.onclick = function () {
this.style.width = '150px'
this.style.height = '150px'
}
// 2 用户如果离开密码框,里面输入个数不是6~16,则提示错误信息,否则提示输入正确信息
// 为输入框添加失焦事件,视角时判断其value是否符合要求触发相应提示
let uNameInput = document.querySelector('.uNameInput')
let uNameCheck = document.querySelector('.uNameCheck')
uNameInput.onblur = function () {
if (this.value.length >= 6 && this.value.length <= 16) {
uNameCheck.innerHTML = '符合命名规则'
uNameCheck.className = 'uNameCheckSuccees'
}
else {
uNameCheck.innerHTML = '不符合命名规则,请重新填写'
uNameCheck.className = 'uNameCheckErro'
}
}
// 3. 排他思想 = > 点击哪个li其设置红色高亮显示,其他li为原始色
// 遍历li集合集体注册点击事件,点击时让所有li class清空,让自身Class为激活状态
let paitLiList = document.querySelectorAll('.paitBox li')
console.log(paitLiList)
for (let i = 0; i < paitLiList.length; i++) {
paitLiList[i].onclick = function () {
for (let i = 0; i < paitLiList.length; i++) {
paitLiList[i].className = 'paitBoxLi'
}
this.className = 'AtivePaitBoxLi'
}
}
</script>
// 开关灯
<body>
密码框:<input type="password" value="" id="psdInput">
<button id="lookPsdBtn">看看密码</button>
</body>
<script>
let psdInput = document.querySelector("#psdInput")
let lookPsdBtn = document.querySelector("#lookPsdBtn")
let ok = true
// 通过ok判断输入框的'type'以及按钮的innerText
// 开关灯思想:开灯后,按钮要提示关灯反之亦然。
// 按钮的值和输入框的类型相反,当输入框类型切换为密码时按钮提示看看密码
lookPsdBtn.onclick = () => {
ok = !ok
if (ok) {
lookPsdBtn.innerHTML = '看看密码'
psdInput.type = 'password'
} else {
lookPsdBtn.innerHTML = '不看密码了'
psdInput.type = ''
}
}
</script>
// 导航栏切换页面
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.tab {
width: 978px;
margin: 100px auto;
}
.tab_list {
height: 39px;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
cursor: pointer;
}
.tab_list .current {
background-color: #c81623;
color: #fff;
}
.item_info {
padding: 20px 0 0 20px;
}
.item {
display: none;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(50000)</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价(50000)模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 菜单项和展示域数量一致
// 通过排他思想设置当前激活的菜单项和显示的菜单区域
// 菜单区域如何匹配相应菜单项? 每次点击为其菜单项添加'index'属性,这样即可对应匹配相应的展示域
var tab_list = document.querySelector('.tab_list')
var lis = tab_list.querySelectorAll('li')
var items = document.querySelectorAll('.item')
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
// 菜单项设置匹配展示域的索引
this.setAttribute("index", i)
for (let i = 0; i < lis.length; i++) {
// 排他
lis[i].className = ''
items[i].style.display = 'none'
}
// 激活自己
this.className = 'current'
items[this.getAttribute('index')].style.display = 'block'
}
}
</script>
节点操作
网页所有内容都是节点(标签 内容 属性 注释
HTML DOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。
节点属性
- nodeType :1 表示元素节点
- nodeType :2 表示属性节点
- nodeType : 3 节点包含文字、空格、换行等
通过节点关系获取节点
<body>
<div class="father">
<p>我是爸爸</p>
<div class="son">
<p>我是哥哥</p>
</div>
<div class="son">
<p>我是弟弟</p>
</div>
</div>
</body>
<script>
// 1. 查找父节点
// 子节点.parentNode 返回最近的父节点;没有节点返回Null
let son = document.querySelector('.son')
let father = son.parentNode
// 2.查找子节点
//父.children
// 是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的)。
let children = father.children
// console.log(children, '子节点集合')
console.log(father.firstChild, '第一个子节点')
// 2.1获取第一个/最后一个子元素节点
// 这两个方法有兼容性问题,IE9 以上才支持。
/* console.log(father.firstElementChild, '第一个元素子节点')
console.log(father.lastElementChild, '最后一个元素子节点'); */
// 处理兼容
console.log(children[0])
console.log(children[length - 1])
// 3. 查找兄弟节点
// 这两个方法有兼容性问题,IE9 以上才支持。
let gege = father.children[1]
// 3.1 获取下一个兄弟元素节点
let didi = gege.nextElementSibling
console.log(didi, '弟弟')
// 3.2 获取上一个兄弟元素节点
console.log(didi.previousElementSibling, '哥哥')
// 3.3 寻找下一个兄弟元素节点的兼容性写法
function nextElementSibling (el) {
let element = el
while (element = element.nextSibling) {
// console.log(element, 'while')
if (element.nodeType === 1) {
return element
}
}
}
console.log(nextElementSibling(gege));
// ***********************************************
</script>
创建节点
<body>
<ul>
<li>01:日本投放和污水</li>
</ul>
</body>
<script>
let ul = document.querySelector('ul')
let ulChildren = ul.children
console.log(ulChildren[0])
// ul第一个子元素li
let fli = ul.firstElementChild
// 1.创建元素节点 document.createElement('标签名')
let newLi = document.createElement('li')
// 2.节点插入内容
newLi.innerHTML = '日本地震了'
/*
3.插入节点
3.1 appendChild(插入元素)
3.1 insertBefore(插入元素, 向谁前插入的节点 )
*/
ul.appendChild(newLi, '向后插入')
ul.insertBefore(newLi, ulChildren[0])
</script>
克隆节点
<body>
<ul>
<li>
点我删除我
</li>
</ul>
</body>
<script>
let ul = document.getElementsByTagName('ul')[0]
let li = ul.children[0]
li.onclick = function () {
// 被克隆元素.cloneNode(true):true为深度克隆可以复制克隆源对象的子节点,false为浅克隆只复制科隆源本身
let newLi = li.cloneNode(true)
ul.appendChild(newLi)
}
</script>
删除节点
<body>
<ul>
<li>
点我删除我
</li>
</ul>
</body>
<script>
let ul = document.getElementsByTagName('ul')[0]
let li = ul.children[0]
li.onclick = function () {
// 父节点.removeChild(要删除的节点)
ul.removeChild(li)
}
</script>
节点增删练习 ——评论框
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
}
textarea {
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul {
margin-top: 50px;
}
li {
width: 300px;
padding: 5px;
background-color: rgb(245, 209, 243);
color: red;
font-size: 14px;
margin: 15px 0;
}
li a {
float: right;
}
</style>
</head>
<body>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul>
</ul>
<script>
var btn = document.querySelector('button')
var text = document.querySelector('textarea')
var ul = document.querySelector('ul')
btn.onclick = function () {
let textValue = text.value
if (!textValue) {
alert('请输入内容')
return
}
let li = document.createElement('li')
li.innerHTML = textValue + '<button onclick = deleteThis(event)>删除</button>'
// ul.appendChild(li)
ul.insertBefore(li, ul.children[0])
}
function deleteThis (event) {
// console.log(event.target)
let thisFather = event.target.parentNode.parentNode.removeChild(event.target.parentNode)
}
</script>
<!-- <script>
// 1. 获取元素
var btn = document.querySelector('button')
var text = document.querySelector('textarea')
var ul = document.querySelector('ul')
// 2. 注册事件
btn.onclick = function () {
if (text.value == '') {
alert('您没有输入内容')
return false
} else {
// console.log(text.value);
// (1) 创建元素
var li = document.createElement('li')
// 先有li 才能赋值
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>"
// (2) 添加元素
// ul.appendChild(li);
ul.insertBefore(li, ul.children[0])
// (3) 删除元素 删除的是当前链接的li 它的父亲
var as = document.querySelectorAll('a')
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
// node.removeChild(child); 删除的是 li 当前a所在的li this.parentNode;
ul.removeChild(this.parentNode)
}
}
}
}
</script> -->
</body>
动态渲染表格练习
<style>
table {
width: 500px;
margin: 100px auto;
border-collapse: collapse;
text-align: center;
}
td,
th {
border: 1px solid #333;
}
thead tr {
height: 40px;
background-color: #ccc;
}
</style>
</head>
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
let table = document.querySelector('table')
// 1.先去准备好学生的数据
var datas = [{
name: '魏璎珞',
subject: 'JavaScript',
score: 100
}, {
name: '弘历',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大猪蹄子',
subject: 'JavaScript',
score: 0
}]
for (let i in datas) {
// 1.生成行
let tr = document.createElement('tr')
for (let v in datas[i]) {
// 2.生成列,循环取出每一列的值后加入到行中
let td = document.createElement('td')
td.innerHTML = datas[i][v]
tr.appendChild(td)
}
// 2.2添加最后一列操作按钮
let lastTd = document.createElement('td')
lastTd.innerHTML = '<button onclick = deleteThis(event)> 删除 </button>'
// 3.把处理完的行放到表格
tr.appendChild(lastTd)
table.appendChild(tr)
}
// 删除当前行
function deleteThis (event) {
event.target.parentNode.parentNode.parentNode.removeChild(event.target.parentNode.parentNode)
}
</script>
</body>
对比三种添加节点方法
document.write()
element.innerHTML
document.createElement()
区别
1. document.write 是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
2. innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘
3. innerHTML 创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
4. createElement() 创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
属性操作
、
自定义属性
//为区分是否为元素内置属性,h5提供设置以data-开头的属性
// 1.
// this.dataset.index = i
// 2.
this.dataset['index'] = i
// 获取自定义属性需添加data-
this.getAttribute('data-index')