JavaScript = ECMAScript + DOM + BOM
1. DOM
1. 获取元素
document.getElementById('nav'); // 通过ID获取
document.getElementsByTagName('li'); // 通过标签名获取,返回元素伪数组
document.getElementsByName('account'); // 通过name获取,返回元素伪数组
document.getElementsByClassName('nav'); // 以类名获取,范围元素伪数组
document.querySelector('#nav .top'); // 以css选择器选择,返回第一个匹配的元素
document.querySelectorAll('#nav li'); // 以css选择器选择,返回元素伪数组
2. 事件
2.1 事件绑定与解绑
- 传统注册方式
唯一性:同一个事件源的同一个事件只能注册一个处理函数
<button onclick="alert('hi~')">
button
</button>
btn.onclick = function(){} // 点击事件
input.onblur = function(){} // 失去焦点
input.onfocus = function(){} // 得到焦点
element.onmouseover = function(){} // 鼠标经过
element.onmouseout = function(){} // 鼠标离开
- 事件监听注册方式
可以给同一个元素同一个事件添加多个监听器。监听器处理函数依次执行。
// IE9以上支持
btn.addEventListener('click', function(){ // 不带on
alert('hi~');
});
btn.addEventListener('click', function(){ // 不带on
alert('你好~');
});
- 解绑事件
btn.addEventListener('click', fn);
function fn(){
alert('hi~');
btn.removeEventListener('click', fn);
}
2.2 DOM事件流
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
DOM事件流分为三个阶段:
-
捕获阶段
-
当前目标阶段
-
冒泡阶段
btn.addEventListener('click', function(){
alert('hi~');
}, true);
// 第三个参数为true,则说明在捕获阶段执行;若为false,则在冒泡阶段执行。默认是false
onblur、onfocus、onmouseenter、onmouseout没有冒泡
2.3 事件对象
// IE 9
btn.addEventListener('click', function(e){
console.log(e); // 事件对象中有关于该事件的各种信息(比如鼠标点击的位置)
});
// IE 6、7、8
btn.addEventListener('click', function(e){
e = e || window.event; // 兼容性处理
console.log(e);
});
事件对象的属性或方法 | 作用 |
---|---|
e.target/this | 返回触发事件的元素(IE9)/绑定事件的对象 |
e.type | 返回事件的类型 |
e.preventDefault() | 阻止默认行为(如连接跳转) IE 9 |
e.stopPropagation() | 阻止继续向上冒泡 IE9 |
e.cancelBubble = true | 阻止继续向上冒泡 兼容好,非标准 |
2.4 事件委托(冒泡的重要应用)
不是每个子节点单独设置事件监听器,而是将事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
只操作了依次DOM,提高了程序性能。
<ul>
<li>子节点1</li>
<li>子节点2</li>
</ul>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
e.target.style.backgroundColor = 'pink';
});
2.5 常用鼠标事件
document.addEventListener('contextmenu', function(e){
e.preventDefault()
}); // 禁止右键菜单
document.addEventListener('selectstart', function(e){
e.preventDefault()
}); // 禁止选中内容
2.6 常用键盘事件
document.addEventListener('keyup', function() {
console.log('按键弹起');
}); // 按键弹起时触发
document.addEventListener('keydown', function() {
console.log('按键按下');
}); // 按键按下时触发,不区分字母大小写
document.addEventListener('keypress', function() {
console.log('按键按下');
}); // 按键按下时触发,但不识别功能键,只能识别字符键,区分字母大小写
三个事件的执行顺序 keydown -> keypress -> keyup
3. 操作元素
3.1 操作元素内容
element.innerText = '文本'; // 不解析HTML标签
element.innerHTML = '文本'; // 解析HTML标签
3.2 操作常见元素属性
element.src = 'images/img.png';
element.herf = 'http://www.baidu.com/';
element.title = '标题';
element.alt = '替代文本';
3.3 操作表单元素属性
element.type = 'email';
element.value = '请输入';
element.disabled = 'disabled';
3.4 操作元素样式属性
element.style.backgroundColor = '#fff';
element.className = 'change'
3.5 自定义属性值
element.属性; // 只能获取内置属性
element.getAttribute('属性'); // 可以获得自定义属性
element.属性 = '内容';
element.setAttribute('属性','内容');
element.dataset.属性 = '内容'; // 该方法的自定义属性‘data-属性’,html中属性的横杠对应js中的驼峰命名。IE版本至少为11
4. 节点操作
4.1 父节点
element.parentNode;
4.2 子节点
element.childNodes; // 获得所有子节点,包括元素子节点、属性子节点、文本子节点、注释子节点
element.children; // 获得所有元素子节点
element.firstChild; // 第一个子节点,可能是任意类型的子节点
element.lastChild; // 最后一个子节点,可能是任意类型的子节点
element.firstElementChild; // 第一个元素子节点, IE9以上支持
element.lastElementChile; // 最后一个元素子节点,IE9以上支持
element.children[0]; // 第一个元素子节点
element.children[ul.length]; // 最后一个元素子节点
4.3 兄弟节点
element.nextSibling; // 下一个兄弟节点
element.nextElementSibling; // 下一个元素兄弟节点,IE9以上
element.previousSibling; // 前一个兄弟节点
element.previousElementSibling; // 前一个元素兄弟节点,IE9以上
4.4 增删节点
var li = document.createElement('li');
ul.appendChild(li);
ul.insertBefore(li, ul.children[0]);
ul.removeChild(ul.children[0]);
4.5 克隆节点
var li = document.querySelector('ul li');
var liShallowCopy = li.cloneNode(); // 浅拷贝
var liDeepCopy = li.cloneNode(true); // 深拷贝
4.6 增加大量节点的性能
var ul = document.querySelector('ul');
// 低效
for (var i = 0; i < 1000; i++) {
ul.innerHTML += '<li></li>';
}
// 高效
for (var i = 0 ; i < 1000 ; i ++){
var li = document.createElement('li');
ul.appendChild(li);
}
//超高效
var arr = new Array(1000);
for (var i = 0 ; i < 1000 ; i ++){
arr[i] = '<li></li>';
}
ul.innerHTML = arr.join('');
2. BOM
1. 浏览器窗口事件
1.1 窗口加载事件
window.addEventListener('load', function() {
// 待页面加载完毕时,执行此函数。包括样式、图片、flash等
});
document.addEventListener('DOMContentLoaded', function() {
// 待DOM加载完毕时,执行此函数,不包含样式、图片、flash等
});
window.addEventListener('pageshow', function() {
// 待页面出现时执行。此函数是为了兼容FireFox浏览器的往返缓存。
// 这个缓存不仅保存着页面数据,还保存了DOM和JavaScript的状态,实际上是将整个页面都保存在了内存里。
});
1.2 调整窗口大小事件
window.addEventListener('resize', function() {
console.log('窗口大小变化了');
});
2. 定时器
// window可以省略
// 第二个参数是延时时间,单位是毫秒,缺省值是0
// 第一个参数称为回调函数
// 只调用一次
var time1 = window.setTimeout(function(){
console.log('时间到了')
}, 2000);
// 清除Timeout定时器
window.clearTimeout(time1);
// 反复调用
var time2 = window.setInterval(function(){
console.log('时间到了')
}, 2000);
// 清除Interval定时器
window.clearInterval(time2);
3. 执行队列
JS是单线程语言。但是HTML5提出的WebWorker标准,允许JS脚本创建多个线程。
JS执行机制:
- 先执行执行栈中的同步任务。
- 将异步任务(回调函数)放入任务队列(消息队列)中。
- 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
准确的说,应该是将异步任务放入异步进程处理当中,让它决定是否将该任务放入任务队列中。
事件循环:由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环。消息队列中的任务进入任务栈,执行结束后,会再去消息队列看看有无任务。
4. location对象
window的一个属性,用于获取或设置窗体的URL,并且可以用于解析URL。
4.1 URL
4.2 location对象的属性
4.3 location API
// 重定向:记录浏览历史,所以可以实现后退功能
location.assgin("https://www.baidu.com");
// 不记录浏览历史,所以不可以实现后退功能
location.replace("https://www.baidu.com");
// 刷新页面(F5,使用缓存内容),可以添加参数true,代表强制刷新(ctrl+F5,不带缓存的刷新,完全重新加载)
location.reload();
5. navigator对象
navigator对象包含有关浏览器的信息,该属性可以返回有客户机发送服务器的uesr-agent头部的值。可以判断是手机还是电脑之类的。
以下JS代码可以实现是手机端还是PC端。
6. history对象
实现前进和后退。
history.back(); // 后退
hsitory.forward(); // 返回
hsitory.go(2); // 参数正数代表前进,负数代表后退
3. PC端网页特效
1. offset偏移量
// 返回有定位的父元素,否则返回body
element.offsetParent;
// 返回元素相对于有定位的父元素的偏移
element.offsetTop;
element.offsetLeft;
// 返回元素的宽度和高度,与element.style.width、element.style.height类似,但存在区别
element.offsetWidth;
element.offsetHeight;
- offset与style的区别
offset | style |
---|---|
可以得到任意样式表中的样式值 | 只能得到行内样式表中的值 |
返回值没有单位 | 带单位 |
padding+border+width | 只有width |
只读属性 | 可以读写 |
想获取元素的大小位置,用offset | 想修改元素的值,用style |
2. 元素可视区client
client属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框的大小 |
element.clientWidth | padding+width |
element.clientHeight | padding+width |
3. 立即执行函数与flexible.js
(function(a,b) {
console.log(a+b)
})(1, 2);
// 不需要调用,直接执行
两种形式
(function() {})();
(function() {}()); // 比较老道的写法
立即执行函数最大的作用就是独立创建了一个作用域,都是局部变量,不会产生命名冲突。
4. scroll系列属性
element.scrollTop; // 代表元素被卷曲的长度
window.pageYOffset; // 代表窗口被卷曲的长度
document.addEventListener('scroll', function() {}); // 窗口滚动事件
5. offset、client、scroll三大系列总结
-
offset经常用于获得元素的位置
-
client经常用于获得元素的大小
-
scroll经常用于获得滚动距离
-
页面的滚动距离通过window.pageYOffset获得
-
window.scroll(x,y)将窗口滚动至指定位置,x,y不加单位
6. mouseover和mouseenter事件的区别
mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。
mouseenter只经过自身盒子会触发
之所以这样,就是因为mouseenter不会冒泡
7. 简单动画函数封装
function animante(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
if (obj.offsetLeft >= target) {
// 停止动画
clearInterval(obj.timer);
// 回调函数
if(callback) callback();
}
// 缓动动画
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
};
animante(document.querySelector('#div'),60);
// 注意,obj对象需要定位
div {
position :absolute;
left: 10px;
top: 10px;
width: 10px;
height: 10px;
background-color: pink;
}
4. 本地存储
1. window.sessionStorage会话存储
- 特点:
- 生命周期为关闭浏览器窗口,刷新也不会消失
- 在同一个窗口(页面)下数据可以共享
- 以键值对的形式存储使用
var val = input.value;
sessionStorage.setItem("key",val);
sessionStorage.getItem("key");
sessionStorage.removeItem("key");
sessionStorage.clear(); // 清除所有
2. window.localStorage本地存储
- 特点:
- 生命周期永久生效,除非手动删除,否则关闭页面也会存在
- 可以多窗口(页面)共享(同一浏览器可以共享)
- 以键值对的形式存储使用
var val = input.value;
localStorage.setItem("key",val);
localStorage.getItem("key");
localStorage.removeItem("key");
localStorage.clear(); // 清除所有
- 案例:记住账号密码