JS-WebAPIs第1天-DOM
参考:
pink老师JS基础 JavaScript基础语法-dom/bom-es6-jQuery-数据可视化echarts-包含笔记源码作业黑马程序员pink老师前端入门视频教程(持续更新)
MDN-Web API接口参考 文档对象模型
文章目录
Web APIs 和JS基础的关联性
一. 什么是DOM(Document Object Model)
详细参考{MDN-Web API接口参考 文档对象模型}, 这里先只学几个常用方法并给出示例.
The Document Object Model (DOM) connects web pages to scripts or programming languages by representing the structure of a document. The DOM represents a document with a logical tree. Each branch of the tree ends in a node, and each node contains objects.
DOM是W3C组织推荐的处理可扩展标记语言(HTML/XML)的标准编程接口. DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。DOM的方法(methods)让你可以用特定方式操作这个树,用这些方法你可以改变文档的结构、样式或者内容。节点可以关联上事件处理器,一旦某一事件被触发了,那些事件处理器就会被执行.
要做一个动态页面, 就是触发响应, 称之为事件. 事件是有三部分组成 事件源 事件类型 事件处理程序 我们也称为事件三要素.首先获取DOM元素也就是事件源, 接着设计触发的事件类型(点击\按下…), 最后通过函数设计响应(事件处理程序).
Document
接口描述了任何类型的文档的通用属性与方法。根据不同的文档类型(例如HTML、XML、SVG,…),还能使用更多 API:使用 "text/html"
作为内容类型(content type)的 HTML 文档,还实现了 HTMLDocument
接口,而 XML 和 SVG 文档则(额外)实现了 XMLDocument
接口。
二. 事件-获取页面元素当事件源
根据ID获取(适用于独一的元素) | document.getElementById() |
---|---|
根据标签名获取 | document.getElementsByTagName() |
通过HTML5新增方法获取 | document.getElementsByClassName(‘类名’); document.querySelector(’.类名/#ID名’) |
特殊元素获取(html/body…) | document.body; document.documentElement; |
2.1 document.getElementById()根据ID获取
MDN详细信息: https://developer.mozilla.org/zh-CN/docs/Web/API/Document/getElementById
ID是独一无二的, 因此可以直接通过ID获取元素
// 1. 因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面,即body的后面
// 2. get 获得 element 元素 by 通过 驼峰命名法
// 3. 参数 id是大小写敏感的字符串
// 4. 返回的是一个元素对象
var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer);
// 5. console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法
console.dir(timer);
2.2 document/element.getElementsByTagName()根据标签名获取
document. getElementsByTagName()可以获取HTML中所有这个标签的元素, 如果需要某个特点父元素下的此类子元素, 可以用element(这里是父元素). getElementsByTagName(标签名‘)
// 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. 如果页面中只有一个li 返回的还是伪数组的形式
// 4. 如果页面中没有这个元素 返回的是空的伪数组的形式
// 5. element.getElementsByTagName('标签名'); 父元素必须是指定的单个元素
// var ol = document.getElementsByTagName('ol'); // [ol]
// console.log(ol[0].getElementsByTagName('li'));
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
2.3 H5新增方式-CSS选择器(不兼容IE678…)
-
document.getElementsByClassName(‘类名’) 根据类名获得某些元素集合,包括所有同名元素,返回一个伪数组
-
document.querySelector() 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box #nav(.表示class名, #表示id名)
-
document.querySelectorAll() 返回所有
<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
// 1. getElementsByClassName 根据类名获得某些元素集合
var boxs = document.getElementsByClassName('box');
console.log(boxs); //返回伪数组包含’盒子1’’盒子2’两个元素
// 2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box #nav
var firstBox = document.querySelector('.box');
console.log(firstBox); //盒子1
var nav = document.querySelector('#nav');
console.log(nav); //返回< div id="nav">此行
var li = document.querySelector('li');
console.log(li); //首页
// 3. querySelectorAll()返回指定选择器的所有元素对象集合
var allBox = document.querySelectorAll('.box');
console.log(allBox);
var lis = document.querySelectorAll('li');
console.log(lis);
</script>
</body>
2.4 特殊元素
// 1.获取body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
// 2.获取html 元素
// var htmlEle = document.html; // 此时为undefined
var htmlEle = document.documentElement;
console.log(htmlEle);
三. 事件-触发响应
执行事件的步骤: 1,获取事件源 2,注册事件(绑定事件) 3,添加事件处理程序(函数赋值形式)
常见的鼠标事件:
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发(CSS里没有) |
onmouseover | 鼠标经过触发(CSS里hover可实现) |
onmouseout | 鼠标离开触发 |
onfocus | 获得鼠标焦点(适用于表单输入) |
onblur | 失去鼠标焦点 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
四. 操作元素
4.1 改变元素内容
格式:
element.innerText;
element.innerHTML;
使用举例:
//获取事件源
var div = document.querySelector('div');
div.innerText = '<strong>今天是:</strong> 2019';
//返回: <strong>今天是:</strong> 2019
div.innerHTML = '<strong>今天是:</strong> 2019';
//返回: 今天是:(加粗字体) 2019
// 这两个属性是可读写的 可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
innerText 和 innerHTML的区别 :
// 1. innerText 不识别html标签 非标准 会去除空格和换行
// 2. innerHTML 识别html标签 W3C标准 保留空格和换行的
//总结: innerText非标准, 推荐使用标准innerHTML
4.2 常用元素的属性操作
element.src //改变路径
href //返回当前样式表文件(css文件)的路径地址
id, alt, title...
使用案例:
<head>
<link rel="StyleSheet" href="//C:/Windows/Desktop/example.css" type="text/css" />
<script>
function sref() {
alert(document.styleSheets[0].href);
}
</script>
</head>
<body>
<button onclick="sref()">显示路径</button>
</body>
</html>
<!-- 弹出 "file:C:/Windows/Desktop/example.css -->
见练习2-根据不同时间显示不同提示语和图片
4.3 表单元素的属性操作
利用DOM可以操作如下表单元素的属性:
属性 | 举个栗子 |
---|---|
type | input密码框变文本框,显示密码 |
value | 搜索框的默认文字 |
checked | |
selected | |
disabled |
表单里的文字不能通过innerHTML修改,而是有专门的属性
见练习3-点击显示密码
4.4 样式属性操作
1. element.style //行内样式操作,等效于把样式在CSS行内更改,优先级高
2. element.className //类名样式操作, 同时更改多个样式时使用,避免在JS里写过多CSS样式代码
练习4-关闭二维码(网页上的小块广告, 点击关闭)
练习5-循环精灵图
练习6-搜索框输入时隐藏默认字符
五. 节点操作
文档叫做文档节点, 元素叫元素节点, 标签成为标签节点, 属性也是节点, 甚至注释也是节点. 一般主要操作元素节点.
一般地,节点至少拥有nodeType(节点类型), nodeName(节点名称)和nodeValue(节点值)这三个基本属性.
- 元素节点 nodeType 为1
- 属性节点 nodeType 为2
- 文本节点 nodeType 为3 (包括文字,空格,换行)
5.1 父节点
利用亲父子关系: node.parentNode, 如果找不到父节点返回空.
5.2 子节点
parentNode.childNodes
获得此父节点的所有孩子, 其中文字算文本节点, 也会被存进该伪数组.
如果只想获得里面的元素节点,需要再遍历去除其他类型节点, 更麻烦. 所有一般不使用childNodes
parentNode.children
实际开发常用,获取所有子元素节点.
parentNode.firstChild && parentNode.lastChild
获得第一个/最后一个节点, 包括文本
parentNode.firstElementChild && parentNode.lastElementChild
返回第一个/最后一个子元素节点,找不到则返回null
注意: 只兼容IE9+
实际开发写法, 解决兼容问题:
parentNode.children[0] 返回第一个子元素
parentNode.children[parentNode.children.length-1] 返回最后一个子元素
5.3 兄弟节点
element.nextSibling && previousSibling
下个兄弟节点和上个兄弟节点, 包含文本,换行等
node.nextElementSibling && previousElementSibling
IE9+才支持 返回下一个兄弟元素节点,找不到返回null
封装一个兼容性函数
function getNextElementSibling(element) {
var el = element;
while(el = el.nextSibling) {
if (el.nodeType === 1){
return el;
}
}
return null;
}
5.4 创造节点-增加节点
1. appendChild
2. insertBefore
使用案例: 用户发表评论时显示出来,实际是创造了一个节点
创造节点有两步: 1. 创建新元素 2. 把新元素添加进去
//创造节点方法:
var newNode = document.createElement('tagTypeName');
//添加节点方法:
1. 添加到指定父节点的子节点列表末尾, 类似css里的after伪元素
parentNode.appendChild(newNode);
2. 添加到置顶父节点的子节点列表的指定元素前面
parentNode.insertBefore(newNode, parentNode.children[0]);
举个栗子:
<ul><ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
//先获取已有元素,为要添加的位置
var ul = document.querySelector('ul');
//
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
5.5 删除节点
node.removeChild(child)
从DOM中删除父节点node的一个子节点, 返回删除的节点.
举个栗子:
<body>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
<button>删除</button>
<script>
// 1. 获取父元素
var ul = document.querySelector('ul');
// 2. 删除子元素 ul.removeChild(ul.children[0]);
//3. 点击删除
var btn = document.querySelector('button');
btn.onclick = function() {
if (ul.children.length === 0) {
alert('恭喜你,删光啦');
this.disabled = true;
} else {
ul.removeChild(ul.children[0]);
}
}
</script>
</body>
5.6 复制节点
练习见: [动态生成数组]
node.cloneNode()
返回调用该方法的节点的一个副本, 也称克隆节点/拷贝节点;
注意: 1.如果括号参数为空或者false, 代表浅拷贝, 即只克隆标签类型,不复制里面的内容; 2. 括号内true, 则全部复制
克隆完如果需要使用,别忘了添加此克隆节点
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);//把ul的第一个孩子深复制
ul.appendChild(lili);
六, 创建节点的三种方式
6.1 document.write()
页面加载完再重新写入, 页面除了写入的新节点其他会被清空
<body>
<button>点击</button>
<p>abc</p>
<div class="inner"></div>
<div class="create"></div>
<script>
// 三种创建元素方式区别
// 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('<div>123</div>');
}
</script>
</body>
上面所示JS等效于如下:
window.onload = function() {
document.write('<div>123</div>');
}
很不常用, 了解即可
6.2 element.innerHTML
相当于给父节点里面放一个子节点, innerHTML后面不必是text类型, 可以带标签.
innerHTML添加也有两种方式.
第一种, 直接拼接字符串. 缺点: 每次拼接都会新建一个加长的字符串, 多次拼接会大量占用内存
var inner = document.querySelector('.inner');
// 拼接字符串方式用innerHTML创建
inner.innerHTML = '<a href="#">百度</a>'
// 拼接100个
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href="#">百度</a>'
}
第二种(优), 用数组形式实现拼接多个字符串, 先把字符串放进数组, 再一次性 arr.join(’’) 把数组转字符串拼进去
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
6.3 document.creatElement()
// 3. document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
6.4 三者区别
比如面试问题如下:
问: innerHTML和creatElement谁效率高?
答: 如果不拼接字符串, 而是采用数组形式, 那么innerHTML效率会更高
问: 为什么innerHTML效率更高. creatElement每次都创建一个节点,再append进父节点, 下次创建节点时虽然上次的节点所占内存空间被释放,依然会新建一个节点, 所以效率慢一些, 但结构清晰