问题:整个页面 由元素嵌套元素,document是最外面的最大的元素,当单击一个div时,同时你也单击了div的父元素,甚至整个页面。哪么是先执行父元素的单击事件,还是先执行div的单击事件???
-
事件流: 描述的是从页面中接收事件的顺序。
事件被触发时
会在元素节点之间按照特定的顺序传播
,这个过程就是事件流- 例如:首先给div注册单击事件,当你单击了div时,也就是单击body、单击了html,单击了document。
-
事件捕获:网景最早提出:document对象首先接收到click事件,然后事件沿着DOM树逐级向下传播,直到传播到事件的实际目标。(由外向内)
-
事件冒泡:IE最早提出:事件由具体的元素(文档中嵌套层次最深的哪个节点)接收,然后逐级向上传播到DOM最顶层节点的过程 。(由内向外)
-
W3C统一:制定统一的标准——先捕获再冒泡。IE、Firefox、Chrome、Opera和Safari即支持冒泡又支持捕获。目前低版本的IE浏览器只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流)建议使用冒泡流。
-
总结
:比如我们向水里面扔一块石头,首先石头下降的过程,可以理解为事件捕获,石头下降至水底之后产生气泡,气泡上升的过程,可以理解为事件冒泡。 -
注意
: js代码中只能执行捕获或者冒泡的其中一个阶段- onclick和attachEvent 只能得到冒泡阶段
- addEventListener(type、listener、useCapture) 第三个参数如果是
true
,表示在事件捕获阶段调用事件处理程序,如果是false
(不写默认是false) 则表示的是事件冒泡阶段调用事件处理程序。 - 实际开发中我们很少使用事件捕获,我们更关注事件冒泡
- 有些事件是没有事件冒泡的,比如
blur
、focus、mouseenter、mouseleave - 如何阻止事件冒泡
事件流的三个阶段
-
捕获阶段
<div class="father"> <div class="son">son盒子</div> </div> <script> // 如果addEventListener() 第三个参数是 true 那么在捕获阶段触发 // document -> html -> body -> father -> son var son = document.querySelector('.son'); // 给son注册单击事件,第3个参数为true son.addEventListener('click', function() { alert('son'); }, true); var father = document.querySelector('.father'); // 给father注册单击事件,第3个参数为true father.addEventListener('click', function() { alert('father'); }, true); // 给document注册单击事件,第3个参数为true document.addEventListener('click', function() { alert('document'); }, true) </script> 复制代码
-
目标阶段
-
冒泡阶段
<div class="father"> <div class="son">son盒子</div> </div> <script> // onclick 和 attachEvent(ie) 在冒泡阶段触发 // 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 // son -> father ->body -> html -> document var son = document.querySelector('.son'); // 给son注册单击事件 son.addEventListener('click', function() { alert('son'); }, false); // 给father注册单击事件 var father = document.querySelector('.father'); father.addEventListener('click', function() { alert('father'); }, false); // 给document注册单击事件,省略第3个参数 效果跟冒泡阶段一样 document.addEventListener('click', function() { alert('document'); }) </script> 复制代码
阻止默认行为
-
阻止默认行为 例如 表单的提交会跳转页面,a标签被单击后,默认会进行页面跳转
-
addEventListener() 注册事件 ,只有
一种
阻止默认行为的方式 ,e.preventDefault() -
传统的注册方式 onclick ,有三种注册方式(preventDefault(),returnValue,return false;)
<a href="http://www.baidu.com">百度</a> <script> // 2. 阻止默认行为 让链接不跳转 只有一种阻止默认行为的方式 var a = document.querySelector('a'); a.addEventListener('click', function(e) { e.preventDefault(); // dom 标准写法 }); // 3. 传统的注册方式 a.onclick = function(e) { // 普通浏览器 e.preventDefault(); 方法 e.preventDefault(); // 低版本浏览器 ie678 returnValue 属性 e.returnValue = false; // 我们可以利用return false 也能阻止默认行为 没有兼容性问题 return false; //特点是return后面的代码不会执行 } </script> 复制代码
阻止事件冒泡
事件冒泡本身的特性,会带来坏处,与好处 要怎么利用冒泡这一特性
-
e.stopPropagation( ) //有兼容性,只支持高版本的浏览器
-
e. cancelBubble=true; // 只支持 IE6-8, 低版本浏览器
<div class="father"> <div class="son">son儿子</div> </div> <script> var son = document.querySelector('.son'); // 给son注册单击事件 son.addEventListener('click', function(e) { alert('son'); e.stopPropagation(); // stop 停止 Propagation 传播 window.event.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡 }, false); var father = document.querySelector('.father'); // 给father注册单击事件 father.addEventListener('click', function() { alert('father'); }, false); // 给document注册单击事件 document.addEventListener('click', function() { alert('document'); }) </script> 复制代码
冒泡的应用—事件委托
- 作用:减少操作DOM的次数,提高程序的性能
- 动态新创建的子元素,也拥有事件。
将自己的事情委托给,别人处理
例如,不给子元素添加注册事件,而是给父元素添加注册事件,把子元素的处理代码放在父元素处理程序中……(子元素利用冒泡让父元素触发事件)
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';
})
</script>
复制代码
动画函数封装
核心原理
:js的动画是通过定时器(setInterval())不断移动盒子实现的
注意:js动画中元素需要 有定位
才能动
- 简单动画函数的封装
- 函数需要传递两个参数
移动距离
和动画对象
- 函数需要传递两个参数
如何给不同的动画元素指定不同的定时器?
- 核心原理:利用js是一门动态语言,可以很方便的给当前对象添加属性。
<script>
// var obj = {};
// obj.name = 'andy';
// 简单动画函数封装obj目标对象 target 目标位置
// 给不同的元素指定了不同的定时器
function animate(obj, target) {
// 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
// 解决方案就是 让我们元素只有一个定时器执行
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
if (obj.offsetLeft >= target) {
// 停止动画 本质是停止定时器
clearInterval(obj.timer);
}
obj.style.left = obj.offsetLeft + 1 + 'px';
}, 30);
}
var div = document.querySelector('div');
var span = document.querySelector('span');
var btn = document.querySelector('button');
// 调用函数
animate(div, 300);
btn.addEventListener('click', function() {
animate(span, 200);
})
</script>
复制代码
缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
思路:
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
- 核心算法: (目标值 – 现在的位置) / 10 做为每次移动的距离步长
- 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
- 注意步长值需要取整
动画函数多个目标值之间移动
可以让动画函数从 800 移动到 500。
当我们点击按钮时候,判断步长是正值还是负值
1.如果是正值,则步长往大了取整
2.如果是负值,则步长 向小了取整
动画函数添加回调函数
回调函数原理:将函数作为实参传递给另一个函数的形参中使用 。当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。
回调函数写的位置:定时器结束的位置。
动画完整版代码
function animate(obj, target, callback) {
// console.log(callback); callback = function() {} 调用的时候 callback()
// 先清除以前的定时器,只保留当前的一个定时器执行
clearInterval(obj.timer);
obj.timer = setInterval(function() {
// 步长值写到定时器的里面
// 把我们步长值改为整数 不要出现小数的问题
// var step = Math.ceil((target - obj.offsetLeft) / 10);
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();
}
// 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}, 15);
}
复制代码
节流阀
防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量var flag= true;
If(flag){flag = false; do something} 关闭水龙头
利用回调函数动画执行完毕, flag = true 打开水龙头
移动端触屏事件概述
移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件 touch(也称触摸事件),Android和 IOS 都有。
touch 对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。
常见的触屏事件如下:
click延时解决方案
-
移动端click事件会有300ms的延时,原因是移动端屏幕双击会缩放页面
-
解决方案:
-
禁用缩放。浏览器禁用默认的双击缩放行为并且去掉300ms的点击延迟
<meta name="viewport" content="user-scalable=no"> 复制代码
-
使用插件。fastclick 插件解决300ms 延迟。
-
GitHub官网地址: https://github.com/ftlabs/fast…
-
引入js插件文件
-
设置配置文件
if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); } 复制代码
-
-
-
本地存储
本地存储特性
- 数据存储在用户的浏览器中
- 设置、获取、清除方便、甚至页面刷新不丢失数据
- 存储容量大,sessionStorage约
5M
、localStorage约20M
- 只能存储字符串、可以通过
JSON.stringify()
将对象编码成字符串后存储 - 使用本地存储的数据,需要将本地存储的对象格式的字符串转化成对象使用
JSON.parse
window.sessionStorage
-
生命周期是
关闭浏览器窗口
-
以键值对的形式存储
-
可在同一个窗口(页面)下数据可共享
-
存储容量约 5M
-
存储数据
//以键值对的形式存储 sessionStorage.setItem(key,value) 复制代码
-
获取数据
//获取key对应的值 sessionStorage.getItem(key) 复制代码
-
删除数据
//删除key对应的值 sessionStorage.removeItem(key) 复制代码
-
清除数据:(所有都清除掉)
//删除所有数据 sessionStorage.clear() 复制代码
-
window.localStorage
- 生命周期为
永久性
,除非手动清除 - 以键值对的形式存储
- 在同一个浏览器 下的所有窗口(页面)都可共享数据
- 存储量 约20M
存储数据:
//以键值对的形式存储
localStorage.setItem(key, value)
复制代码
获取数据:
//获取key对应的值
localStorage.getItem(key)
复制代码
删除数据:
//删除key对应的值
localStorage.removeItem(key)
复制代码
清空数据:(所有都清除掉)
//清除所有的数据
localStorage.clear()
复制代码
本地存储的小结
sessionStorage | localStorage | |
---|---|---|
生命周期 | 关闭浏览器 |
永久性 ,除非手动清除 |
作用域 | 在同一页面下共享数据 | 在同一浏览器下共享数据 |
存储量 | 5M | 20M |
文件读取
1. 首先需要一个上传控件用来获取上传的文件
2. 点击上传按钮的时候通过onchange
3. 通过files获取上传文件
4. 创建读取器 new FileReader();
5. 读取器中的方法,属性及事件
方法:
readAsText(file) 读取成文本形式
readAsDataURL(file) 读取成文件路径形式
属性:
reader.result 获取读取结果
事件: onload 当读取操作完成后
备注:获取读取结果的时候,一定要在读取操作结束后执行(在onload事件中完成)
复制代码
<body>
<img src="" alt="">
<input type="file">
<script type="text/javascript">
var img = document.querySelector("img");
var input = document.querySelector("input");
input.onchange = function(e) {
//获取读取文件
var file = this.files[0];
//创建读取器
var reader = new FileReader();
//读取文件
reader.readAsDataURL(file);
//当文件读取成功后
reader.onload = function() {
//判断文件后缀名是否合法
var file_name = file.name;
var f_name = file_name.substring(file_name.lastIndexOf('.')) ;
var f_ary = ['.jpg', '.png', '.gif', '.ico'];
var flag = true;
for(var i = 0; i < f_ary.length; i++) {
if (f_name == f_ary[i]) {
img.src = this.result;
flag = true;
break;
}else {
flag = false;
continue;
}
}
if (flag) {
alert('读取成功!');
}else {
alert('文件格式错误!');
}
}
}
</script>
</body>
复制代码
原生js 之 (DOM操作) >-<
「点赞、收藏和评论」
❤️关注+点赞+收藏+评论+转发❤️,鼓励笔者创作更好的文章,谢谢?大家。