目录
前言
通过学习的过的JS代码语法,我们可以去操作DOM树(由html的标签构造的一棵树),修改树结构进而影响用户在浏览器上看到的最终效果
如何在JS中得到DOM树对象:通过文档对象
window.document 对象(表现为文档,但我们可以通过文档去操作树)
如何定位出一个/一批节点对象+结合css选择器语法
document.querySelector('#hello') -- ID选择器
找到树中id是hello的节点对象,如果不存在的话,得到undefin或者null
document.querySelector('.hello') -- 类选择器
document.querySelector('p') -- 元素选择器
PS:
querySelector(...)符合条件的节点对象可能会存在多个,但是只会返回第一个满足条件的
文档中从上到下的顺序,树中深度优先遍历的顺序
querySelectorAll(...)找到符合条件的所有对象
一、基本用法举例
ex1:换图片
<img id="i1" src="xxx">
var i1 = document.querySelector("#i1")
i1.src = 'yyy'
ex2:修改h1标签的内容
<h1>今天是 2023 年</h1>
var h1 = document.querySelector('h1')
下面两个都可以修改
h1.innerText = 'xxx'
h1.textContent = 'yyy' //推荐这个
ex3: 修改单选框选择的选项
<div>
男 <input type="radio" name="gender" id="male">
女 <input type="radio" name="gender" id="female" checked>
</div>
var male = document.querySelector('#male')
var female = document.querySelector('#female')
//如果之前选择了男
male.checked = true;
female.checked = false;
//将选择修改成女
female.checked = true;
小结:
一、凡是html标签的属性,都可以修改,例如:
1)input的value
2)checked boolean属性
3)textContent代表标签下的文本
二、由于JS中对应key没有约束,一旦写错单词拼写,修改不会生效,控制台也不会报错
ex4: 直接修改树的结构--节点+innerHTML
<div id="d1">
<h2>整体会被替换</h2>
<p id="p1">Black</p>
<p id="p2">White</p>
</div>
修改id为d1的节点下的树结构
var d1 = document.querySelector("#d1")
d1.innerHTML = "<a href='https://www.baidu.com'>百度一下</a>"
修改之后
<div id="d1">
<a href='https://www.baidu.com'>百度一下</a>
</div>
PS: d1.outerHTML是什么
d1.innerHTML是d1标签下的子树
d1.outerHTML是d1标签下的子树+d1这个标签的结点
ex5 通过创建新结点并插入的方式修改树结构
1)如何创建结点对象
document.createElement('img') --创建了一个img元素(标签)
document.createElement('div') --div
document.createElement('table') --table
此时创建的元素不在DOM树中
2)将某个创建好的节点插入到树中
先找到某个结点a
创建节点b
把b作为a的孩子插入
a.appendChild(b); --为a元素追加一个孩子b
二、事件驱动(even-driven)-例子
ex1: 鼠标点击弹窗
<body>
<!-- type="button" 就表示这个按钮不会进行 form 表单的提交 -->
<button type="button">按钮</button>
<script src="script.js"></script>
</body>
function 弹框() {
alert("用户点击了按钮");
}
// 找到事件源元素
var btn = document.querySelector('button')
// 为 按钮元素的 点击(click)事件,绑定后续处理函数 —— 弹框
btn.onclick = 弹框;
// 语义上: on 是 当的意思
// 语法角度:修改 btn 的 onclick 属性
// 赋值了一个函数
// 事件驱动模型:btn 的 click 事件 的后续处理是 调用弹窗函数
// 注意两个易错的地方:
// 1)onclick 拼写错误 不会报错,但是没有效果
// 2)= 弹窗 把函数赋值给属性, 而不是 = 弹窗(); 把函数调用的返回值赋值给属性
ex2: 点击计数器
<body>
<input type="text" id="counter" value="0" disabled>
<!-- <input type="text" id="counter" value="0" readonly>-->
<button type="button" id="btn">点击 + 1</button>
<script src="script.js"></script>
</body>
<!-- 这里的disabled和readonly就是不让用户在输入框输入数据,防止错误,因为一旦用户输入的是nan,则功能无法正常使用-->
var eCounter = document.querySelector("#counter");
var eBtn = document.querySelector("#btn");
// 为按钮绑定一个点击事件
eBtn.onclick = function() {
// 让 eCounter 的 value 自动 + 1
// eCounter.value 的类型是字符串
// 需要一个字符串转数字的方法 : parseInt(...)
var v = parseInt(eCounter.value);
// v 一定是数字类型
eCounter.value = v + 1;
};
ex3: 自动计时,每秒自动+1
此时事件的来源就不是用户点击,而是根据定时器
JS中的定时器函数 :
1) setTimeout(函数名称,以毫秒为单位的时间)
经过xxx时间后,调用一次传入的函数,只有一次
2) setInterval(函数名称,以毫秒为单位的时间)
从此刻起,每经过xxx时间后,就调用一次传入的函数,重复调用
<body>
<input type="text" id="counter" value="0" disabled>
<script src="v2.js"></script>
</body>
var eCounter = document.querySelector("#counter");
// 设置一个间隔行为:每 1秒(1000 毫秒)执行一次函数
setInterval(function () {
var v = parseInt(eCounter.value);
eCounter.value = v + 1;
}, 1000);
ex4: 点击修改字体大小
<div style="font-size: 16px; font-weight: 700">点击我试试看</div>
var eDiv = document.querySelector("div");
eDiv.onclick = function() {
var fontSize = parseInt(eDiv.style.fontSize);
fontSize += 10;
if (fontSize > 100) {
fontSize = 16;
}
//不能写font-size,只能驼峰写
eDiv.style.fontSize = fontSize + "px";
}
//同样,如果修改背景颜色,不能直接写background-color
//应该写eDiv.style.backgroundColor = "red";
<style>
div {
user-select: none; /* 无法被选中 */
cursor: pointer; /* 鼠标形状变成手的形状 */
}
</style>
ex5: 夜间模式
<div>
<input type="checkbox" id="light-dark"> 夜间模式
</div>
var eCheckbox = document.querySelector("#light-dark");
var eBody = document.querySelector("body");
eCheckbox.onclick = function() {
if (eCheckbox.checked) {
eBody.classList.add("dark");
} else {
eBody.classList.remove("dark");
}
}
ex6: 简易记事本
<div>
<input type="text">
<button type="button">记录</button>
</div>
<div>
<table>
<thead>
<tr>
<th>编号</th>
<th>内容</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
var eInput = document.querySelector("input");
var eBtn = document.querySelector("button");
var eTBody = document.querySelector("tbody");
// 记录全局的编号
var no = 1;
eBtn.onclick = function() {
var content = eInput.value;
// content 是字符串类型
// trim : 裁剪
// trim() 去掉字符串的两边的空白字符(空格、制表符)
content = content.trim();
if (content.length === 0) {
return;
}
var eNoTd = document.createElement("td");
eNoTd.textContent = no;
no++;
var eContentTd = document.createElement("td");
eContentTd.textContent = content;
var eTr = document.createElement("tr");
eTr.appendChild(eNoTd);
eTr.appendChild(eContentTd);
eTBody.appendChild(eTr);
}
ex7: 猜数字
<body>
<div>
<input style="width: 380px;" type="text" placeholder="请输入要猜的数字:1 到 100 之间,包含 1 和 100">
<button type="button" id="guessBtn">猜</button>
<button type="button" id="restartBtn">重新开始</button>
</div>
<div>
已经猜了 <span>0</span> 次。
<ol></ol>
</div>
<script src="script.js"></script>
</body>
var eInput = document.querySelector("input");
var guessBtn = document.querySelector("#guessBtn");
var restartBtn = document.querySelector("#restartBtn");
var eOrderedList = document.querySelector("ol");
var eSpan = document.querySelector("span");
// 一开始先生成一个随机数
var target = Math.floor(Math.random() * 100) + 1;
console.log("DEBUG: 目标随机数是: " + target);
// 提前记录已经猜了多少次
var count = 0;
function outputError(message) {
var eListItem = document.createElement("li");
eListItem.textContent = message;
eListItem.style.color = "red";
eOrderedList.appendChild(eListItem);
}
function outputMessage(message) {
var eListItem = document.createElement("li");
eListItem.textContent = message;
eOrderedList.appendChild(eListItem);
}
// 为 guessBtn 绑定点击事件
guessBtn.onclick = function() {
var v = eInput.value.trim();
eInput.value = "";
if (v.length === 0) {
eInput.value = "";
return;
}
if (isNaN(v)) {
outputError("请输入合法的数字:1 到 100 之间的整数。");
return;
}
v = parseInt(v);
if (v < 1 || v > 100) {
outputError("请输入合法的数字:1 到 100 之间的整数。");
return;
}
count++;
eSpan.textContent = count;
if (v === target) {
outputMessage(v + ": 猜对了,游戏结束。");
// TODO: 猜对了,就让游戏停止(输入框不能输东西了,用户点击按钮也没用了)
eInput.disabled = true;
} else if (v < target) {
outputMessage(v + ": 猜小了。");
} else {
outputMessage(v + ": 猜大了。");
}
if (count === 5) {
outputError("最多只能猜 5 次,游戏结束。");
eInput.disabled = true;
}
};
restartBtn.onclick = function() {
// 1. 重新生成随机数
target = Math.floor(Math.random() * 100) + 1;
console.log("DEBUG: 目标随机数是: " + target);
// 2. 计数器归零
count = 0;
eSpan.textContent = count;
// 3. 清空结果面板 :删除 ol 的所有子元素
// ol.innerHTML = "";
eOrderedList.innerHTML = "";
// 4. 把 input 标签打开
eInput.disabled = false;
eInput.value = "";
};