▊ Web APIs与JS基础的关联
JS的三个组成部分中,经常提到的JS基础是指ECMAScript,Web APIs阶段是DOM和BOM
API(Application Programming Interface,应用程序编程接口)我们并不陌生,那么什么是Web API呢?
其实用法思想差不多,Web API用来操作浏览器功能和页面元素的接口
▊ DOM
▍DOM树
文档 document :整个页面
元素 element :页面中所有的标签的都是元素
节点 node :页面中所有的内容都是节点,包括标签、属性、文本、注释等
☀ DOM把以上内容都看作是对象
▍获取页面元素
注意看注释!
// console.dir() 可以打印元素对象,方便查看里面的属性和方法
// 根据id:
var timer = document.getElementById('time');
// 注1:返回是一个元素对象
// 注2:括号里是字符串,必须加引号
// 根据标签名:
var list = document.getElementsByTagName('li');
// 注1:获取了页面(document)的所有li
// 注2:返回的是元素对象的集合(伪数组的形式)
// 注3:获得的对象是动态的
var navList = document.getElementById('me').getElementsByTagName('li');
// 注1:获取了id为'me'的ul的li
// 根据类名:
var boxs = document.getElementsByClassName('box');
// 注1:返回的是集合(即使只找到了一个元素,也是个伪数组)
// HTML5新增的两种方法(推荐):
var box = document.querySelector('.box');
var box = document.querySelector('#time');
var box = document.querySelector('li');
// 注1:只返回指定选择的第一个对象
// 注2:选择器要加'#'或'.'或不加,告诉它这是个什么选择器
var boxs = document.querySelectorAll('.box');
// 注1:顾名思义,返回集合
// 获取head元素
var headElement = document.head;
// 获取body元素
var bodyElement = document.body;
// 获取html元素
var htmlElement = document.documentElement;
▍事件基础
简单来说,就是触发-响应机制
// 事件三要素: 事件源,事件类型,事件处理程序
// 与点击按钮为例
//(1) 事件源 —— 事件被触发的对象
var btn = document.getElementById('btn');
//(2) 事件类型 —— 如何触发?
//(3) 事件处理程序 —— 通过一个函数赋值完成
btn.onclick = function(){alert('赛高 ! ! !');}
▍操作元素
1.改变元素的内容
innerText
和innerHTML
(推荐后者)
var box = document.querySelector('div');
box.innerText = '一只萝莉'; // 不能识别html标签
box.innerHTML = '<strong>一只萝莉</strong>'; // 可以识别html标签
// 会覆盖之前的内容 !
// 它们是可读可写的
console.log(box.innerText); // 不识别html标签,和换行和空格一起被自动去掉了
console.log(box.innerHTML); // 可识别html标签,标签、换行和空格都被保留
2.改变元素的属性(src、href、title、alt…)
直接按 对象.属性
思路写
// demo:
var myImg = document.querySelector('img');
myImg.src = 'loli.jpg';
3.操作表单元素的属性
需要注意的是,innerHTML
用来修改普通盒子的文本内容,而表单的文本内容是写在属性value
中的
表单特有的属性除了value
,还有type
, checked
, selected
, disabled
…
// demo:点击一次按钮后该按钮就被禁用
myBtn.onclick = function() {
this.disabled = true; // true写成'disabled'也行
// 注意:this指向的是对象myBtn,也就是该事件的调用者
}
<!-- demo:密码的输入(小眼睛) -->
<!-- 核心思路是密码框和文本框的转换:即input的type属性——password和text -->
<div class="box">
<input type="password" id="pwd">
<img src="eyeclose.png" id="eye">
</div>
<script>
var myInput = document.getElementById('pwd'); // 获取输入框对象
var myBtn = document.getElementById('eye'); // 获取img对象当做按钮
var flag = 0; // 通过一个flag标记进行交替
myBtn.onclick = function() {
if (flag == 0) {
myInput.type = 'text';
myBtn.src = 'eyecopen.png';
flag = 1;
} else {
myInput.type = 'password';
myBtn.src = 'eyeclose.png';
flag = 0;
}
}
</script>
4.修改元素的样式属性(大小,颜色,位置等)
① element.style
行内样式操作
② element.className
类名样式操作
// 方式1: 行内样式操作
var box = document.querySelector('div');
box.onclick = function() {
this.style.width = '250px';
this.style.backgroundColor = 'Pink';
}
// 注1:属性值加引号——因为本质是修改行内样式,也因此CSS权重较高
// 注2:属性的驼峰命名写法
<!-- demo:关闭小广告 -->
<!-- 核心思路是:同一个按钮控制整个父盒子的display(block or none?) -->
<div class="box">
<img src="loli1.jpg" alt="">
<div class="close">×</div>
</div>
<script>
var closeBtn = document.querySelector('.close');
var box = document.querySelector('.box');
closeBtn.onclick = function() {
box.style.display = 'none';
}
</script>
// 精灵图
// 核心思路是:精灵图上的图标位置都是[成行或成排的],因此根据其位置规律就可以计算出其[背景位置]
var list = document.querySelectorAll('li'); // 返回的是一个伪数组,伪数组的元素才是对象
for(var i = 0; i < list.length; i++) {
list[i].style.backgroundPosition = '0 -' + i*44 + 'px'; // 就是 '0 0px' '0 44px' '0 88px'...
}
// 方式二:类名样式操作
// 上面的demo中,都是改变某个元素的仅几个样式,而当需要改变的样式太多时,岂不是要写很多个this.属性? [类名样式操作]给我们提供了另一种思路:
// 把改变后的样式都写在css里,作为一个类;触发事件后就把这个类加上
box.onclick = function() {
this.className = 'change'; // .change使我们提前写在css的一个类
}
// 缺点也很致命:会覆盖原先的类名
// 解决方案很简单但一定要能想到: this.className = 'old new'; ———都写上就okk了
5.补充:排他思想
这是一种特别常用的思想,比如我们通常需要多个按钮中同时只能一个被按下,那么就需要用到排他思想:
按下这个按钮作为事件,将所有的按钮先复原,再设置此按钮的按下效果
6. 获取属性值的两种方法
element.属性
:通常用来也只能获取内置属性(元素自带的属性值)
element.getAttribute('属性')
: 主要用来获取自定义属性
7. 设置属性值的两种方法
element.属性 = '值'
:通常用来也只能设置内置属性(元素自带的属性值)
element.setAttribute('属性', '值')
: 主要用来修改自定义属性
注:div.className = 'nav'
等价于div.setAttribute('class', 'nav')
8. 移除属性
element.removeAttribute('属性')
9. H5自定义属性
一个约定:自定义属性以data-
作为前缀
获取属性的新写法:element.dataset.属性
或 element.dataset['属性']
(dataset实际上是一个集合)
注:像data-part-name这种有多个短连接符的自定义属性,采用驼峰命名法:dataset.partName
或dataset['partName']
▍节点操作
为什么有的情况下使用节点操作?
DOM获取元素有时较为繁琐且逻辑结构性不强,这时就可以利用节点的层级关系(父子,兄弟)来获取元素
节点概述:
- 至少拥有nodeType, nodeName, nodeValue三个基本属性
- 关于节点类型nodeType:元素节点为1, 属性节点为2, 文本节点为3(包含文字、空格、换行)
- 我们在实际开发中,节点操作是指操作元素节点
获取节点:
<div class="bigBox">
<div class="midBox">
<div class="littleBox"></div>
<div class="littleBox"></div>
<div class="littleBox"></div>
</div>
</div>
<script>
var box = document.querySelector('.midBox');
box.parentNode // 获取父节点(最近的父亲)
box.childNodes // 获取子节点(实际上返回了一个含有7个对象的伪数组 —— 返回了所有的子节点(包括回车这个文本节点))
box.children // 获取子节点(这是常用的:返回所有的子元素节点;不包括文本节点)
box.firstChild // 第一个子节点(>_<可是是回车(文本节点))
box.lastChild // 最后一个子节点(>_<可是是回车(文本节点))
box.firstElementChild // 第一个孩子元素节点
box.lastElementChild // 最后一个孩子元素节点
box.children[0] // 更好用!
box.children[box.children.length - 1] //更好用!
box.nextSibling // 下一个兄弟节点
box.previousSibling // 上一个兄弟节点
box.nextElementSibling // 下一个兄弟元素节点
box.previousElementSibling // 上一个兄弟元素节点
</script>
节点的增、删
<ul>
<li>loli1</li>
<li>loli2</li>
</ul>
<script>
var son = document.createElement('li'); // 创建元素节点
var father = document.querySelector('ul');
father.appendChild(son); // 追加元素节点
father.insertBefore(son, father.children[0]); // 插入元素节点(在第二个参数的前面)
father.removeChild(father.children[0]); // 删除(第一个)节点 (这个删除的写法其实很奇怪,小心一下)
</script>
节点的克隆
<script>
var father = document.querySelector('ul');
var loli = father.children[0].cloneNode(); // 默认false,浅拷贝,只复制节点本身 不复制其子节点
var loli = father.children[0].cloneNode(true); // true,深拷贝, 复制节点本身和里面所有的子节点
// 另外,文本节点也是子节点,也就是说,浅拷贝连内容也无法复制
</script>
Qus:element.innerHTML
和document.createElement
在动态创建元素时,效率的比较?
Ans:innerHTML在创建较多元素时效率更高(采取数组形式拼接,不要直接字符串拼接!),结构性不强
createElement在创建较多元素时效率低一些(不是很多),但是结构清晰
☀ Loli & JS
♫ Suki