js进阶-WebAPIs-DOM

一、Web APIs

1、 Web APIs与JS基础关联性

JS基础阶段:

  • 我们学习的是ECMAscript标准规定的基本语法

  • 要求同学们掌握Js基础语法

  • 只学习基本语法,做不了常用的网页交互效果

  • 目的是为了Js后面的课程打基础、做铺垫

Web APls阶段:

  • web APIs是w3c组织的标准

  • web APIs 我们主要学习DoM和BOM

  • web APIs 是我们Js 所独有的部分

  • 我们主要学习页面交互功能

  • 需要使用Js 基础的课程内容做基础

  • Js 基础学习ECMAscript 基础语法为后面作铺垫,web APIs是Js 的应用,大量使用Js 基础语法做交互效果

2、 DOM

2.1 简介

文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口

2.2 获取元素

因为文档页面从上往下加载,因此先得有标签,所以script要写到标签下面

2.2.1 根据ID获取

document.getElementById()

返回的是一个元素对象

<div id="time">2019-9-9</div>
<script>
// 1.因为我们文档页面从上往下加载,所以得先有标签,所以script写在标签下面
// 2.get 获得 element 元素 by 通过 驼峰命名法
// 3.参数 id是大小写敏感的字符串
// 4.返回的是一个元素对象
var timer = document.getElementById('time');
console.log(timer);
// 5. console.dir 打印我们的元素对象,更好的查看里面的属性和方法
console.dir(timer);
</script>

2.2.2 根据标签名获取

doucument.getElementsByTagName('标签名');

返回的是获取过来元素对象的集合 以伪数组的形式存储

<ul>
<li>知否知否,应是等你好久1</li>
<li>知否知否,应是等你好久2</li>
<li>知否知否,应是等你好久3</li>
<li>知否知否,应是等你好久4</li>
<li>知否知否,应是等你好久5</li>
</ul>
<script>
// 1.返回的是获取过来元素对象的集合 以伪数组的形式存储
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);
// 2.依次打印,遍历
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
// 3.如果页面中只有 1 个 li,返回的还是伪数组的形式
// 4.如果页面中没有这个元素,返回的是空伪数组
</script>

还可以根据标签名获取某个元素(父元素)内部所有指定标签名的子元素,获取的时候不包括父元素自己
父元素必须是单个指定元素

element(某个元素).getElementsByTagName('标签名')
<ul>
<li>知否知否,应是等你好久1</li>
<li>知否知否,应是等你好久2</li>
<li>知否知否,应是等你好久3</li>
<li>知否知否,应是等你好久4</li>
<li>知否知否,应是等你好久5</li>
</ul>
<ol id="ol">
<li>生僻字1</li>
<li>生僻字2</li>
<li>生僻字3</li>
<li>生僻字4</li>
<li>生僻字5</li>
</ol>
<script>
var a = document.getElementsByTagName('ol');//将所有的ol都找出来,形成一个伪数组
console.log(a);
console.log(a[0].getElementsByTagName('li'));//在父元素中查找li,在伪数组中选取父类
</script>

也可以根据id实现

var a = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));

2.2.3 通过HTML5新增的元素

  • 根据类名返回元素对象合集 :

document.getElementsByClassName('类名');

<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav"></div>
<script>
var boxs = document.getElementsByClassName('box');
console.log(boxs);
</script>
  • 根据指定选择器返回第一个元素对象
    document.querySelector('选择器')
var firstb = document.querySelector('.box')
console.log(firstb);
var navs = document.querySelector('#nav')//也可以用来选择id名
console.log(navs);
//也可以选择标签,只能得到第一个对象
  • 返回指定选择器的所有元素对象集合
    document.querySelectorAll('选择器')
var allb = document.querySelectorAll('.box')
console.log(allb);

2.2.4 获取特殊标签

  • 获取body元素 返回body元素对象
    document.body;

  • 获取html元素 返回html元素对象
    document.documentElement;

2.3 事件基础

  • JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。

  • 简单理解: 触发— 响应机制。

  • 网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。

2.3.1 事件三要素

  • 事件源(谁)

  • 事件类型(什么事件)

  • 事件处理程序(做什么)

<script>
// 点击一个按钮,弹出对话框
// 1. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素
//(1) 事件源 事件被触发的对象 谁 按钮
var btn = document.getElementById('btn');
//(2) 事件类型 如何触发 什么事件 比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
//(3) 事件处理程序 通过一个函数赋值的方式 完成
btn.onclick = function() {
alert('秋香');
}
</script>

2.3.2 执行事件的步骤

  • 获取事件源

  • 注册事件(绑定事件)

  • 添加事件处理程序(采取函数赋值形式)

2.3.3 鼠标事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

2.4 操作元素

2.4.1 改变元素内容

  • element.innerText——非标准 (从起始位置到终止位置的内容,不识别html标签(里面的标签会直接显示)、空格和换行)
<button>123</button>
<div>某个时间</div>
<p>112233</p>
<script>
//获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
//注册事件
btn.onclick = function () {
//添加处理程序
div.innerText = getDate();
}
function getDate() {
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
var day = date.getDay();
return '今天是' + year + '年' + month + '月' + dates + '日 ' + arr[day];
}
//元素可以不用添加事件
var p = document.querySelector('p')
p.innerText = getDate();
  • element.innerHTML——W3C推荐 (从起始位置到终止位置的内容,但它识别html标签,同时保留空格和换行)
var p = document.querySelector('p')
p.innerHTML = '<strong>今天是</strong>' + getDate();

2.4.2 常用元素的属性操作

<button class="ldh">刘德华</button>
<button class="zxy">张学友</button><br>
<img src="imges/京东广告右.jpg" alt="" title="刘德华">
<script>
var ldh = document.querySelector('.ldh');//注意这里不能用getElementsByClassName,他返回的是数组,不能用于添加事件
var zxy = document.querySelector('.zxy');
var img = document.querySelector('img');
zxy.onclick = function () {
img.src = 'imges/京东广告左.jpg';
img.title = '张学友'
}
ldh.onclick = function () {
img.src = 'imges/京东广告右.jpg';
img.title = '刘德华'
</script>

根据时间显示问候语和图片案例:

<img src="imges/s.png" alt="">
<div>上午好</div>
<script>
var img = document.querySelector('img');
var div = document.querySelector('div');
var date = new Date();
var h = date.getHours();
if (h < 12) {
img.src = 'imges/s.png';
div.innerHTML = '上午好';
} else if (h < 18) {
img.src = 'imges/x.png';
div.innerHTML = '下午好';
} else {
img.src = 'imges/w.png';
div.innerHTML = '晚上好';
}
</script>

2.4.3 修改表单属性

  • 利用DOM可以操作如下表单元素的属性:
    type, value, checked, selected, disabled

  • 注:表单里面的值通过修改value值来修改的

input.value = "xxx";
input.type = "xxx";
input.checked = "xxx";
input.selected = true / false;
input.disabled = true / false;//当为true时,禁用
this.disabled=true;//this指向调用者

例:密码的可见与不可见

<div>
<input type="password" value=""><br>
<label for="">
<img src="imges/不可见.jpg" alt="">
</label>
</div>
<button>登录</button>
<script>
var pas = document.querySelector('input');
var img = document.querySelector('img');
var flag = 0;
img.onclick = function () {
if (flag == 0) {
pas.type = 'text';
img.src = 'imges/可见.jpg'
flag = 1;
} else {
pas.type = 'password';
img.src = 'imges/不可见.jpg'
flag = 0;
}
}
</script>

2.4.4 样式属性操作

1)element.style— 行内样式操作

div.style.backgroundColor = 'pink';
div.style.width = '250px';
  • JS里面的样式(中间有'-')采取驼峰命名法,比如 fontSize ,backgroundColor
  • JS 修改 style 样式操作 ,产生的是行内样式,CSS权重比较高

例:隐藏二维码

<div>
<img src="imges/chahao.jpg" alt="" width="20px" class="chahao">
<img src="imges/erweima.webp" alt="" class="erweima">
</div>
<script>
var del = document.querySelector('.chahao');
var div = document.querySelector('div');//注意这里,隐藏的是div,因此div也需要声明
del.onclick = function () {
div.style.display = 'none';//display 使用小写即可
}
</script>

循环精灵图 backgroundPosition 位置为负值

<!-- 循环精灵图 -->
<style>
ul li {
background-image: url(imges/sprite.png);
background-repeat: no-repeat;
}
</style>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
var index = 44 * i;//索引号*两张图纵坐标的间距=精灵图的y坐标
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
</script>

显示隐藏文本框内容

首先需要两个新事件,获得焦点onfocus,失去焦点onblur

<input type="text" value="输入">
<script>
var btn = document.querySelector('input');
//获取焦点事件
btn.onfocus = function () {//光标在输入框内
if (btn.value === '输入') {//文本框内是原字符,才变为空
btn.value = '';
}
btn.style.color = '#333'
}
//失去焦点事件
btn.onblur = function () {
if (btn.value === '') {//文本框里没有内容时,才复原
btn.value = '输入';
}
btn.style.color = '#999'
}
</script>

2) element.className— 类名样式操作

this.className = '新类名';

  • className 会直接更改元素的类名,会覆盖原先的类名

this.className = '旧类名 新类名';原先的类名也保留了

<style>
div {
width: 100px;
height: 100px;
color: beige;
font-size: 16px;
background-color: blueviolet;
}
/* 更改后的样式 */
.change {
width: 120px;
height: 120px;
color: aqua;
font-size: 14px;
background-color: blue;
}
</style>
<div>盒子</div>
<script>
var divs = document.querySelector('div');
divs.onclick = function () {
divs.className = ('change');//使div当前的类名改为change
}
</script>
.dui {
display: inline-block;
color: green;
}
.cuo {
color: red;
}
<div>
<input type="password" value="">
<p class="dui">!密码长度为6~16个字符</p>
</div>
<script>
var pwd = document.querySelector('input');
var text = document.querySelector('p');
pwd.onblur = function () {
if (pwd.value.length < 6) {//判断输入密码长度
text.innerHTML = '× 密码过短 应不小于6个字符'//要注意这里的对象名不是标签名,都写错好几次了!!!
text.className = 'dui cuo'
} else if (pwd.value.length > 16) {
text.innerHTML = '× 密码过长 应不大于16字符'
text.className = 'dui cuo'
} else {
text.innerHTML = '√'
text.className = 'dui'
}
}
</script>

2.4.5 排他思想

  • 所有元素全部清除样式

  • 给当前的元素设置样式

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<button>按钮6</button>
<script>
var btn = document.getElementsByTagName('button');
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
for (var i = 0; i < btn.length; i++) {//先将所有颜色都变为默认
btn[i].style.backgroundColor = '';//这里是在for循环内,用this来指代不了
}
this.style.backgroundColor = 'pink';//this指向btn[i]
}
//这里我最开始用的是失焦事件,也可以实现,但本节重点讲解排他算法
/* btn[i].onblur = function () {
this.style.backgroundColor = '';//颜色变为默认
} */
}
</script>

例:点击更换背景

body {
background: url() no-repeat;
background-size: 100%;
}
<ul class="pifu">
<li><img src="imges/壁纸1.webp" alt="" height="60px"></li>
<li><img src="imges/壁纸2.webp" alt="" height="60px"></li>
<li><img src="imges/壁纸3.webp" alt="" height="60px"></li>
<li><img src="imges/壁纸4.webp" alt="" height="60px"></li>
</ul>
<script>
var btn = document.querySelector('.pifu').querySelectorAll('img');//将类名为pifu的ul里的img全部选取出来
for (var i = 0; i < btn.length; i++) {
btn[i].onclick = function () {
document.body.style.backgroundImage = 'url(' + this.src + ')';
//this.src指鼠标点击的图片的路径
}
}
</script>

2.4.6 表格隔行变色

鼠标事件:

  • 鼠标经过onmouseover
  • 鼠标离开onmouseout
<style>
table {
width: 800px;
margin: 100px auto;
border-collapse: collapse;
/*边框合并*/
font-size: 14px;
text-align: center;
}
thead {
background-color: rgb(137, 183, 255);
}
tr {
height: 30px;
}
tbody td {
border-bottom: 1px solid #d7d7d7;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>代码</th>
<th>名称</th>
<th>最新公布净值</th>
<th>累计净值</th>
<th>前单位净值</th>
<th>净值增长率</th>
</tr>
</thead>
<tbody>
<tr>
<td>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<tr>
<td>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<tr>
<td>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
<tr>
<td>003526</td>
<td>农银金穗3个月定期开放债券</td>
<td>1.075</td>
<td>1.079</td>
<td>1.074</td>
<td>+0.047%</td>
</tr>
</tbody>
</table>
<script>
var tbs = document.querySelector('tbody').querySelectorAll('tr');
for (var i = 0; i < tbs.length; i++) {
tbs[i].onmouseover = function () {
this.style.backgroundColor = 'pink';
}
tbs[i].onmouseout = function () {
this.style.backgroundColor = '';
}
}
</script>

2.4.7 全选和取消

<style>
table {
width: 200px;
margin: 100px auto;
text-align: center;
border-collapse: collapse;
}
tr {
height: 35px;
background-color: rgba(234, 234, 234);
}
th {
background-color: rgb(137, 183, 255);
border: 1px solid rgb(215, 215, 215);
}
td {
border: 1px solid rgb(192, 191, 191);
font-size: 14px;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th><input type="checkbox" id="cbAll"></th>
<th>商品</th>
<th>价格</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="checkbox"></td>
<td>桃子</td>
<td>12元/斤</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>油泼面</td>
<td>10元</td>
</tr>
<tr>
<td><input type="checkbox"></td>
<td>唇膏</td>
<td>9.9元</td>
</tr>
</tbody>
</table>
<script>
var cball = document.querySelector('#cbAll');
var cb = document.querySelector('tbody').querySelectorAll('input');
//经过行变色,前提是tb不设置背景颜色
var trs = document.querySelector('tbody').querySelectorAll('tr');
for (var i = 0; i < trs.length; i++) {
trs[i].onmouseover = function () {
this.style.backgroundColor = 'white';
}
trs[i].onmouseout = function () {
this.style.backgroundColor = '';
}
}
//一键全选,取消
cball.onclick = function () {
for (i = 0; i < cb.length; i++) {
cb[i].checked = this.checked;
//将总复选框的值赋值给下面各个复选框,即下面复选框的状态与总复选框状态一致
}
}
//单个全选,总的自动勾选
for (i = 0; i < cb.length; i++) {
cb[i].onclick = function () {
var flag = true;//控制是否被选中
//每次都要循环检查单个复选框是否全部选中
for (i = 0; i < cb.length; i++) {
if (!cb[i].checked) {
flag = false;//存在单个复选框没有被选中,flag就变为false
break;//提高执行效率
}
}
cball.checked = flag;//结束循环后,判断单个复选框是否全部被选中
}
}
</script>

2.4.8 自定义属性

1)获取自定义的属性值

  • 获取内置属性值(元素本身自带的属性):element.属性;
    (通常是内置属性使用)
    console.log(div.id)

  • 获取自定义的属性:element.getAttribute('属性');
    (主要获得 自己添加的自定义的属性可使用)
    console.log(div.getAttribute('id'));

2)设置属性值

  • 设置内置属性值: element.属性 = '值';
    div.id='text';

  • 主要设置自定义的属性: element.setAttribute('属性',值 / '其他');
    div.setAttribute('index',1);
    div.setAttribute('class','footer');

3)移除属性

element.removeAttribute('属性');

例:tab栏切换

<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 700px;
height: 35px;
background-color: rgb(240, 240, 240);
border-bottom: 2px solid rgb(220, 63, 63);
line-height: 35px;
margin: 100px auto;
margin-bottom: 0;
}
.tab ul li {
list-style: none;
text-align: center;
padding: 0 15px;
float: left;
}
.tab_con {
width: 700px;
margin: 100px auto;
margin-top: 0;
}
.item {
display: none;
}
.current {
background-color: rgb(220, 63, 63);
color: aliceblue;
}
</style>
</head>
<body>
<div class="tab">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价</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">
商品评价模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
<script>
var tab = document.querySelector('.tab').querySelectorAll('li');
var item = document.querySelector('.tab_con').querySelectorAll('.item');
for (var i = 0; i < tab.length; i++) {
//给5个li设置索引号
tab[i].setAttribute('index', i);//注意!注意!这里一定是tab[i]
tab[i].onclick = function () {
//tab样式变换
for (var i = 0; i < tab.length; i++) {
tab[i].className = '';
}
this.className = 'current';
//显示内容
var a = this.getAttribute('index');//得到当前点击的是哪个li
for (var i = 0; i < item.length; i++) {
item[i].style.display = '';
}
item[a].style.display = 'block';
}
}
/* for (var i = 0; i < tab.length; i++) {
tab[i].onclick = function () {
this.className = 'current';
}
//这里的失焦事件就不可以用了,俺也不明白
tab[i].onblur = function () {
this.className = '';
}
} */
</script>

2.4.9 H5自定义属性

设置H5自定义属性:H5规定自定义属性 data- 开头作为属性名并赋值

获取H5自定义属性:

  • 兼容性获取 element.getAttribute(‘data-index’)

  • H5新增的:element.dataset.index 或element.dataset[‘index’] IE11才开始支持
    (dataset是一个集合,里面存放了所有已data开头的属性)

console.log(div.getAttribute('data-list-name'));
console.log(div.dataset.listName);//当自定义属性有多个 _ 链接的单词,采用驼峰命名法
console.log(div.dataset['listName']);

2.5 节点操作

2.5.1 节点概述


节点至少有三个基本属性

  • nodeType
    1 元素节点,nodeType为1
    2 属性节点,nodeType为2
    3 文本节点,nodeType为3(文本节点包含文字、空格、换行等)

  • nodeName

  • nodeValue

2.5.2 父节点

node.parentNode

  • parentNode属性可以返回某节点的父结点,注意是最近的一个父结点

  • 如果指定的节点没有父结点则返回null

<div class="box">
<span class="erweima">×</span>
</div>
<script>
var erweima=document.querySelector('.erweima');
// var box=document.querySelector('.box')
erweima.parentNode;//box 为 erweima 的父节点,因此替代上一句
</script>

2.5.3 子节点

1)parentNode.childNodes (标准)

<ul>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var ul = document.querySelector('ul');
//var lis=ul.querySelectorAll('li');
ul.childNodes;//他的输出值里
</script>
  • 返回值包含了所有的子结点,包括元素节点,文本节点等

  • 如果只想要获得里面的元素节点,则需要专门处理。所以我们一般不提倡使用childNodes

2)parentNode.children (非标准)

  • 它只返回子元素节点,其余节点不返回 (这个是我们重点掌握的)

  • 虽然 children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用

<ul>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var ul = document.querySelector('ul');
//var lis=ul.querySelectorAll('li');
console.log(ul.childNodes);
console.log(ul.children);//会常用

3)获取第一个和最后一个子元素

① 返回所有的节点,包括元素节点,文本节点等
  • parentNode.firstChild 返回第一个子节点,找不到则返回null
    包含所有的节点,包括元素节点,文本节点等

  • parentNode.lastChild 返回最后一个子节点,找不到则返回null
    包含所有的节点,包括元素节点,文本节点等

② 仅返回子元素节点(有兼容性问题,IE9以上才支持)
  • parentNode.firstElementChild 返回第一个子节点,找不到则返回null

  • parentNode.lastElementChild 返回最后一个子节点,找不到则返回null

③实际开发的写法

parentNode.children[0];

parentNode.children[最后一个的索引号];

<ul>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var ul = document.querySelector('ul');
//返回全部元素
console.log(ul.firstChild);
console.log(ul.lastChild);
//仅返子元素
console.log(ul.firstElementChild);
console.log(ul.lastElementChild);
//实际开发
console.log(ul.children[0]);
console.log(ul.children[ul.children.length-1]);//用全部子元素的个数-1

案例:下拉菜单

点击查看代码
<style>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none;
}
.nav {
width: 300px;
margin: 10px auto;
}
.nav .dh {
width: 80px;
height: 50px;
text-align: center;
float: left;
line-height: 50px;
}
.nav .dh:hover {
background-color: rgb(240, 240, 240);
color: orange;
}
.nav ul {
display: none;
}
.dh ul li {
border: 1px solid rgb(253, 220, 128);
padding: 0px 10px;
}
.dh li:hover {
background-color: antiquewhite;
}
</style>
</head>
<body>
<ul class="nav">
<li class="dh"><a href="">微博 ↓</a>
<ul>
<li>私信</li>
<li>评论</li>
<li>@我</li>
</ul>
</li>
<li class="dh"><a href="">博客 ↓</a>
<ul>
<li>私信</li>
<li>评论</li>
<li>@我</li>
</ul>
</li>
<li class="dh"><a href="">邮箱 ↓</a>
<ul>
<li>私信</li>
<li>评论</li>
<li>@我</li>
</ul>
</li>
</ul>
<script>
var nav = document.querySelector('.nav');
var lis = nav.children;
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function () {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function () {
this.children[1].style.display = '';
}
}
</script>

2.5.4 兄弟节点

① 返回所有的节点,包括元素节点,文本节点等

  • node.previousSibling 返回上一个兄弟节点,找不到则返回null
    包含所有的节点,包括元素节点,文本节点等

  • node.nextSibling 返回下一个兄弟节点,找不到则返回null
    包含所有的节点,包括元素节点,文本节点等

② 仅返回兄弟元素节点(有兼容性问题,IE9以上才支持)

  • node.previousElementSibling 返回上一个兄弟节点,找不到则返回null

  • node.nextElementSibling 返回下一个兄弟节点,找不到则返回null

<body>
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling); // #text
console.log(div.previousSibling); // #text
// 2. nextElementSibling 得到下一个兄弟元素节点
console.log(div.nextElementSibling); //<span>我是span</span>
console.log(div.previousElementSibling);//null
</script>
</body>

2.5.5 创建节点

页面添加一个新的元素:

  • 先创建节点
    document.createElement('tagName')
    因为这些元素原先不存在,是根据需求动态产生的,所有也称为动态创建元素节点

  • 再添加节点
    1. node.appendChild(child) node父级,child子级
    将一个节点添加到 指定父节点的 子节点列表 末尾(类似push)

    2. node.insertBefore(child,指定元素)
    将一个节点添加到 父节点的 指定子节点 前面

<ul>
<li>123</li>
</ul>
<script>
//1.创建节点
var li = document.createElement('li');
//2.添加节点
var ul = document.querySelector('ul');
ul.appendChild(li);//插入到123后面
//添加到已有子节点的前面
var lis = document.createElement('li');//创建的的节点
ul.insertBefore(lis, ul.children[0])//插入到123前面

补充:利用element.insertAdjacentHTML('position', text);可以把字符串格式元素添加到父元素中

position : 一个 DOMString,表示插入内容相对于元素的位置,并且必须是以下字符串之一:

  • beforebegin:元素自身的前面。
  • afterbegin:插入元素内部的第一个子节点之前。
  • beforeend:插入元素内部的最后一个子节点之后。
  • afterend:元素自身的后面。

案例:简单的留言发布

点击查看代码
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 200px;
margin: 50px 0 30px 50px
}
textarea {
width: 150px;
height: 100px;
resize: none;
border: 1px solid rgb(255, 107, 132);
cursor: text;
}
ul li {
list-style: none;
background-color: pink;
width: 200px;
margin-left: 50px;
margin-bottom: 10px;
}
</style>
<body>
<div class="liuyan">
<textarea name="" id="">123</textarea>
<button>发布</button>
</div>
<ul>
</ul>
<script>
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
var ul = document.querySelector('ul')
btn.onclick = function () {
if (text.value == '') {
alert('输入内容无效')
} else {
var lis = document.createElement('li');
ul.appendChild(lis);
lis.innerHTML = text.value;
}
}
</script>

2.5.6 删除节点

node.removeChild(child)方法从 DOM 中删除一个子节点,返回 删除的节点

<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.removeChild(ul.children[0]);
</script>

简单的删除发布留言:

点击查看代码
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 200px;
margin: 50px 0 30px 50px
}
textarea {
width: 150px;
height: 100px;
resize: none;
border: 1px solid rgb(255, 107, 132);
cursor: text;
}
ul li {
list-style: none;
background-color: pink;
width: 200px;
margin-left: 50px;
margin-bottom: 10px;
}
li a {
float: right;
text-decoration: none;
}
</style>
<div class="liuyan">
<textarea name="" id="">123</textarea>
<button>发布</button>
</div>
<ul>
</ul>
<script>
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
btn.onclick = function () {
if (text.value == '') {
alert('输入内容无效')
} else {
var lis = document.createElement('li');
ul.appendChild(lis);
lis.innerHTML = text.value + '<a href="javascript:;">删除</a>';//innerHTML可以识别标签
//javascript:;可阻止链接跳转
//删除评论
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
ul.removeChild(this.parentNode);
//需要删除a的父亲li,即this.parentNode,而他的父亲是ul
}
}
}
}
</script>

2.5.7 复制节点

node.cloneNode()

  • node.cloneNode();
    括号为空或者里面是false 浅拷贝 只复制标签 不复制里面的内容

  • node.cloneNode(true);
    括号为true 深拷贝 复制标签 复制里面的内容

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
//先克隆节点
var liclone = ul.children[0].cloneNode();// 浅拷贝
var liclone = ul.children[0].cloneNode(true);// 深拷贝
//再添加节点
ul.appendChild(liclone);
</script>
</body>

动态生成表格:

点击查看代码
<table>
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1.准备数据,大量数据用数组
var datas = [{
name: '张三',
age: 18,
sex: '男'
},
{
name: '李四',
age: 18,
sex: '男'
},
{
name: '王五',
age: 18,
sex: '男'
}];
//2.往tbody里面创建行
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {
var tr = document.createElement('tr');
tbody.appendChild(tr);
//3.在行里面创建单元格,单元格的个数取决于属性的个数,这里采用遍历对象的属性,对第i个对象进行遍历
for (var k in datas[i]) {
var td = document.createElement('td');
tr.appendChild(td);
//取值
td.innerHTML = datas[i][k];//这里的 obj[k] 得到的是属性值
}
//创建'删除'的单元格
var td = document.createElement('td');
tr.appendChild(td);
td.innerHTML = '<a href="javascript:;">删除</a>';
}
//添加删除事件
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
tbody.removeChild(this.parentNode.parentNode);
//删除行tr,而他的父亲是tbody,this.parentNode指td,他的父亲是tr
}
}

2.5.8 三种动态创建元素的区别

  • document.write()

    • 直接将内容写入页面的内容流,但是文档流执行完毕,所以会导致页面全部重绘,也就是说,如果页面文档流加载完毕,再调用这句话会导致页面重绘,原来的就没有了,仅剩下新建的元素
  • element.innerHTML

    特点:

    • innerHTML 是将内容写入某个DOM节点,不会导致页面重绘
    • 创建多个元素效率更高(但是要采用数组拼接效率才高)
  • document.createElement()

    • 特点:大量创建时,效率低一点点,但是结构更清晰
<body>
<div class="innner"></div>
<div class="create"></div>
<script>
// 2. innerHTML 创建元素
var inner = document.querySelector('.inner');
// 2.1 innerHTML 用拼接字符串方法
for (var i = 0; i <= 100; i++) {
inner.innerHTML = '<a href="#">百度</a>';
}
// 2.2 innerHTML 用数组形式拼接
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3. document.createElement() 创建元素
var create = document.querySelector('.create');
var a = document.createElement('a');
create.appendChild(a);
</script>
</body>

2.6 DOM重点核心

对于DOM操作,我们主要针对子元素的操作,主要有

  • 创建:document.write、innerHTML、createElement

  • 增:appendChild、insertBefore

  • 删:removeChild

  • 改:主要修改dom的元素属性,dom元素的内容、属性、表单的值等

    • 修改元素属性:src、href、title 等
    • 修改普通元素内容:innerHTML、innerText
    • 修改表单元素:value、type、disabled
    • 修改元素样式:style、className
  • 查:主要获取查询dom的元素

    • DOM提供的API方法:getElementById、getElementsByTagName (古老用法,不推荐)
    • H5提供的新方法:querySelector、querySelectorAll (提倡)
    • 利用节点操作获取元素:父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling) 提倡
  • 属性操作:主要针对于自定义属性

    • setAttribute:设置dom的属性值
    • getAttribute:得到dom的属性值
    • removeAttribute:移除属性

3. 事件高级

3.1 注册事件

注册事件有两种方式:传统方式和方法监听注册方式

3.1.1 传统方式

  • 利用 on 开头的事件

  • btn.onclick = function(){}

  • 特点:注册事件的唯一性

  • 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数

3.1.2 方法监听注册方式

  • w3c推荐方式

  • addEventListener() 它是一个方法

  • IE9之前的IE不支持此方法,可使用 attachEvent() 代替

  • 同一个元素同一个事件可以注册多个监听器

  • 按注册顺序依次执行

eventTarget.addEventListener()

方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数

eventTarget.addEventListener(type,listener[,useCapture])

该方法接收三个参数:

1.type:事件类型字符串,比如click,mouseover,注意这里不要带on
2.listener:事件处理函数,事件发生时,会调用该监听函数
3.useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习
<body>
<button>传统注册事件</button>
<button>方法监听注册事件</button>
<button>ie9 attachEvent</button>
<script>
var btns = document.querySelectorAll('button');
// 1. 传统方式注册事件
btns[0].onclick = function () {
alert('hi');
}
btns[0].onclick = function () {
alert('hao a u');
}
// 2. 事件监听注册事件 addEventListener
// (1) 里面的事件类型是字符串 所以加引号 而且不带on
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function () {
alert(22);
})
btns[1].addEventListener('click', function () {
alert(33);
})
// 3. attachEvent ie9以前的版本支持
btns[2].attachEvent('onclick', function () {
alert(11);
})
</script>
</body>

3.2 解绑事件

3.2.1 传统事件删除方式

eventTarget.onclick = null;

3.2.2 removeEventListener删除事件方式

eventTarget.removeEventListener(type,listener[,useCapture]);

该方法接收三个参数:

1. type:事件类型字符串,比如click,mouseover,注意这里不要带on
2. listener:事件处理函数,事件发生时,会调用该监听函数
3. useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习

3.2.3 detachEvent删除事件方式(兼容)

eventTarget.detachEvent(eventNameWithOn,callback);
该方法接收两个参数:

1. eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
2. callback: 事件处理函数,当目标触发事件时回调函数被调用
  • ie9以前的版本支持
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function () {
alert(11);
// 1. 传统方式删除事件
divs[0].onclick = null;
}
// 2.removeEventListener 删除事件
divs[1].addEventListener('click', fn); //里面的fn不需要调用加小括号
function fn() {//要删除de事件不能用匿名函数
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3.IE9 中的删除事件方式
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
</body>

3.3 DOM事件流

事件流描述的是从页面中接收事件的顺序

比如我们给一个div注册了点击事件:

DOM事件流分为3个阶段:1.捕获阶段 2.当前目标阶段 3.冒泡阶段

事件冒泡: IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
事件捕获: 网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。

// dom 事件流 三个阶段
// 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
// 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
// 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
var son = document.querySelector('.son');
son.addEventListener('click', function () {
alert('son');
}, true)
var father = document.querySelector('.father');
father.addEventListener('click', function () {
alert('father');
}, true)//点击子盒子先弹出father,再弹出son
//4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
var son2 = document.querySelector('.son2');
son2.addEventListener('click', function () {
alert('son2');
}, false)
var father2 = document.querySelector('.father2');
father2.addEventListener('click', function () {
alert('father2');//点击子盒子先弹出松2,再弹出father2
}, false)

3.4 事件对象

var div=document.querySelector('div');
div.onclick=function(event){}
div.addEventListener('click',function(event){})

event就是一个事件对象,写到监听函数的小括号中 当形参来看

  • event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看

  • 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数

  • 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的
    比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,
    如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键

  • 这个事件对象我们可以自己命名 比如 event 、 evt、 e

  • 事件对象也有兼容性问题 ie678 通过 window.event, 兼容性的写法: e = e || window.event;

3.4.1 常见的属性和方法

事件对象属性方法 说明
e.target 返回触发事件的对象 标准
e.type 返回事件的类型 比如click mouseover 不带on
e.srcElement 返回触发事件的对象 非标准 ie6-8使用
e.preventDefault() 方法 阻止默认行为 标准 比如不让链接跳转
e.returnValue 属性 阻止默认行为 非标准,ie6-8使用
e.stopPropagation() 方法阻止冒泡 标准
e.cancelBubble 属性阻止冒泡,非标准,ie6-8使用

1) e.target和this的区别

  • e.target 是事件触发的元素。(例如点击事件,鼠标点击的哪个元素,返回的就是哪个元素)

  • this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素)

    和this有个非常相似的属性 currentTarget,返回的也是事件的绑定元素,有兼容性问题,不常用

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
console.log(e.target);//返回的是li
console.log(this);//返回的是ul
})
</script>

2)返回事件类型 (e.type)

var div = document.querySelector('div');
div.addEventListener('click', fn);
function fn(e) {
console.log(e.type);//返回结果为 click

3)阻止默认行为 (e.preventDefault())

让链接不跳转,或者 让提交按钮不提交

var a = document.querySelector('a');
a.addEventListener('click', function (e) {
e.preventDefault();
})

return flase也能阻止默认行为,且无兼容性问题,但后面的代码无法实现,且只限用于传统注册方式

4)阻止冒泡(e.stopPropagation())

var son2 = document.querySelector('.son2');
son2.addEventListener('click', function (e) {
alert('son2');
e.stopPropagation();
}, false)
var father2 = document.querySelector('.father2');
father2.addEventListener('click', function () {
alert('father2');
}, false)
//只弹出son2,不再弹出father2

ie 6-8写法:
window.e.cancelBubble = true;

3.4.2 事件委托

原理:

不是每个子节点单独设置监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

案例:给ul注册点击事件,然后点击里面的li的时候,当前的li可以用event.target得到,并且点击li,事件会冒泡到ul上

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
for (var i = 0; i < ul.children.length; i++) {
ul.children[i].style.backgroundColor = '';
}
e.target.style.backgroundColor = 'pink';
})
//点击li,通过事件冒泡 传给ul,触发ul点击事件,再通过e.targr来得到点击的对象
</script>

3.5 常用的鼠标事件 2

3.5.1 禁止选中文字 和 禁止右键菜单

1)selectstart

  • 主要控制鼠标选中

  • 可以通过阻止默认行为来取消默认的上下文菜单

hello world!
<script>
document.addEventListener('selectstart', function (e) {
e.preventDefault();
})

2)contextmenu

  • 主要控制应该何时显示上下文菜单

  • 可以通过阻止默认行为来取消默认的上下文菜单

hello world!
<script>
document.addEventListener('contextmenu', function (e) {
e.preventDefault();//阻止默认行为
})

3.5.2 鼠标事件对象

  • event对象代表事件的状态,跟事件相关的一系列信息的集合

  • 现阶段我们主要是用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent。

鼠标事件对象 说明
e.clientX 返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY 返回鼠标相对于浏览器窗口可视区的Y坐标
e.pageX(重点) 返回鼠标相对于文档页面的X坐标(屏幕滚动后点击的坐标不同) IE9+ 支持
e.pageY(重点) 返回鼠标相对于文档页面的Y坐标(屏幕滚动后点击的坐标不同) IE9+ 支持
e.screenX 返回鼠标相对于电脑屏幕的X坐标
e.screenY 返回鼠标相对于电脑屏幕的Y坐标
<script>
document.addEventListener('click', function (e) {
//相对浏览器的坐标
console.log(e.clientX);
console.log(e.clientY);
//相对页面文档的坐标
console.log(e.pageX);
console.log(e.pageY);
//相对电脑屏幕的坐标
console.log(e.screenX);
console.log(e.screenY);
})
</script>

案例:跟随鼠标

img {
position: absolute;
top: 0;
right: 0;
}
<body>
<img src="imges/魔女.png" alt="" width="100" height="">
<script>
var img = document.querySelector('img');
//mousemove只要鼠标移动1px就会触发事件
document.addEventListener('mousemove', function (e) {
img.style.left = e.clientX + 'px';
img.style.top = e.clientY + 'px';
//想要鼠标到图的中间位置
img.style.left = e.clientX - 50 + 'px';
img.style.top = e.clientY - 40 + 'px';
})

3.6 常见的键盘事件

键盘事件 触发条件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发
onkeypress 某个键盘按键被按下时触发,但是它不识别功能键,比如 ctrl shift 箭头等
  • 如果使用addEventListener 不需要加 on

  • onkeypress 和前面2个的区别是,它不识别功能键,比如左右箭头,shift 等

  • 三个事件的执行顺序是: keydown – keypress — keyup

<script>
//按任意按键,松开键盘触发
document.addEventListener('keyup', function () {
console.log('world');
})
//按任意按键,按下键盘触发
document.addEventListener('keydown', function () {
console.log('hello');//按住不松会一直触发
})
////按下键盘触发,但不识别功能键
document.addEventListener('keypress', function () {
console.log('hello');//按住不松会一直触发
})
</script>

3.6.1键盘事件对象

属性 说明
keyCode 返回该键值的ASCII值
  • onkeydown和 onkeyup 不区分字母大小写(按大小写得到的ASCII码值相同),onkeypress 区分字母大小写。
//键盘事件对象
document.addEventListener('keypress', function (e) {
console.log(e.keyCode);
})

案例:按下s键后光标在搜索框内显示

var search = document.querySelector('input');
//此处用keyup是因为按键松开后才会触发事件,因此s不会被输入
document.addEventListener('keyup', function (e) {
if (e.keyCode == 83) {
search.focus();//focus()方法:获得焦点
}
})

案例:放大单号

点击查看代码
<style>
div {
width: 168px;
border: 1px solid rgba(0, 0, 0, .4);
position: relative;
box-shadow: 0px 2px 10px rgba(0, 0, 0, .4);
margin-bottom: 10px;
font-size: 19px;
display: none;
}
div::before {
content: '';
border-top: 10px solid white;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 10px solid transparent;
width: 0;
height: 0;
position: absolute;
top: 24px;
left: 84px;
margin-left: -5px;
border-style: solid dashed dashed;
border-color: #fff transparent transparent;
}
input {
position: absolute;
top: 50px;
}
</style>
<body>
<div></div>
<input type="text">
<script>
//输入单号,显示放大
//检测是否输入,添加键盘事件
//将表单的值赋给div
//失去焦点,div隐藏,获得焦点,div显示
var big = document.querySelector('div');
var input = document.querySelector('input');
input.addEventListener('keyup', function () {
if (input.value !== '') {
big.style.display = 'block';
big.innerHTML = this.value;
} else {
big.style.display = '';
big.innerHTML = this.value;
}
input.addEventListener('blur', function () {
big.style.display = '';
big.innerHTML = this.value;
})
input.addEventListener('focus', function () {
if (input.value !== '') {
big.style.display = 'block';
big.innerHTML = this.value;
}
})
})
</script>
</body>
  • keydown和keypress在文本框里面的特点:他们两个触发的时候,文字还没有落入文本框中
posted @   准备开始  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示