一、WebAPI 背景知识
JS 分成三个大的部分:
- ECMAScript: 基础语法部分
- DOM API: 操作页面结构
- BOM API: 操作浏览器
要想写实际的程序,光会语言是不够的,还需要掌握相关的 "生态”,配套的库 / 框架
对于在浏览器上运行 JS 来说,最最核心的库,就是 DOM API
就是浏览器给 JS 提供的原生接口
基于这样的接口,就可以针对页面的上的元素进行操作了
DOM => 文档 对象 模型
HTML 中,会把每个 html 标签,都视为是一个 JS 中可以操作的对象,操作这个对象就可以影响到界面的显示
浏览器给 JS 提供的 API 非常丰富,也有很多组
DOM API
BOM APl
其实还有一些其他的
websocket APl,canvas APl…
统称为 WebAPI,我们主要是介绍DOM
原生的DOM API 能用,但是并不方便
因此除了原生的 API 之外,也存在了大量的第三方库 / 框架,其中 jquery 就是最知名的一个库
Vue,React 等前端框架,本质上还是对 DOM 的封装
jQuery
jQuery是一套跨浏览器的JavaScript库,简化HTML与JavaScript之间的操作。
特点是轻量级,丰富的DOM选择器,事件、样式、动画支持,Ajax操作支持,可扩展性强
Bootstrap
boostrap是一套追求一致性的框架。
特点是跨设备,跨浏览,响应布局,支持html5 css3,支持less动态样式扩展
jQuery UI
jquery ui是jquery对桌面端的扩展,可以通过可视化界面进行配置。
API:
-
API 是一个更广义的概念,而 WebAPI 是一个更具体的概念,特指 DOM+BOM
-
所谓的 API 本质上就是一些现成的函数 / 对象,让程序猿拿来就用,方便开发
相当于一个工具箱,只不过程序猿用的工具箱数目繁多,功能复杂
DOM:
-
DOM 全称为 Document Object Model.
-
W3C 标准给我们提供了一系列的函数, 让我们可以操作:
- 网页内容
- 网页结构
- 网页样式
DOM 树:
- 一个页面的结构是一个树形结构,称为 DOM 树
重要概念:
-
文档: 一个页面就是一个 文档,使用 document 表示.
-
元素:页面中所有的标签都称为 元素,使用 element 表示.
-
节点:网页中所有的内容都可以称为 节点,(标签节点,注释节点,文本节点,属性节点等),使用 node表示
这些文档等概念在 JS 代码中就对应一个个的对象
所以才叫 “文档对象模型”
二、获取元素
1、querySelector
- 要想操作页面上的元素,就需要先拿到对应的 JS 对象
- DOM 中提供了一组 API 能够获取到网页的元素,最重要的两个:
querySelector
,querySelectorAll
其实是一个 document 这样的对象的属性
页面中的全局对象,一个页面加载好了,就会自动生成一个全局变量,就叫做 document,这里面就有一些属性和方法,让我们来操作页面的内容
<div class="one">
one
</div>
<div class="two">
two
</div>
<ul>
<li>
three
</li>
</ul>
<script>
// querySelector 参数就是一个 CSS 的选择器
let div = document.querySelector('.one');
console.log(div);
// id 选择器
let obj = document.querySelector('#two');
console.log(obj);
// 复合选择器
let obj2 = document.querySelector('ul li');
console.log(obj2);
</script>
页面结果:
one
two
- three
2、querySelectAll
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<script>
let obj2 = document.querySelector('ul li');
console.log(obj2);
</script>
当 querySelector 的参数的选择器,匹配到了多个元素的时候,此时返回的对象,就是匹配结果中的第一个元素
像这种情况,如果我们想把这些 li 都选中,就需要使用 querySelectAll
,querySelectAll 返回的是一个 “数组” ,就包含了所有被选中的元素
let obj2 = document.querySelectorAll('ul li');
但是准确的说,querySelectorAll
返回的不是一个真正的原生数组,而是一个对象,只不过这个对象,有 length,也能够通过下标的方式来访问内部元素
这样的对象使用起来和数组非常相似 (一模一样),称为 “伪数组”
三、事件
1、什么是事件
- JS 要构建动态页面,就需要感知到用户的行为
- 用户对于页面的一些操作(点击,选择,修改等),操作都会在浏览器中产生一个个事件,被 JS 获取到,从而进行更复杂的交互操作
- 浏览器就是一个哨兵,在侦查敌情(用户行为),一旦用户有反应(触发具体动作),哨兵就会点燃烽火台的狼烟(事件),后方就可以根据狼烟来决定下一步的对敌策略
JS 中的很多代码,都是通过 “事件” 来触发的
事件就是浏览器对于用户的操作行为进行了一个 “统称” (准确的说,事件也不一定全是用户操作产生的,但是大部分是的)
例如,鼠标在页面上移动,就会产生一个鼠标移动事件
再例如,鼠标在页面某个位置点击,就会产生一个鼠标点击事件。再例如,鼠标滚轮,来滚动页面,就会产生一组滚动事件。再例如,用户按下键盘的某个按键,也会产生一个键盘事件。再例如,用户修改浏览器窗口大小,也会产生一个窗口大小改变事件
JS 干的一个主要工作,就是在不同的事件中,进行不同的处理
2、事件三要素
- 事件源 :哪个HTML元素产生的事件.
- 事件类型 :鼠标移动 / 鼠标点击 / 键盘事件 / 窗口大小改变事件…
- 事件的处理程序 :当事件产生之后,执行什么样的 JS 代码,进一步如何处理,往往是一个回调函数
3、点击事件
<!-- 事件源:button -->
<button>这是一个按钮</button>
<script>
let button = document.querySelector('button');
// 事件类型:onclick 事件处理函数:function
button.onclick = function() {
alert('hello');
}
</script>
称此函数为回调函数:这个函数不会立即调用,而是在合适的实际,被 库 / 框架 自动的调用
另一种写法:这个写法,就把页面 (HTML) 写的更乱,我们期望 结构,样式,行为,能够分离
<button onclick="f()">这是一个按钮</button>
<script>
function f() {
alert('hello');
}
</script>
四、操作元素
操作 = 获取+修改
- 操作元素内容
- 操作元素的属性
- 操作元素的样式
1、操作元素内容
通过 对象 里面的一个属性 innerHTML 来实现 (元素里面包含的 html 代码是什么样子的)
1.1、 打印内容
<div id="screen">hello world</div>
<button id="btn">这是一个按钮</button>
<script>
let btn = document.querySelector('#btn');
btn.onclick = function() {
let screen = document.querySelector('#screen');
console.log(screen.innerHTML);
}
</script>
当我们点击多次按钮,可以看到,在控制台上,并没有显示多条数据,而是显示了个数字,控制台默认下会把相同的打印合并成一条的,可以设置在控制台中对相似消息进行分组
1.2、获取内容按钮
<div id="screen">
<ul>
<li>aaa</li>
<li>aaa</li>
<li>aaa</li>
</ul>
</div>
<button id="btn">获取内容按钮</button>
1.3、 修改内容按钮
<div id="screen">
<ul>
<li>aaa</li>
<li>aaa</li>
<li>aaa</li>
</ul>
</div>
<button id="btn">修改内容按钮</button>
<script>
let btn = document.querySelector('#btn');
btn.onclick = function() {
let screen = document.querySelector('#screen');
screen.innerHTML = '<h1>修改后的内容</h1>'
}
</script>
1.4、点击加一
div 显示整数,一个按钮,每次点击这个按钮,就让里面的整数+1
注意: 这里,innerHTML 得到的是 string 类型,要想进行数字相加,就需要把字符串转成整数
let val = screen.innerHTML;
console.log(typeof(val)); // string
val = parseInt(val);
Java 里的 parselnt 是 Integer 类的成员方法。此处 JS 中的 parselnt 相当于是一个全局的函数
由于 JS 是动态类型,转换成数字之后,仍然可以赋值给 valval,就从 string => number 类型
<div id="screen">
0
</div>
<button id="plus">+</button>
<script>
let plusBtn = document.querySelector('#plus');
plusBtn.onclick = function() {
// 1、获取 screen 的值
let screen = document.querySelector('#screen');
let val = screen.innerHTML;
val = parseInt(val);
// 2、将这个值 + 1
val = val + 1;
// 3、把新值写回去
screen.innerHTML = val;
}
</script>
1.5、input 点击加一
<input type="text" id="screen">
input 作为一个单标签(单身狗),不配拥有 innerHTML,此处是通过 input 的 value 属性,来获取到内部的内容的
<input type="text" id="screen" value="0">
<button id="plus">+</button>
<script>
let plusBtn = document.querySelector('#plus');
plusBtn.onclick = function() {
// 1、获取 screen 的值
let screen = document.querySelector('#screen');
let val = screen.value;
val = parseInt(val);
// 2、将这个值 + 1
val = val + 1;
// 3、把新值写回去
screen.value = val;
}
</script>
2、操作元素的属性
2.1、点击切换图片
通过 dom 对象 . 属性名 就可以进行操作了
<img src="picture1.jpg" alt="">
<script>
let img = document.querySelector('img');
img.onclick = function() {
console.log(img.src); // 打印 src 属性的内容
if (img.src.indexOf('picture1.jpg') >= 0) {
img.src = 'picture2.jpg';
} else if (img.src.indexOf('picture2.jpg') >= 0) {
img.src = 'picture1.jpg';
}
}
</script>
一个 HTML 标签里,能写哪些属性,就同样可以通过 JS 中的 DOM 对象来获取到一样的属性,
可以通过 console.dir
这个方法,打印出一个 dom 对象的全部属性和值
console.dir(img);
3、获取/修改表单元素属性
表单 (主要是指 input 标签) 的以下属性都可以通过 DOM 来修改
value
: input 的值.disabled
: 禁用checked
: 复选框会使用selected
: 下拉框会使用type
: input 的类型(文本, 密码, 按钮, 文件等)
这些属性,都属于表单元素专有的属性
3.1、点击计数
使用一个输入框输入初始值(整数). 每次点击按钮, 值 + 1
<input type="text" id="text" value="0">
<input type="button" id="btn" value='点我+1'>
<script>
var text = document.querySelector('#text');
var btn = document.querySelector('#btn');
btn.onclick = function () {
var num = +text.value;
console.log(num);
num++;
text.value = num;
}
</script>
- input 具有一个重要的属性 value, 这个 value 决定了表单元素的内容
- 如果是输入框, value 表示输入框的内容, 修改这个值会影响到界面显式; 在界面上修改这个值也会影响到代码中的属性
- 如果是按钮, value 表示按钮的内容. 可以通过这个来实现按钮中文本的替换
3.2、切换按钮的文本
假设这是个播放按钮, 在 “播放” - “暂停” 之间切换
<input type="button" value="播放">
<script>
let input = document.querySelector('input');
input.onclick = function() {
if (input.value == '播放') {
input.value = '暂停';
} else if (input.value == '暂停') {
input.value = '播放';
}
}
</script>
3.3、全选 / 取消全选按钮
实现一个全选效果,主要是操作 input 的 checked 属性
- 点击全选按钮,则选中所有选项
- 只要某个选项取消,则自动取消全选按钮的勾选状态
<input type="checkbox" id="all"> 全选 <br>
<input type="checkbox" class="girl"> 薛宝钗 <br>
<input type="checkbox" class="girl"> 林黛玉 <br>
<input type="checkbox" class="girl"> 王熙凤 <br>
<input type="checkbox" class="girl"> 贾探春 <br>
<script>
// 1、获取元素
let all = document.querySelector('#all');
let girls = document.querySelectorAll('.girl'); //
// 2、给 all 注册点击事件
all.onclick = function() {
for (let i = 0; i < girls.length; i++) {
// all.checked 就是 all 这个复选框的选中状态
girls[i].checked = all.checked;
}
}
// 3、针对每个 girl 注册点击事件,实现对于 all 的取消操作
for (let i = 0; i < girls.length; i++) {
girls[i].onclick = function() {
all.checked = checkGirls(girls);
}
}
function checkGirls(girls) {
// 判断是不是所有的 girl 都被选中了
for (let i = 0; i < girls.length; i++) {
if (!girls[i].checked) {
// 只要有一个是未选中,all 就是未选中状态
return '';
}
}
// 遍历完,所有都是选中状态,就让 all 也是选中状态
return 'checked';
}
</script>
4、操作元素样式
本质上也是操作元素属性
style
对应行内样式 (直接把样式写到 style 里面)className
/classList
对应 内部样式 / 外部样式,应用了一个 / 一组 CSS 类名
4.1、点击加字体大小
let div = document.querySelector('div');
div.onclick = function() {
// 1、获取当前的字体大小
console.log(div.style.fontSize);
}
注意:
1、CSS 不区分大小 写,一般不用驼峰。JS 不能支持 –
作为变量名,不能使用脊柱。所有的 CSS 属性都是同样的规则映射过去的
2、当前这里得到 fontSize 是一个字符串,要想相加,就得转成整数
‘20px’ => parselnt => 20
parselnt 转换的时候,会从头往后去转换,遇到非数字字符 ‘px’ ,就转换停止了
3、当修改CSS属性值的时候,一定要注意单位!! 如果单位不合适 / 遗漏,就会失效
<div style="font-size: 20px;">这是一个文本</div>
<script>
let div = document.querySelector('div');
div.onclick = function() {
// 1、获取当前的字体大小
console.log(parseInt(div.style.fontSize));
let fontSize = parseInt(div.style.fontSize);
// 2、在当前字体大小的基础上,多增加 5px
fontSize += 5;
div.style.fontSize = fontSize + 'px';
}
</script>
在 HTML 中,表示类名的属性,就是 class
但是在 JS 里,属性名变成了 className
/ classList
,为什么不直接使用 class
这个名字?
class
在 JS 中也是一个关键字 ( JS ES6 版本以上,也引入了类这个概念)
如果要修改的样式比较多,通过 style 来修改就麻烦了,可以直接借助 CSS 类来修改
4.2、夜间模式
<style>
.light {
background-color: #fff;
color: #000;
}
.dark {
background-color: #000;
color: #fff;
}
</style>
<div class="light" style="height: 300px;">这是一段话</div>
<button>关灯</button>
<script>
let div = document.querySelector('div');
let button = document.querySelector('button');
button.onclick = function() {
if (div.className == 'light') {
div.className = 'dark';
button.innnerHTML = '开灯';
} else if (div.className == 'dark') {
div.className = 'light';
button.innerHTML = '关灯';
}
}
</script>
4.4、切换颜色
部署到 tomcat \webapps\ROOT 中
<style>
div {
width: 500px;
height: 300px;
font-size: 20px;
font-weight: bold;
text-align: center;
line-height: 300px;
background-image: url(f:/Photos/520.png);
background-size: 100%, 100%;
}
.one {
color: orange;
}
.two {
color: green;
}
button {
width: 150px;
height: 50px;
background-color: rgb(0, 128, 128);
border-radius: 10px;
border: none;
outline: none;
}
button:active {
background-color: #666;
}
</style>
<div class="one">have a good day!</div><br>
<button style="font-size: 17px;">orange</button>
<script>
let div = document.querySelector('div');
let button = document.querySelector('button');
button.onclick = function() {
if (div.className == 'one') {
div.className = 'two';
button.innerHTML = 'green';
} else if (div.className == 'two') {
div.className = 'one';
button.innerHTML = 'orange';
}
}
</script>
5、操作节点
针对元素操作,其实是操作元素的属性 (元素本身没有发生改变)
针对节点操作,其实是新增节点 / 删除节点
5.1、新增节点
分成两个步骤:
创建元素节点
把元素节点插入到 dom 树中
第一步相当于生了个娃, 第二步相当于给娃上户口
创建新节点:
使用 createElement
方法来创建一个元素,options 参数暂不关注
<script>
let newDiv = document.createElement('div'); // 创建标签
newDiv.id = 'newDiv';
newDiv.className = 'one';
newDiv.innerHTML = 'hello';
console.log(newDiv);
</script>
此处创建的节点,并没有被挂在 dom 树上,因此浏览器页面中,是显示不出来的
上面介绍的只是创建元素节点, 还可以使用:
createTextNode 创建文本节点
createComment 创建注释节点
createAttribute 创建属性节点
我们以 createElement 为主即可
把节点挂在dom树上:
使用 appendChild
把节点插入到某个节点插入到指定节点的最后一个孩子之后
<div class="container"></div>
<script>
let newDiv = document.createElement('div'); // 创建标签
newDiv.id = 'newDiv';
newDiv.className = 'one';
newDiv.innerHTML = 'hello';
console.log(newDiv);
let container = document.querySelector('.container');
container.appendChild(newDiv);
</script>
还可以使用 insertBefore 将节点插入到指定节点之前
- var insertedNode = parentNode.insertBefore(newNode, referenceNode);
- insertedNode 被插入节点(newNode)
- parentNode 新插入节点的父节点
- newNode 用于插入的节点
- referenceNode newNode 将要插在这个节点之前
如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾.
注意: referenceNode 引用节点不是可选参数
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv, container.children[0]);
</script>
注意1: 如果针对一个节点插入两次, 则只有最后一次生效(相当于把元素移动了)
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
// 此处的 children 里有 4 个元素
container.insertBefore(newDiv, container.children[0]);
// 此处的 children 里有 5 个元素(上面新插了一个), 0 号元素是 新节点,
// 1 号元素是 11, 2号节点是 22, 所以是插入到 22 之前.
container.insertBefore(newDiv, container.children[2]);
</script>
注意2: 一旦一个节点插入完毕, 再针对刚刚的节点对象进行修改, 能够同步影响到 DOM 树中的内容
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
var newDiv = document.createElement('div');
newDiv.innerHTML = '我是新的节点';
var container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv, container.children[0]);
// 插入完毕后再次修改 newDiv 的内容
newDiv.innerHTML = '我是新节点2';
</script>
5.2、删除节点
删除节点,removeChild
方法来实现
得先拿到父节点,然后再拿到待删除的子节点,通过 removeChild
就能删除了
- oldChild = element.removeChild(child);
- child 为待删除节点
- element 为 child 的父节点
- 返回值为该被删除节点
- 被删除节点只是从 dom 树被删除了, 但是仍然在内存中, 可以随时加入到 dom 树的其他位置.
- 如果上例中的 child节点 不是 element 节点的子节点,则该方法会抛出异常
<div class="container"></div>
<button>删除 div</button>
<script>
let newDiv = document.createElement('div'); // 创建标签
newDiv.id = 'newDiv';
newDiv.className = 'one';
newDiv.innerHTML = 'hello';
console.log(newDiv);
let container = document.querySelector('.container');
container.appendChild(newDiv);
let button = document.querySelector('button');
button.onclick = function() {
container.removeChild(newDiv); // 前面已经获取了
}
</script>
五、代码案例
1、猜数字
Math.random 得到的 [0,1) 随机的 小数 ,如何生成 1 - 100 呢?
先 *100,得到 [0,100) 之间的小数。然后向下取整Math.floor
,也就是直接舍弃小数部分
<button id="resetBtn">重新开始一局游戏</button> <br>
<span>要猜的数字:</span>
<input type="text">
<button id="guessBtn">猜</button> <br>
<span>结果:</span> <span id="result"></span> <br>
<span>已经猜的次数:</span> <span id="guessCount">0</span>
<script>
// 1、需要用到的元素
let resetBtn = document.querySelector('#resetBtn');
let input = document.querySelector('input');
let guessBtn = document.querySelector('#guessBtn');
let resultSpan = document.querySelector('#result');
let guessCountSpan = document.querySelector('#guessCount');
// 2、生成一个 1 - 100 的随机数
let toGuess = Math.floor(Math.random() * 100) + 1;
console.log(toGuess);
// 3、实现点击 猜 按钮的逻辑
guessBtn.onclick = function() {
// 1) 读取 input 输入的内容,转成整数
if (input.value == '') {
return;
}
let curNum = parseInt(input.value);
// 2) 判断大小 给出提示
if (curNum < toGuess) {
resultSpan.innerHTML = '低了';
resultSpan.style.color = 'red';
} else if (curNum > toGuess) {
resultSpan.innerHTML = '高了';
resultSpan.style.color = 'red';
} else {
resultSpan.innerHTML = '猜对了';
resultSpan.style.color = 'green' ;
}
// 3) 更新猜的次数
let guessCount = parseInt(guessCountSpan.innerHTML);
guessCountSpan.innerHTML = guessCount + 1;
}
// 4、实现 reset 操作,开始游戏
resetBtn.onclick = function() {
// 让页面刷新即可
// location 是和 document 并列关系的对象,用来控制页面的链接/地址,通过 reload 操作就可以刷新页面
location.reload();
}
</script>
2、表白墙
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100%;
}
h3 {
text-align: center;
padding: 30px 0; /* 上下内边距 20,左右为 0 */
font-size: 24px;
}
p {
text-align: center;
color: #999;
padding: 10px 0;
}
.row {
width: 400px;
height: 50px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.row span {
width: 60px;
font-size: 20px;
}
.row input {
width: 300px;
height: 40px;
line-height: 40px;
font-size: 20px;
text-indent: 0.5em;
/* 去掉输入框的轮廓线 */
outline: none;
}
.row #submit {
width: 200px;
height: 40px;
font-size: 20px;
line-height: 40px;
margin: 0 auto;
color: white;
background-color: orange;
/* 去掉边框 */
border: none;
border-radius: 10px;
}
/* 按下的效果 */
.row #submit:active {
background-color: grey;
}
</style>
<div class="container">
<h3>表白墙</h3>
<p>输入后点击提示,会将信息显示在表格中</p>
<div class="row">
<span>谁:</span>
<input type="text">
</div>
<div class="row">
<span>对谁:</span>
<input type="text">
</div>
<div class="row">
<span>说:</span>
<input type="text">
</div>
<div class="row">
<button id="submit">提交</button>
</div>
</div>
<script>
// 当用户点击 submit,就会获取 input 中的内容,把内容构造成一个 div,插入页面末尾
let submitBtn = document.querySelector('#submit');
submitBtn.onclick = function() {
// 1、获取 2 个 input
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let msg = inputs[2].value;
if (from == '' || to == '' || msg == '') {
// 用户还未填写完毕
return;
}
// 2、生成一个新的 div,内容就是 input 中的内容,新的 div 加到页面中
let div = document.createElement('div');
div.innerHTML = from + ' 对 ' + to + ' 说 ' + msg;
div.className = 'row'; // 应用 row 的样式
let container = document.querySelector('.container');
container.appendChild(div);
// 3、清空之前输入框的内容
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
}
</script>
刚才咱们写的表白墙程序,是通过一些 div.row 来保存咱们提交的消息,这些 div.row,是挂在, DOM,树上,就是在内存中的,容易失去的
一旦页面刷新 / 关闭了,此时,之前内存中保存的数据,就没了
为了解决上述的数据容易丢失问题,有以下解决方案:
-
可以把提交的数据,保存在浏览器本地 (浏览器提供了 localStorage / indexDB 这样的机制,能够实现本地存储),本质上,是通过浏览器,把你要存的数据,存到当前电脑的磁盘上
问题:只有我在自己的电脑上能看到,别人看不到 -
可以把提交的数据,通过网络通信,传输给服务器,由服务器进行保存
- 服务器保存在内存里
- 服务器保存在文件中
- 服务器保存在数据库里
3、待办事项
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 800px;
margin: 0 auto;
display: flex;
}
.todo,
.done {
width: 50%;
height: 100%;
}
.container h3 {
height: 50px;
text-align: center;
line-height: 50px;
background-color: #333;
color: #fff;
}
.nav {
width: 800px;
height: 100px;
margin: 0 auto;
display: flex;
align-items: center;
}
.nav input {
width: 600px;
height: 50px;
}
.nav button {
width: 200px;
height: 50px;
border: none;
background-color: orange;
color: #fff;
}
.row {
height: 50px;
display: flex;
align-items: center;
}
.row input {
margin: 0 10px;
}
.row span {
width: 300px;
}
.row button {
width: 50px;
height: 40px;
}
</style>
<div class="nav">
<input type="text">
<button>新建任务</button>
</div>
<div class="container">
<div class="todo">
<h3>未完成</h3>
<div class="row">
<input type="checkbox">
<span>任务</span>
<button>删除</button>
</div>
</div>
<div class="done">
<h3>已完成</h3>
</div>
</div>
<script>
// 一、实现新增任务
let addTaskButton = document.querySelector('.nav button');
addTaskButton.onclick = function () {
// 1. 获取到任务内容的输入框
let input = document.querySelector('.nav input');
// 2. 获取到输入框内容
let taskContent = input.value;
// 3. 根据内容新建一个元素节点
let row = document.createElement('div');
row.className = 'row';
let checkbox = document.createElement('input');
checkbox.type = 'checkbox';
let span = document.createElement('span');
span.innerHTML = taskContent;
let button = document.createElement('button');
button.innerHTML = '删除';
row.appendChild(checkbox);
row.appendChild(span);
row.appendChild(button);
// 4. 把新节点插入到 todo 中
let todo = document.querySelector('.todo');
todo.appendChild(row);
// 二、点击复选框后将元素放到 "已完成"
// 在事件回调函数中使用 this 能够获取到当前处理事件的元素.
// 通过 this.parentNode 属性能够获取到当前元素的父元素.
// 点击 checkbox 时, 会先修改 value , 再触发点击事件
// 修改 addTaskButton.onclick
// 5. 给 checkbox 注册点击事件
checkbox.onclick = function () {
//
var row = this.parentNode;
// 注意! 是先触发 checked 为 true, 然后再调用 onclick 函数
if (this.checked) {
var target = document.querySelector('.done');
} else {
var target = document.querySelector('.todo');
}
target.appendChild(row);
}
// 三、点击删除按钮删除该任务
// 6. 给删除按钮注册点击事件
button.onclick = function () {
let row = this.parentNode;
let grandParent = row.parentNode;
grandParent.removeChild(row);
}
}
</script>