API学习03
节点操作
DOM节点:DOM树里每一个内容都称之为节点
节点类型:
- 元素节点:所有的标签,比如body,div,html是根节点
- 属性节点:所有属性,比如href
- 文本节点:所有文本
- 其他
元素节点的增删改查
查找节点:通过元素间的关系查找节点
1.父节点查找
语法: 子元素.parentNode 返回最近一级的父节点,找不到返回null
通过元素父子关系,实现广告关闭
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>广告关闭2</title>
<style>
.ad {
position: relative;
width: 1000px;
height: 200px;
background-color: pink;
margin: 100px auto;
text-align: center;
font-size: 50px;
line-height: 200px;
font-weight: 700;
}
.close {
position: absolute;
right: 20px;
top: 10px;
width: 20px;
height: 20px;
background-color: skyblue;
text-align: center;
line-height: 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="ad">
我是广告
<div class="close">X</div>
</div>
<script>
// 1. 获取事件源
const close = document.querySelector('.close')
// 2. 事件监听
close.addEventListener('click', function () {
// 通过子元素,找到父元素并关闭
close.parentNode.style.display = 'none'
})
</script>
</body>
</html>
实现效果于API案例一样,只是这种方式更简单,不需要再声明父元素
2.子节点查找
语法: 父元素.children
仅获得所有是元素节点的子元素,返回的是一个伪数组
例如,在列表中可以通过ul 找到所有的li
3.兄弟节点查找
语法:
元素.nextElementSibling :获取下一个兄弟节点
元素.previousElementSibling: 获取上一个兄弟节点
增加节点
有一些情况下,我们需要在页面中增加元素,比如点击发布按钮可以增加一条留言
一般增加节点有两步操作:1. 创建一个新节点 2.将创建好的节点添加到指定元素内部
1.创建节点
语法:document.createElement(‘标签名’)
2.增加节点
找到父元素节点,插入创建好的子元素节点
语法:
(1)作为父元素最后子元素插入:父元素.appendChild(要插入的子元素)
(2)插入到父元素某个子元素的前面:父元素.insertBefore(要插入的元素,前一个元素)
<body>
<ul>
<li>我是li</li>
</ul>
<script>
// 1. 通过document.createElement('标签名’)创建节点
const div = document.createElement('div')
// 2. 插入父元素最后
// 这样直接插入body 会插入到 script 标签后面
document.body.append(div)
const ul = document.querySelector('ul')
const li =document.createElement('li')
li.innerHTML = '我也是li'
// 会作为最后一个元素插入到 ul
// ul.append(li)
// 将ul 插入到第一个元素前面
ul.insertBefore(li,ul.children[0])
</script>
</body>
3.克隆节点
语法:元素.cloneNode(布尔值),默认布尔值为false
布尔值为true:代表克隆时会包含后代节点一起克隆
布尔值为false:则代码克隆时不会包含后代节点
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
const ul = document.querySelector('ul')
// 1. 克隆节点
const li = ul.children[0].cloneNode(true)
// 2. 追加到最后
ul.append(li)
// 简单写法
// ul.append(ul.children[0].cloneNode(true))
</script>
</body>
删除节点
在JavaScript原生DOM操作中,要删除元素必须通过父元素删除
语法:父元素.removeChild(要删除的元素)
Window对象
BOM(Browser Object Model)
BOM:浏览器对象模型
var定义的变量、函数可以通过window对象访问,let和const声明的变量不能由window对象直接访问
定时器—延时函数
JavaScript内置的一个用来让代码延迟执行的函数,叫setTimeout,常用于打开软件时倒计时广告
语法:
setTimeout(回调函数,等待的毫秒数)
setTimeout仅仅执行一次,可以理解为一段代码在设定的时间后再执行,即延迟执行,平时省略window
清除延迟函数:
let timer = setTimeout(回调函数,等待时间ms)
clearTimeout(timer)
第一个输出:1111、3333、2222
第二个输出:1111、3333、2222
JS执行机制
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。
这是因为 Javascript 这门脚本语言诞生的使命所致——JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。 应该先进行添加,之 后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。
这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。
JS 执行机制:
- 先执行执行栈中的同步任务。
- 异步任务放入任务队列中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待 状态,
事件循环event loop
location对象
location数据类型是一个对象, 它拆分并保存了 URL
**常用属性和方法 **
-
href 属性获取完整的 URL 地址,对其赋值时用于**地址的跳转 **
-
search 属性获取地址中携带的参数,符号 ?后面部分
-
hash 属性获取地址中的哈希值,符号 # 后面部分
-
reload 方法用来刷新当前页面,现在已经默认没有布尔参数
href实现页面跳转
案例:5s自动跳转页面
<body>
<a href="https://www.baidu.com"><span></span>秒后自动跳转</a>
<script>
// 1. 获取元素
const a = document.querySelector('a')
// 2. 设置定时器
let i = 5
a.children[0].innerHTML = `${i}`
let timeId = setInterval(function (){
// 每一秒减1
i--
if (i===0) {
// 清除定时器
clearInterval(timeId)
// 跳转页面
location.href = a.href
}
a.children[0].innerHTML = `${i}`
},1000)
</script>
</body>
其他属性之后会用的到
navigator对象
navigator的数据类型是对象,该对象记录浏览器自身的一些信息
常用userAgent方法检测浏览器版本及平台
// 检测 userAgent(浏览器信息)
!(function () {
const userAgent = navigator.userAgent
// 验证是否为Android或iPhone
const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/)
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/)
// 如果是Android或iPhone,则跳转至移动站点
if (android || iphone) {
location.href = 'http://m.itcast.cn' }
})()
history对象
本地存储
许多时候当我们进行刷新时数据就会丢失,为了满足越来越多的需求,HTML5提供了解决方案。将数据存储在浏览器当中,设置、存取方便,而且刷新不会丢失。
localStorage
- 存储数据:localStorage.setItem(key, value)
存储的数据只能是字符串,如果是数字会转换为字符串
// 1. 存储数据 键值对
localStorage.setItem('uname','木子')
// localStorage.setItem('uname','mz') 再次输入就是改变uname对应的value值
localStorage.setItem('age',18)
console.log(localStorage.getItem('age')) // 18
console.log(typeof localStorage.getItem('age')) // string
- 获取数据:localStorage.getItem(key) 获取的是key对应的value值
// 2. 获取数据
console.log(localStorage.getItem('uname')) // 控制台输出木子
- 删除数据:localStorage.removeItem(key)
// 3. 删除键值对
localStorage.removeItem('uname')
上面几种方法的参数都是string
sessionStorage
特性:
- 生命周期为关闭浏览器窗口
- 在同一个窗口(页面)下数据可以共享
- 以键值对的形式存储使用
- 用法跟localStorage 基本相同
存储复杂数据类型
本地存储只能存储字符串,无法存储复杂数据类型。
解决:需要将复杂数据类型转换成JSON字符串,再存储到本地
存储数据:localStorage.setItem(key, JSON.stringify(复杂数据类型))
获取数据:JSON.parse(JSON字符串)
<script>
const obj = {
name: '木子',
age: 18,
gender: '女'
}
// 复杂数据类型存储
localStorage.setItem('obj',JSON.stringify(obj))
// 直接使用 localStorage.getItem('obj') 得到的是JSON字符串类型
console.log(localStorage.getItem('obj'))
console.log(typeof localStorage.getItem('obj'))
// 把取出JSON字符串转换为对象
console.log(JSON.parse(localStorage.getItem('obj')))
</script>
字符串拼接-map()、join()
1.map()方法
map方法可以遍历数组,处理数据,并且返回新的数组
2.join()方法
join() 方法用于把数组中的所有元素转换一个字符串,无参默认逗号分隔
<script>
const arr = ['pink','red','blue']
// 1. 数组map()方法
const newArr=arr.map(function (ele,index){
// ele数组元素 index数组下标
console.log(ele)
console.log(index)
// 对每个元素进行字符串拼接
return ele+'颜色'
})
// 输出处理后的新数组
console.log(newArr)
// 2. 数组join()方法
// 无参数默认逗号隔开
console.log(arr.join())
// 将数组的所有元素用空串连接成一个字符串
console.log(arr.join(''))
// 将数组的所有元素用‘、’隔开
console.log(arr.join('、'))
</script>
页面展示
综合案例-学生就业统计表
需求: 录入学生信息,页面刷新数据不丢失
模块分析:
①:新增模块, 输入学生信息,数据会存储到本地存储中
②:渲染模块,数据会渲染到页面中
③:删除模块,点击删除按钮,会删除对应的数据
思路分析:
①:因为页面刷新不丢失数据,所以可能存在已有数据,所以第一步,我们先找本地存储里面查找是否有数据,如果有数据先进行渲染页面,如果没有数据,我们放一个空数组,用来存放数据
②:渲染模块,数据会渲染到页面中
③:新增模块, 输入学生信息,数据会存储到本地存储中,然后渲染页面
④:删除模块,点击删除按钮,会删除对应的数据,然后渲染页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
<title>学生就业统计表</title>
<link rel="stylesheet" href="../iconfont/iconfont.css">
<link rel="stylesheet" href="../css/index.css"/>
</head>
<body>
<h1>学生就业统计表</h1>
<form class="info" autocomplete="off">
<input type="text" class="uname" name="uname" placeholder="姓名"/>
<input type="text" class="age" name="age" placeholder="年龄"/>
<input type="text" class="salary" name="salary" placeholder="薪资"/>
<select name="gender" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
<select name="city" class="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="曹县">曹县</option>
</select>
<button class="add">
<i class="iconfont icon-titian"></i>添加
</button>
</form>
<div class="title">共有数据<span>0</span>条</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>录入时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<!-- <tr>
<td>1</td>
<td>迪丽热巴</td>
<td>23</td>
<td>女</td>
<td>12000</td>
<td>北京</td>
<td>2099/9/9 08:08:08</td>
<td>
<a href="javascript:">
<i class="iconfont icon-shanchu"></i>
删除
</a>
</td>
</tr> -->
</tbody>
</table>
<script>
// 参考数据
// const initData = [
// // {
// // stuId: 1,
// // uname: '迪丽热巴',
// // age: 22,
// // salary: '12000',
// // gender: '女',
// // city: '北京',
// // time: '2099/9/9 08:08:08'
// // }
// ]
// localStorage.setItem('data', JSON.stringify(initData))
// 1. 渲染业务
// 1.1 读取本地存储的数据
// 短路或,如果本地有数据取出渲染,没有数据置空
const arr = JSON.parse(localStorage.getItem('data')) || []
const tbody = document.querySelector('tbody')
// console.log(arr)
// 1.2 map()和join()渲染页面
function render() {
const newArr = arr.map(function (ele, index) {
return `
<tr>
<td>${ele.stuId}</td>
<td>${ele.uname}</td>
<td>${ele.age}</td>
<td>${ele.gender}</td>
<td>${ele.salary}</td>
<td>${ele.city}</td>
<td>${ele.time}</td>
<td>
<a href="javascript:" data-id="${index}">
<i class="iconfont icon-shanchu"></i>
删除
</a>
</td>
</tr>
`
})
tbody.innerHTML = newArr.join('')
// 显示条数
document.querySelector('.title span').innerHTML = newArr.length
}
render()
// 2. 新值业务
// 取消button的默认提交
const info = document.querySelector('.info')
const uname = document.querySelector('.uname')
const age = document.querySelector('.age')
const salary = document.querySelector('.salary')
const gender = document.querySelector('.gender')
const city = document.querySelector('.city')
info.addEventListener('submit', function (e) {
e.preventDefault()
// 非空判断
if (!uname.value || !age.value || !salary.value) {
return alert('输入内容不能为空')
} else {
arr.push(
{
// id这样写是为了删除再添加数据时,id值比页面最后一条数据的id大1,如果按下面直接赋值当进行删除时id值会出现很多问题
// stuId: arr.length+ 1,
stuId: arr[arr.length -1].stuId + 1 || 0,
uname: uname.value,
age: age.value,
salary: salary.value,
gender: gender.value,
city: city.value,
time: new Date().toLocaleString()
}
)
// 对添加的数据进行渲染
render()
// 存储新增加的数据
localStorage.setItem('data', JSON.stringify(arr))
// 重置表单
info.reset()
}
})
// 3. 删除模块
// 事件委托
tbody.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
// 确认框,点击确认返回true
if (confirm('您确定要删除该条数据吗?')) {
// 根据自定义索引找到数据
arr.splice(+e.target.dataset.id, 1)
// 重新渲染页面
render()
// 重新存储,覆盖旧数据
localStorage.setItem('data', JSON.stringify(arr))
}
}
})
</script>
</body>
</html>
效果预览
这个案例id的值类似于学号又相似于序号,但是因为只是抽象的例子,它设定的值并没有现实依据,可能出现一些问题(比如若是当成学号每条数据的id都应该唯一,不应该删除数据的id被新增加的数据占用,又若是按照序号,删除数据后它并不是从1开始的不间断的序号),学习方法即可。
效果预览
信息录入
这个案例id的值类似于学号又相似于序号,但是因为只是抽象的例子,它设定的值并没有现实依据,可能出现一些问题(比如若是当成学号每条数据的id都应该唯一,不应该删除数据的id被新增加的数据占用,又若是按照序号,删除数据后它并不是从1开始的不间断的序号),学习方法即可。