js2之DOM和BOM基础
1 DOM简介
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML或者XML)的标准编程接口
W3C 已经定义了一系列的 DOM 接口,通过这些 DOM 接口可以改变网页的内容、结构和样式
1.1 DOM树
文档:一个页面就是一个文档,DOM 中使用 document 表示
元素:页面中的所有标签都是元素,DOM 中使用 element 表示
节点:网页中的所有内容都是节点(属性、文本、注释等),DOM 中使用 node 表示
2 获取元素
DOM在我们实际开发中主要就是用来操作元素
获取页面中的元素可以使用以下几种方式:
根据 ID 获取
根据标签名获取
通过 HTML5 新增的方法获取
特殊元素获取
2.1 根据ID获取元素-getElementById()
使用 getElementById() 方法可以获取带有 ID 的元素对象
document.getElementById('idName'); // 参数是 id的名称
使用 console.dir() 可以打印获取的元素对象,更好的查看对象里面的属性和方法
2.2 根据标签名获取元素-getElementsByTagName()
使用 getElementsByTagName() 方法可以返回带有指定标签名的对象的集合
// 参数是 标签名,比如 div p li span 等
document.getElementsByTagName('标签名');
需要注意以下:
- 因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历
- 得到元素对象是动态的
- 如果获取不到元素,则返回为空的伪数组(因为获取不到对象)
我们还可以根据标签名获取某个元素(父元素)内部所有指定标签名的子元素
element.getElementsByTagName('标签名');
父元素element必须是单个对象(必须指明是哪一个元素对象),获取的时候不包括父元素自己
<ul>
<li>你好,你好</li>
<li>你好,你好</li>
<li>你好,你好</li>
<li>你好,你好</li>
</ul>
<ol id="ol">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ol>
<script>
var lis = document.getElementsByTagName('li');
// 1.返回的是 获取的元素对象集合,是以伪数组的形式存储的
console.log(lis, '返回所有的li元素对象集合');
console.log(lis[0], '获取第一个元素');
// 2. 如果想要依次打印里面的元素对象,可以采取遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
// 3. 还可以根据标签名获取某个元素(父元素)内部所有指定标签名的子元素
var ol = document.getElementById('ol');
var lis2 = ol.getElementsByTagName('li');
console.log(lis2, '返回ol里面的所有的li元素对象集合');
</script>
2.3 H5方法获取
getElementsByClassName('类名')
根据类名返回元素对象集合
querySelector('选择器')
根据指定选择器返回第一个元素对象
如果有多个元素对象,也只返回第一个元素对象
document.querySelectorAll('选择器')
根据指定选择器返回元素对象的集合
querySelector 和 querySelectorAll里面的选择器需要加符号,比如:document.querySelector('#nav');
<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, '返回所有的box元素对象集合');
// 2. querySelector 返回指定选择器的第一个元素对象 切记 里面的选择器需要加符号 .box #nav
var firstBox = document.querySelector('.box');
console.log(firstBox); // 只返回第一个元素对象
var nav = document.querySelector('#nav');
console.log(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>
2.4 特殊元素的获取
2.4.1 获取 body 元素
doucumnet.body // 返回body元素对象
2.4.2 获取 html 元素
document.documentElement // 返回html元素对象
2.5 classList 属性
classList属性是HTML5新增的一个属性,返回元素的类名。但是ie10以上版本支持
2.5.1 添加类
element.classList.add('类名');
2.5.2 移除类
element.classList.remove('类名');
2.5.3 切换类
element.classList.toggle('类名');
3 事件基础
JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为,就是触发--- 响应机制
网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个 事件,然后去执行某些操作
3.1 事件三要素
事件源 (哪个元素对象)
事件类型 (什么事件)
事件处理程序 (做什么)
3.2 执行事件的步骤
获取事件源
注册事件(绑定事件)
添加事件处理程序(采取函数赋值形式)
3.3 常见的鼠标事件
鼠标事件 | 触发条件 |
---|---|
onclick | 鼠标点击左键触发 |
onmouseover和onmouseout -- 有冒泡属性 | 鼠标经过/离开触发 |
onmouseenter/onmouseleave -- 没有冒泡属性 | 鼠标经过/离开触发 |
onfocus | 获取鼠标焦点触发 |
onblur | 失去鼠标焦点触发 |
onmousemove | 鼠标移动触发 |
onmouseup | 鼠标弹起触发 |
onmousedown | 鼠标按下触发 |
// 鼠标点击事件 onclick
var btn = document.getElementById('btn');
btn.onclick = function() {
alert('点击了按钮');
}
注意:mouseenter 和mouseover的区别:mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。 mouseenter 只会经过自身盒子触发
3.3.1 禁止鼠标右键菜单 contextmenu
document.addEventListener('contextmenu', function (e) {
// 阻止 鼠标右键菜单 的默认行为
e.preventDefault();
})
3.3.2 禁止鼠标选中 selectstart
document.addEventListener('selectstart', function (e) {
// 阻止 鼠标选中 的默认行为
e.preventDefault();
})
3.3.3 常用鼠标事件对象
event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象 MouseEvent 和键盘事件对象 KeyboardEvent
鼠标事件对象 | 说明 |
---|---|
e.clientX | 返回鼠标相对于 浏览器窗口 的可视区X坐标 |
e.clientY | 返回鼠标相对于 浏览器窗口 的可视区Y坐标 |
e.pageX | 返回鼠标相对于 文档页面 的X坐标 |
e.pageY | 返回鼠标相对于 文档页面 的Y坐标 |
e.screenX | 返回鼠标相对于 电脑屏幕 的X坐标 |
e.screenY | 返回鼠标相对于 电脑屏幕 的Y坐标 |
鼠标移动,图片跟随移动
<style>
img {
/* 图片尺寸是 96 80 */
position: absolute;
top: 2px;
}
</style>
<img src="images/angel.gif" alt="">
<script>
var img = document.querySelector('img');
// 注册 mousemove 鼠标移动 事件
document.addEventListener('mousemove', function (e) {
img.style.left = e.pageX - 48 + 'px';
img.style.top = e.pageY - 40 + 'px';
// -48 -40 是为了让图片始终位于 鼠标的中间位置
})
</script>
3.9 常用键盘事件
键盘事件 | 触发条件 |
---|---|
onkeyup | 键盘按键松开被触发(推荐) |
onkeydown | 键盘按键按下被触发 |
onkeypress | 键盘按键按下被触发,但是不识别功能键:ctrl shift 左右箭头等 |
keyCode | 键盘事件对象属性,返回该键的 ASCII 值 |
注意事项:
- 如果使用 addEventListener 不需要加 on
- onkeydown 和 onkeyup 不区分字母大小写,所以返回的keyCode大小写一样,onkeypress 区分字母大小写,所以返回的keyCode的大小写不一样
- 三个事件的执行顺序是: keydown - keypress - keyup
- onkeydown 如果一直按着不松开,会多次触发
3.4 注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件
注册事件有两种方式:传统注册方式和方法监听注册方式
3.4.1 传统注册方式
特点
利用 on 开头的事件,例如 onclick onmouseover onfocus 等s
特点: 注册事件的唯一性
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
语法结构
<button onclick=“alert('hi~')”></button>
btn.onclick = function() {}
3.4.2 方法监听注册方式 addEventListener
特点
w3c 标准 推荐方式
addEventListener()
它是一个方法
lIE9 之前的 IE 不支持此方法,可使用 attachEvent()
代替
特点:同一个元素同一个事件可以注册多个监听器
按注册顺序依次执行
语法结构
eventTarget.addEventListener(type, listener[, useCapture])
eventTarget.addEventListener()
方法将指定的监听器注册到 eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数
3个参数:
type:****事件类型字符串,比如 click 、mouseover ,注意这里不要带 on
listener:事件处理函数,事件发生时,会调用该监听函数
useCapture:可选参数,是一个布尔值,默认是 false,就是冒泡
3.4.3 attachEvent 事件监听方式 (IE9之前)
eventTarget.attachEvent(eventNameWithOn, callback)
eventTarget.attachEvent()方法将指定的监听器注册到 eventTarget(目标对象) 上,当该对象触发指定的事件时,指定的回调函数就会被执行
2个参数:
eventNameWithOn:事件类型字符串,比如 onclick 、onmouseover ,这里要带 on
callback: 事件处理函数,当目标触发事件时回调函数被调用
IE8 及早期版本支持
3.4.4 注册事件兼容性解决方案
function addEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 addEventListener 方法
if (element.addEventListener) {
element.addEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
// 相当于 element.onclick = fn;
element['on' + eventName] = fn;
}
}
3.5 解绑(删除)事件
// 传统事件 解绑
eventTarget.onclick = null;
// 方法监听注册方式 解绑
eventTarget.removeEventListener(type, listener[, useCapture]);
eventTarget.detachEvent(eventNameWithOn, callback); --- IE9 之前
3.5.1 解绑事件 兼容性
function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
3.6 DOM事件流
事件流描述的是从页面中接收事件的顺序
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即 DOM 事件流
DOM事件流分为3个阶段: 捕获阶段、当前目标阶段、冒泡阶段
事件冒泡: 事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程
事件捕获: 由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程
DOM事件流过程:
我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡
注意事项:
- JS 代码中只能执行捕获或者冒泡其中的一个阶段
- onclick 和 attachEvent(IE9以下注册事件) 只能得到冒泡阶段
- addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
捕获阶段
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
// 点击 son div,会依次输出:document father son
var son = document.querySelector('.son');
var father = document.querySelector('.father');
son.addEventListener('click', function () {
alert('son');
}, true);
father.addEventListener('click', function () {
alert('father');
}, true);
document.addEventListener('click', function () {
alert('document');
}, true);
</script>
冒泡阶段
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
// 点击 son div,会依次输出:son father document
var son = document.querySelector('.son');
var father = document.querySelector('.father');
son.addEventListener('click', function () {
alert('son');
}, false);
father.addEventListener('click', function () {
alert('father');
}, false);
document.addEventListener('click', function () {
alert('document');
})
</script>
3.7 事件对象 event
event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态;
事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象 event,它有很多属性和方法
这个 event 是个形参,系统帮我们设定为事件对象,不需要传递实参过去
当我们注册事件时, event 对象就会被系统自动创建,并依次传递给事件监听器(事件处理函数)
eventTarget.onclick = function(event) {
}
eventTarget.addEventListener('click', function(event) {
})
// 这个 event 就是事件对象,我们还喜欢的写成 e 或者 evt
件对象本身的获取存在兼容问题
标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到
在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找
兼容性方案:e = e || window.event
事件对象常用的属性和方法
e.target
:返回触发事件的对象
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function (e) {
console.log(e.target); // 返回:<button>点击</button>
console.log(window.event.srcElement); // IE6-8 标准
});
</script>
e.srcElement:是IE6-8使用
this 和 e.target区别
this 是事件绑定的元素, 这个函数的调用者(绑定这个事件的元素) ,谁调用就指向谁
e.target 是事件触发的元素,谁点击就指向谁
<div>123</div>
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<script>
// 1. e.target 返回的是触发事件的对象(元素) this 返回的是绑定事件的对象(元素)
// 区别 : e.target 点击了那个元素,就返回那个元素
// this 哪个元素绑定了这个点击事件,那么就返回谁
var div = document.querySelector('div');
div.addEventListener('click', function (e) {
// e.target 谁点击(触发)了那个元素,就返回哪个对象
console.log(e.target); // 返回:<div>123</div>
// 哪个元素绑定了这个事件,就返回哪个对象
console.log(this); // 返回:<div>123</div>
})
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
console.log(this); // 返回:ul对象,因为是ul绑定了事件
console.log(e.currentTarget); // 返回和this一样,但是ie6-8不兼容
// e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
console.log(e.target);
})
</script>
e.type:返回事件类型
例如:click、focus、blur,不带 on
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function (e) {
console.log(e.type); // 返回:click
});
</script>
e.preventDefault() 阻止默认事件
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function (e) {
// 阻止默认事件
e.preventDefault();
// IE6-8标准
window.event.returnValue;
});
</script>
e.stopPropagation() 阻止冒泡
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function (e) {
// 阻止事件 冒泡
e.stopPropagation();
// IE6-8标准
window.eventcancelBubble=true;
});
// 兼容性写法:
if(e && e.stopPropagation){
e.stopPropagation();
}else{
window.event.cancelBubble = true;
}
</script>
3.8 事件委托(代理、委派)
事件委托也称为事件代理, 在 jQuery 里面称为事件委派
3.8.1 原理
不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点
<ul>
<li>知道了1</li>
<li>知道了2</li>
<li>知道了3</li>
<li>知道了4</li>
<li>知道了5</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
// 给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// e.target 获取每个点击的对象
e.target.style.backgroundColor = 'red';
})
</script>
3.8.2 作用
我们只操作了一次 DOM ,提高了程序的性能
4 操作元素
JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容 、属性等
4.1 改变元素的内容
element.innerText
从起始位置到终止位置的内容, 但它去除 html 标签, 同时空格和换行也会去掉
element.innerHTML
起始位置到终止位置的全部内容,包括 html 标签,同时保留空格和换行
element.innerText和element.innerHTML,不仅可以设置元素的内容,还可以获取元素的内容
<button>点击显示当前系统时间</button>
<div></div>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2. 注册时间并添加事件处理函数
btn.onclick = function () {
// 点击修改 元素的内容 显示
div.innerHTML = getDate();
}
// 获取当前系统时间
function getDate() {
var date = new Date();
console.log(date)
var y = date.getFullYear();
var m = date.getMonth() + 1;
m = m < 10 ? '0' + m : m;
var d = date.getDate();
d = d < 10 ? '0' + d : d;
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
return '今天是' + y + '年' + m + '月' + d + '日 ' + arr[+date.getDay()] + '';
}
4.2 元素的属性操作
常见的元素属性操作有: src、href、 id、alt、title
element.src=新的属性
<button id="ldh">刘德华</button>
<button id="zxy">张学友</button> <br>
<img src="images/ldh.jpg" alt="我是刘德华" title="刘德华">
<script>
// 1. 获取元素
var ldh = document.getElementById('ldh');
var zxy = document.getElementById('zxy');
var img = document.querySelector('img');
// 2. 注册事件 并添加事件处理程序
zxy.onclick = function () {
img.src = 'images/zxy.jpg';
img.title = '张学友';
img.alt = '我是张学友图片';
}
ldh.onclick = function () {
img.src = 'images/ldh.jpg';
img.title = '刘德华';
img.alt = '我是刘德华图片';
}
</script>
4.3 自定义属性操作
4.3.1 获取属性值
// 获取 内置属性值
element.属性
// 获取自定义属性值
element.getAttribute('属性');
4.3.2 设置属性值
// 只能设置 内置属性值
element.属性 = ‘值’
// 设置 自定义 属性值
element.setAttribute('属性', '值');
4.3.3 移除属性
element.removeAttribute('属性');
4.4 h5 自定义属性
自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
自定义属性获取是通过 getAttribute(‘属性’)
获取。
但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性,因此,H5给我们新增了自定义属性:
H5规定自定义属性data-开头做为属性名并且赋值
设置属性
// 设置属性 data-index
<div data-index=“1”></div>
// 通过 js 设置属性 data-index
element.setAttribute(‘data-index’, 2)
获取属性
element.getAttribute(‘data-index’);
H5新增 element.dataset.index
或者 element.dataset[‘index’]
的方式获取 自定义属性,但是只有 ie 11才开始支持
4.5 表单元素的属性操作
利用 DOM 可以操作如下表单元素的属性
type、value、checked、selected、disabled
<button>按钮</button>
<input type="text" value="输入内容">
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
// 2. 注册事件 并添加事件处理程序
btn.onclick = function () {
// 修改input里面的内容
input.value = '我是新的输入内容';
// 设置 btn 不可再次点击
// this 指向的是事件函数的调用者 btn
this.disabled = true;
}
</script>
this 指向的是事件函数的调用者
4.6 样式属性操作
可以通过 JS 修改元素的大小、颜色、位置等样式
JS 里面的样式采取驼峰命名法 ,比如 fontSize、 backgroundColor
JS 修改 style 样式操作,产生的是行内样式,CSS 权重比较高
4.6.1 element.style
行内样式操作
element.style 获得修改元素样式 ,一般是样式比较少,功能简单的的时候使用
// 1. 获取元素
var div = document.querySelector('div');
// 2. 注册事件 处理程序
div.onclick = function() {
// div.style里面的属性 采取驼峰命名法
this.style.backgroundColor = 'purple';
this.style.width = '250px';
this.style.display = 'none';
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
4.6.2 element.className
类名样式操作
修改元素的className更改元素的样式, 适合于样式较多或者功能复杂的情况
var test = document.querySelector('div');
test.onclick = function () {
this.className = 'first change';
}
5 节点操作
网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM 中,节点使用 node 来表示
节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性
元素节点 nodeType 为 1
属性节点 nodeType 为 2
文本节点 nodeType 为 3 (文本节点包含文字、空格、换行等)
一般情况下,节点操作主要操作的是元素节点
利用 DOM 树可以把节点划分为不同的层级关系,常见的是父子兄层级关系
5.1 父亲节点
node.parentNode
parentNode 属性可返回某节点的父节点,注意是最近的一个父节点
如果指定的节点没有父节点则返回 null
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
var erweima = document.querySelector('.erweima');
// 得到的是离元素最近的父级节点 box, 如果找不到父节点就返回为 null
console.dir(erweima.parentNode)
</script>
5.2 子节点
// 返回包含指定节点的子节点的集合--不推荐
parentNode.childNodes(标准)
返回值里面包含了所有的子节点,包括元素节点,文本节点等
如果只想要获得里面的元素节点,则需要专门处理,
parentNode.children(非标准)-- 推荐使用
parentNode.children 是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回
虽然children 是一个非标准,但是得到了各个浏览器的支持,因此我们可以放心使用
第一个和最后一个子节点
// 返回第一个子节点,找不到则返回null。同样,也是包含所有的节点 -- 不推荐
parentNode.firstChild
// 返回最后一个子节点,找不到则返回null。同样,也是包含所有的节点-- 不推荐
parentNode.lastChild
// 以下 两个方法有兼容性问题,IE9 以上才支持
// 返回第一个子元素节点,找不到则返回null -- 推荐使用
parentNode.firstElementChild
// 返回最后一个子元素节点,找不到则返回null -- 推荐使用
parentNode.lastElementChild
5.3 兄弟节点
// 返回当前元素的下一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点 -- 不推荐
node.nextSibling
// 返回当前元素上一个兄弟元素节点,找不到则返回null。同样,也是包含所有的节点 -- 不推荐
node.previousSibling
// 注意:下面的个方法有兼容性问题, IE9 以上才支持
// 返回当前元素下一个兄弟元素节点,找不到则返回null -- 推荐
node.nextElementSibling
// 返回当前元素上一个兄弟节点,找不到则返回null -- 推荐
node.previousElementSibling
5.4 新增节点
5.4.1 创建节点
document.createElement('tagName')
document.createElement() 方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点
5.4.2 添加节点
// 将一个节点添加到指定 父节点的子节点 列表末尾
node.appendChild(child)
// 方法将一个节点添加到父节点的指定子节点前面
node.insertBefore(child, 指定元素)
5.4.3 删除节点
// 从 DOM 中删除一个子节点,返回删除的节点
node.removeChild(child)
简易留言板案例
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 100px;
}
textarea {
width: 200px;
height: 100px;
border: 1px solid pink;
outline: none;
resize: none;
}
ul {
margin-top: 50px;
}
li {
width: 300px;
padding: 5px;
background-color: rgb(245, 209, 243);
color: red;
font-size: 14px;
margin: 15px 0;
}
</style>
<textarea name="" id=""></textarea>
<button>发布</button>
<ul></ul>
<script>
// 1. 获取元素
var btn = document.querySelector('button');
var textarea = document.querySelector('textarea');
var ul = document.querySelector('ul');
// 2. 给btn 注册事件并添加事件处理程序
btn.onclick = function () {
// 2.0 获取textarea输入框的内容
var value = textarea.value;
if (value.length == 0) {
alert('内容不可为空!');
return;
}
// 2.1 创建元素 li
var li = document.createElement('li');
li.innerHTML = value;
// 2.2 添加元素
// ul.appendChild(li); // 这个是添加到ul父元素的最后
ul.insertBefore(li, ul.children[0]); // 添加到第一个
// 2.3 添加成功后 清空输入框
textarea.value = '';
}
</script>
6 BOM 概述
BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window
BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性
6.1 DOM 和 BOM
DOM | BOM |
---|---|
文档对象模型 | 浏览器对象模型 |
DOM 就是把「文档」当做一个「对象」来看待 | 把「浏览器」当做一个「对象」来看待 |
DOM 的顶级对象是 document | BOM 的顶级对象是 window |
DOM 主要是操作页面元素 | BOM 主要是浏览器窗口交互的一些对象 |
DOM 是 W3C 标准规范 | BOM 是浏览器厂商在各自浏览器上定义的,兼容性较差 |
6.2 BOM的构成
BOM 比 DOM 更大,它包含 DOM
window 包含 document、location、navigation、screen、history
window 对象是浏览器的顶级对象,它具有双重角色:
-
它是 JS 访问浏览器窗口的一个接口
-
它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法
var num = 10; console.log(num); // 返回:10 console.log(window.num); // 返回:10 function fn() { console.log(11); } fn(); // 返回:11 window.fn(); // 返回:11
在调用的时候可以省略 window,例如经常使用的:alert() prompt()
7 window 对象常用事件
7.1 窗口加载事件 onload
window.onload 是窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数
有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕,再去执行处理函数
window.onload 传统注册事件方式 只能写一次,如果有多个,会以最后一个 window.onload 为准;如果使用 addEventListener 则没有限制
// 当文档对象加载完成时 会触发此事件,包含 图像、脚本文件、CSS等全部加载完毕
window.onload = function(){
}
// 或者
window.addEventListener("load",function(){
});
DOMContentLoaded 事件触发时,仅当DOM加载完成,不包括样式表,图片,flash等等。Ie9以上才支持
如果页面的图片很多的话, 从用户访问到onload触发可能需要较长的时间, 交互效果就不能实现,必然影响用户的体验,此时用 DOMContentLoaded 事件比较合适
document.addEventListener('DOMContentLoaded',function(){})
7.2 调整窗口大小事件 onresize
window.onresize 是调整窗口大小加载事件, 当触发时就调用的处理函数
只要窗口大小发生像素变化,就会触发这个事件
window.onresize = function(){}
window.addEventListener("resize",function(){});
window.innerWidth 获取的是 当前屏幕的宽度
8 定时器
8.1 setTimeout()
setTimeout() 方法用于设置一个定时器,该定时器在指定时间后执行调用函数
window.setTimeout(调用函数, [延迟的毫秒数]);
毫秒数如果为空,则立即执行 调用函数
停止定时器
window.clearTimeout(timeoutID)
timeoutID是定时器的标识符
说明:
- window 可以省略
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串‘函数名()' -- 不推荐 三种形式
- 延迟的毫秒数省略默认是 0,单位是毫秒
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
8.2 setInterval()
setInterval() 方法重复调用一个函数,每隔这个时间,就去调用一次回调函数
window.setInterval(回调函数, [间隔的毫秒数]);
停止定时器
window.clearInterval(intervalID);
timeoutID是定时器的标识符
说明:
- window 可以省略
- 这个调用函数可以直接写函数,或者写函数名或者采取字符串 '函数名()' 三种形式
- 间隔的毫秒数省略默认是 0,单位是毫秒,表示每隔多少毫秒就自动调用这个函数
- 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符
- 第一次执行也是间隔毫秒数之后执行,之后每隔毫秒数就执行一次
9 this指向
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象
现阶段,我们先了解一下几个this指向
-
全局作用域、普通函数、定时器 中this指向全局对象window
console.log(this); // 指向 window function fn() { console.log(this); // 指向 window } setTimeout(function () { console.log(this); // 指向 window }, 1000);
-
方法调用中,谁调用这个方法,this指向谁
var obj = { sayHi: function () { console.log(this); // this指向的是 obj 这个对象 } } obj.sayHi(); var btn = document.querySelector('button'); btn.addEventListener('click', function () { console.log(this); // this指向的是btn这个按钮对象 })
-
构造函数中this,指向构造函数的实例
function Fun() { console.log(this); // this 指向的是fun 实例对象 } var fun = new Fun();
10 JS 执行队列
10.1 JS 是单线程
JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行, 应该先进行添加,之后再删除。
单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是: 如果 JS 执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉
为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出 Web Worker 标准,允许 JavaScript 脚本创建多个线程。于是,JS 中出现了同步和异步
10.2 同步和异步
10.2.1 概述
同步:前一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的
异步:可以同时执行多个任务:你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情
同步和异步的本质区别:这条流水线上各个流程的执行顺序不同
10.2.2 同步任务和异步任务
同步任务:都在主线程上执行,形成一个执行栈
异步任务:
JS 的异步是通过回调函数实现的,一般而言,异步任务有以下三种类型:
1、普通事件,如 click、resize 等
2、资源加载,如 load、error 等
3、定时器,包括 setInterval、setTimeout 等
异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)
10.3 JS 执行机制
1、 先执行执行栈中的同步任务。
2、 异步任务(回调函数)放入任务队列中。
3、 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
事件循环:由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( event loop)
11 window 常用对象
11.1 location 对象
window 对象给我们提供了一个 location 属性,用于获取或设置窗体的 URL,并且可以用于解析 URL 。 因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象
11.1.1 url 统一资源定位符
是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它
URL 的一般语法格式为:
protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
组成 | 说明 |
---|---|
protocol | 通信协议,常用的是 http https matio ftp等 |
host | 主机(域名) www.itcast.cn |
port | 端口号(可选) 默认是80 |
pathname | 路径 由0个或多个 / 隔开的字符串,一般用来表示主机上的一个文件或目录 |
search | 参数,以键值对的形式,& 隔开 |
hash | # 后面的,一般用户锚点 |
11.1.2 location对象的方法
对象方法 | 说明 |
---|---|
location.href=new url | 跳转到指定页面,记录历史path,新的页面会有回退按钮 |
location.assign() | 功能等同于 location.href |
location.replace() | 替换当前页面,不记录历史path,所以新的页面没有回退按钮 |
location.reload() | 重新加载(刷新)页面,相当于F5;如果要强刷 Ctrl+F5,传参 true 即可 |
11.2 navigation 对象
navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是 userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
// 手机端打开的页面
} else {
// PC端打开的页面
}
11.3 history 对象
history 对象 与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的 URL。
history 对象方法 | 作用 |
---|---|
back() | 后退 |
forward() | 前进 |
go() | 前进、后退功能,如果参数是1,前进一页;如果参数是-1,后退一页 |
12 元素偏移量 offset
offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小等
- 获得元素距离带有定位父元素的位置 left 和 top
- 获得元素自身的大小(宽度高度)
- 注意: 返回的数值都不带单位
常用属性
属性 | 作用 |
---|---|
ele.offsetParent | 返回当前元素带有定位的父元素(带有定位),如果父元素都没有定位,返回body |
ele.offsetLeft | 返回当前元素相对于父元素(带有定位)的左方的偏移 |
ele.offsetTop | 返回当前元素相对于父元素(带有定位)的上方的偏移 |
ele.offetWidth | 返回当前元素包含padding、边框、内容区域的宽度,不带单位 |
ele.offetHeight | 返回当前元素包含padding、边框、内容区域的高度,不带单位 |
鼠标移动时,计算相对于盒子内的位置
<style>
.box {
width: 300px;
height: 300px;
background-color: pink;
margin: 200px;
}
</style>
<div class="box"></div>
<script>
// 计算 鼠标移动时,相对于盒子内的坐标
var box = document.querySelector('.box');
box.addEventListener('mousemove', function (e) {
// 鼠标相对于 文档的x距离 - 盒子相对于 文档的 偏移
var x = e.pageX - this.offsetLeft;
var y = e.pageX - this.offsetTop;
this.innerHTML = 'x坐标是' + x + ' y坐标是' + y;
});
</script>
拖动移动小盒子,并且不要超出大盒子的范围
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<style>
.big {
width: 500px;
height: 500px;
border: 1px red solid;
margin: 30px auto;
position: relative;
}
.small {
width: 300px;
height: 300px;
background-color: yellow;
cursor: move;
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body>
<div class="big">
<div class="small"></div>
</div>
<script>
// 1. 获取元素
var big = document.querySelector('.big');
var small = document.querySelector('.small');
// 拖动小盒子 在大盒子内移动(不能移出大盒子)
small.addEventListener('mousedown', function (e) {
// 获得鼠标在盒子内的坐标
var x = e.pageX - small.offsetLeft;
var y = e.pageY - small.offsetTop;
// 鼠标移动,重新设置小盒子的位置
document.addEventListener('mousemove', move);
// 鼠标松开,移除 鼠标移动事件
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
})
function move(e) {
var newBoxLeft = e.pageX - x;
if (newBoxLeft <= 0) {
newBoxLeft = 0;
} else if (newBoxLeft > big.offsetWidth - small.offsetWidth > 0) {
newBoxLeft = big.offsetWidth - small.offsetWidth
}
small.style.left = newBoxLeft + 'px';
var newBoxTop = e.pageY - y;
if (newBoxTop <= 0) {
newBoxTop = 0;
} else if (newBoxTop > big.offsetHeight - small.offsetHeight) {
newBoxTop = big.offsetHeight - small.offsetHeight;
}
small.style.top = newBoxTop + 'px';
}
});
</script>
</body>
</html>
拖动的模态框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Document</title>
<style>
.login-header {
width: 100%;
text-align: center;
height: 30px;
font-size: 24px;
line-height: 30px;
}
ul,
li,
ol,
dl,
dt,
dd,
div,
p,
span,
h1,
h2,
h3,
h4,
h5,
h6,
a {
padding: 0px;
margin: 0px;
}
.login {
display: none;
width: 512px;
height: 280px;
position: fixed;
border: #ebebeb solid 1px;
left: 50%;
top: 50%;
background: #ffffff;
box-shadow: 0px 0px 20px #ddd;
z-index: 9999;
transform: translate(-50%, -50%);
}
.login-title {
width: 100%;
margin: 10px 0px 0px 0px;
text-align: center;
line-height: 40px;
height: 40px;
font-size: 18px;
position: relative;
cursor: move;
}
.login-input-content {
margin-top: 20px;
}
.login-button {
width: 50%;
margin: 30px auto 0px auto;
line-height: 40px;
font-size: 14px;
border: #ebebeb 1px solid;
text-align: center;
}
.login-bg {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
background: rgba(0, 0, 0, .3);
}
a {
text-decoration: none;
color: #000000;
}
.login-button a {
display: block;
}
.login-input input.list-input {
float: left;
line-height: 35px;
height: 35px;
width: 350px;
border: #ebebeb 1px solid;
text-indent: 5px;
}
.login-input {
overflow: hidden;
margin: 0px 0px 20px 0px;
}
.login-input label {
float: left;
width: 90px;
padding-right: 10px;
text-align: right;
line-height: 35px;
height: 35px;
font-size: 14px;
}
.login-title span {
position: absolute;
font-size: 12px;
right: -20px;
top: -30px;
background: #ffffff;
border: #ebebeb solid 1px;
width: 40px;
height: 40px;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
<div id="login" class="login">
<div id="title" class="login-title">登录会员
<span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
</div>
<div class="login-input-content">
<div class="login-input">
<label>用户名:</label>
<input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
</div>
<div class="login-input">
<label>登录密码:</label>
<input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
</div>
</div>
<div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
</div>
<!-- 遮盖层 -->
<div id="bg" class="login-bg"></div>
<script>
/*
1. 点击弹出层, 模态框和遮挡层 显示 display:block;
2. 点击关闭按钮,模态框和遮挡层 隐藏 display:none;
3. 在页面中拖拽的原理: 鼠标按下并且移动,之后松开鼠标
触发事件是鼠标按下 mousedown, 鼠标移动mousemove 鼠标松开 mouseup
拖拽过程: 鼠标移动过程中,获得最新的值赋值给模态框的left和top值, 这样模态框可以跟着鼠标走了
鼠标按下触发的事件源是 最上面一行,就是 id 为 title
鼠标的坐标 减去 鼠标在盒子内的坐标, 才是模态框真正的位置。
鼠标按下,我们要得到鼠标在盒子的坐标。
鼠标移动,就让模态框的坐标 设置为 : 鼠标坐标 减去盒子坐标即可,注意移动事件写到按下事件里面。
鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除
*/
// 1. 获取元素
var link = document.querySelector('#link');
var login_dialog = document.querySelector('.login');
var mask = document.querySelector('.login-bg');
var closeBtn = document.querySelector('#closeBtn');
var title = document.querySelector('#title');
// 2. 点击 弹出 模态框
link.addEventListener('click', function () {
login_dialog.style.display = 'block';
mask.style.display = 'block';
});
// 3. 点击 关闭 模态框
closeBtn.addEventListener('click', function () {
login_dialog.style.display = 'none';
mask.style.display = 'none';
});
// 4. 开始拖拽
// (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
title.addEventListener('mousedown', function (e) {
// 获得鼠标在盒子内的坐标
var x = e.pageX - login_dialog.offsetLeft;
var y = e.pageY - login_dialog.offsetTop;
// 给document添加 鼠标移动事件,重新设置模态框的位置
document.addEventListener('mousemove', move);
// 鼠标弹起,就让鼠标移动事件移除
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
})
function move(e) {
login_dialog.style.left = e.pageX - x + 'px';
login_dialog.style.top = e.pageY - y + 'px';
}
});
</script>
</body>
</html>
13 元素可视去区 client
client 相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性可以动态的得到该元素的边框大小、元素大小等
属性 | 作用 |
---|---|
ele.clientLeft | 返回元素左边框的大小 |
ele.clientTop | 返回元素上边框的大小 |
ele.clientWidth | 返回当前元素包含padding、内容区域的宽度,不含边框,不带单位 |
ele.clientHeight | 返回当前元素包含padding、内容区域的高度,不含边框,不带单位 |
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
border: 10px solid red;
padding: 10px;
}
</style>
<div></div>
<script>
// client 宽度 和 offsetWidth 最大的区别就是 不包含边框大小
var div = document.querySelector('div');
console.log(div.offsetWidth); // 返回:240 - 包含边框大小
console.log(div.clientWidth); // 返回:220
console.log(div.clientLeft); // 返回:10 元素左边框的大小
console.log(div.clientTop); // 返回:10 元素上边框的大小
</script>
14 元素滚动 scroll
使用 scroll 系列的相关属性,可以动态的得到该元素的大小、滚动距离等
如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发 onscroll 事件
属性 | 作用 |
---|---|
ele.scrollLeft | 返回被卷去的左侧距离 |
ele.scrollTop | 返回被卷去的上侧距离 |
ele.scrollWidth | 返回当前元素实际宽度,不带单位 |
ele.scrollHeight | 返回当前元素实际高度,不带单位 |
元素被卷去的头部是 element.scrollTop , 如果是页面被卷去的头部 则是 window.pageYOffset
仿淘宝侧边栏案例
<!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>
<style>
.slider-bar {
position: absolute;
left: 50%;
top: 300px;
margin-left: 600px;
width: 45px;
height: 130px;
background-color: pink;
}
.w {
width: 1200px;
margin: 10px auto;
}
.header {
height: 150px;
background-color: purple;
}
.banner {
height: 250px;
background-color: skyblue;
}
.main {
height: 1000px;
background-color: yellowgreen;
}
span {
display: none;
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="slider-bar">
<span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
//1. 获取元素
var sliderbar = document.querySelector('.slider-bar');
var banner = document.querySelector('.banner');
var main = document.querySelector('.main');
var goBack = document.querySelector('.goBack');
// banner 区域距离顶部的距离
var bannerTop = banner.offsetTop;
// 侧边栏距离 banner 的距离
var sliderbarTop = sliderbar.offsetTop - bannerTop;
// main距离 顶部的距离
var mainTop = main.offsetTop;
// scroll 滚动事件
document.addEventListener('scroll', function () {
console.log(sliderbar.offsetTop)
// 2. 当滚动到大于等于banner位置的时候,侧边栏 定位变为 fixed ,否则是 absolute;
// 同时 重新设置 slidebar的top属性:侧边栏距离 banner 的距离
if (window.pageYOffset > bannerTop) {
sliderbar.style.position = 'fixed';
sliderbar.style.top = sliderbarTop + 'px';
} else {
sliderbar.style.position = 'absolute';
sliderbar.style.top = '300px';
}
// 2. 当滚动到大于等于main位置的时候,显示 返回顶部按钮
if (window.pageYOffset > mainTop) {
goBack.style.display = 'block';
} else {
goBack.style.display = 'none';
}
});
// 返回顶部
goBack.addEventListener('click', function () {
// window.scroll(0, 0);
animate(window, 0);
});
// 动画函数 上下 移动动画
function animate(obj, target, callback) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var step = (target - window.pageYOffset) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (window.pageYOffset == target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
callback && callback();
}
window.scroll(0, window.pageYOffset + step);
}, 15);
}
</script>
</body>
</html>
页面被卷去的头部兼容性解决方案
1、 声明了 DTD,使用 document.documentElement.scrollTop
2、 未声明 DTD,使用 document.body.scrollTop
3、 新方法 window.pageYOffset 和 window.pageXOffset,IE9 开始支持
function getScroll() {
return {
left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
};
}
// 使用的时候
getScroll().left
15 offset client scroll区分
属性 | 作用 |
---|---|
ele.offsetWidth | 返回元素包含padding、边框、内容区域的宽度,不带单位 |
ele.clientWidth | 返回元素包含padding、内容区域的宽度,不包含边框,不带单位 |
ele.scrollWidth | 返回元素实际宽度,不带单位 |
1、 offset系列 经常用于获得元素位置 offsetLeft offsetTop
2、 client 经常用于获取元素大小 clientWidth clientHeight
3、 scroll 经常用于获取滚动距离 scrollTop scrollLeft
4、 注意页面滚动的距离通过 window.pageXOffset 获得
16 JS 动画
核心原理:通过定时器 setInterval() 不断移动盒子位置
封装的animate.js文件
/*
动画原理:
1. 获得盒子当前位置
2. 让盒子在当前位置上每次移动一定的步长:(目标值 - 现在的位置) / 10 做为每次移动的距离
3. 利用定时器不断重复这个操作(注意一定要加一个条件来终止定时器)
3. 利用定时器不断重复这个操作
4. 注意此元素需要添加定位, 才能使用element.style.left
匀速动画:盒子是当前的位置 + 固定的值 10
缓动动画:盒子当前的位置 + 变化的值 (目标值 - 现在的位置) / 10)
*/
// obj元素对象 target目标 callback回调函数
function animate(obj, target, callback) {
// 首先先清除定时器
clearInterval(obj.timer);
// 创建一个 timer定时器
obj.timer = setInterval(function () {
// 计算 步长
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
if (obj.offsetLeft == target) {
// 停止动画,本质就是停止定时器
clearInterval(obj.timer);
// 当动画停止时,判断是否有回调函数
// if (callback) {
// callback();
// }
// 简写
callback && callback();
}
// 每次移动 step 的步长:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
点击按钮 向左向右移动到指定的位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
position: absolute;
left: 100px;
top: 100px;
width: 100px;
height: 100px;
background-color: pink;
}
</style>
</head>
<body>
<script src="animate1.js"></script>
<div></div>
<button class="btn500">向右移动到800</button>
<button class="btn100">向左移动到100</button>
<script>
/*
动画原理:
1. 获得盒子当前位置
2. 让盒子在当前位置上每次移动一定的步长:(目标值 - 现在的位置) / 10 做为每次移动的距离
3. 利用定时器不断重复这个操作(注意一定要加一个条件来终止定时器)
3. 利用定时器不断重复这个操作
4. 注意此元素需要添加定位, 才能使用element.style.left
匀速动画:盒子是当前的位置 + 固定的值 10
缓动动画:盒子当前的位置 + 变化的值 (目标值 - 现在的位置) / 10)
*/
// 1. 获取元素
var div = document.querySelector('div');
var btn500 = document.querySelector('.btn500');
var btn100 = document.querySelector('.btn100');
// 2. 点击按钮移动盒子到指定的位置
btn500.addEventListener('click', function () {
// 调用函数animate
animate(div, 500);
})
btn100.addEventListener('click', function () {
// 调用函数animate
animate(div, 100, function () {
div.style.backgroundColor = 'red';
});
})
</script>
</body>
</html>
17 本地存储
特性:
1、 数据存储在用户浏览器中
2、 设置、读取方便、甚至页面刷新不丢失数据
3、 容量较大,sessionStorage约5M、localStorage约20M
4、 只能存储字符串,可以将对象JSON.stringify() 编码后存储
window.sessionStorage | window.localStorage |
---|---|
生命周期:关闭浏览器窗口 | 生命周期:永久生效,除非手动删除 ,否则关闭页面也会存在 |
在同一个窗口(页面)下,数据可以共享 | 可以多窗口(页面)共享:(同一浏览器都可以共享) |
以键值对的形式存储使用 | 以键值对的形式存储使用 |
存储数据:sessionStorage.setItem(key, value) | 存储数据:localStorage.setItem(key, value) |
获取数据:sessionStorage.getItem(key) | 获取数据:localStorage.getItem(key) |
删除数据:sessionStorage.removeItem(key) | 删除数据:localStorage.removeItem(key) |
删除所有数据:sessionStorage.clear() | 删除所有数据:localStorage.clear() |