事件语法-DOM

事件语法-DOM

1、事件绑定与事件解绑

1.1绑定

1.1.1行内绑定方式

    <div class="rwx" onclick="javaScript:alert(666)"></div>
    <div class="rwx" onclick="fn1()"></div>
    <script>
        function fn1() {
            console.log(111);
        }
   <input type="text" onChange="alert(this.value)">
    </script>

1.1.2元素属性绑定方式

  • 兼容性很好,但是一个元素的同一个时间上只能绑定一个处理程序
    <div class="rwx">点我</div>
    <script>
        var rwx2 = document.querySelector(".rwx")
        rwx2.onclick = function () {
            console.log(222);
        }
    </script>

1.1.3同元素多处理程序绑定方式1

 <div class="rwx">点我</div>
    <script>
        var rwx3 = document.querySelector(".rwx")
        function fn() {
            console.log(333);
        }
        function fn1() {
            console.log(444);
        }
        rwx3.addEventListener("click", fn)
        rwx3.addEventListener("click", fn1)
    </script>

1.1.4同元素多处理程序绑定方式2

obj.attachEvent('on'+type,fn);
//IE专有( ie11例外),一个事件同样可以绑定多个处理程序
// <meta http-equiv="X-UA-Compatible" content="IE=10" />,解决 IE11向后兼容 IE10的问题

1.1.5解决注册事件兼容性

 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;
 } 

1.2解绑

  1. ele.οnclick=false/‘’/null;
  2. ele.removeEventListener(type,fn,false);
  3. ele.detachEvent(“on”+type,fn);
    ps:2,3若绑定的是匿名函数,则永远无法解除
    <div id="xiake" onclick="console.log('下课1')">
		下课
	</div>
		<script>
			//1.行内和属性绑定的事件 解绑:xiake.οnclick=null
			xiake.onclick=function(){
				xiake.onclick=null;
				console.log(6666)
			}
			//2.移除对应的元素的对应的监听程序
			function fn1 () {
				console.log("真下课1")
			}
			function fn2 () {
				console.log("真下课2")
			}
			function fn3 () {
				console.log("真下课3")
			}
		   xiake.addEventListener("click",fn1)
		   xiake.addEventListener("click",fn2)
		   xiake.addEventListener("click",fn3)		   
		   xiake.removeEventListener("click",fn1)
			// 总结:
			// box.οnclick=函数   box.οnclick=null
			// box.addEventListener  box.removeEventListener
		</script>

1.2.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;
 } 

1.2.2页面HTML滚动的距离兼容写法

let pY = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop

2、事件类型

2.1鼠标事件

1、click、 mousedown、mousemove、mouseup、dblclick、 contextmenu、mouseover、mouseout、mouseenter(html5标准)、mouseleave(html5标准)

    <div class='box'>
        <div class="son">
        </div>
    </div>
    <script>
        //鼠标事件
        //11 click
        var box = document.querySelector(".box")
        box.addEventListener("click", () => {
            console.log("鼠标按下和松开时,鼠标指针都在被选元素内部区域");
        })
        //22 dblclick
        var box = document.querySelector(".box")
        box.addEventListener("dblclick", () => {
            console.log("鼠标按下和松开的时间间隔不能太长,鼠标指针都在被选元素内部区域");
        })
        //33 mousedown
        var box = document.querySelector(".box")
        box.addEventListener("mousedown", () => {
            console.log("鼠标在被选元素内按下");
        })
        //44 mouseup
        var box = document.querySelector(".box")
        box.addEventListener("mouseup", () => {
            console.log("鼠标在被选元素内松开");
        })
        //55 mouseout
        var box = document.querySelector(".box")
        box.addEventListener("mouseout", () => {
            console.log("鼠标从被选元素出去");
            //父元素是被选元素,父到子,子到父 从父移出去都会触发
        })
        //66 mouseover
        var box = document.querySelector(".box")
        box.addEventListener("mouseover", () => {
            console.log("鼠标进入被选元素");
            //父元素是被选元素,进入父,父到子,子到父都会触发
        })
        //77 mouseleave
        var box = document.querySelector(".box")
        box.addEventListener("mouseleave", () => {
            console.log("鼠标从被选元素出去");
            //父元素是被选元素 只有移除父才会触发
        })
        //88 mouseenter
        var box = document.querySelector(".box")
        box.addEventListener("mouseenter", () => {
            console.log("鼠标从被选元素进去");
            父元素是被选元素 只有进入父才会触发
        })
        //99 scroll
        var box = document.querySelector(".box")
        box.addEventListener("scroll", () => {
            console.log("元素自己的滚动条 滚动就触发:单位时间内滚动条的位置发生变化");
        })
    </script>

2.2键盘事件

keydown、keyup、keypress

    <input type="text" id="box2">
    <script>
        // 键盘事件
        //11 keydown
        var box2 = document.querySelector("#box2")
        box2.addEventListener("keydown", function () {
            console.log("输入框的键盘按下就会触发")
        })
        //22 keyup
        var box2 = document.querySelector("#box2")
        box2.addEventListener("keyup", function () {
            console.log("输入框的键盘松开才会触发")
        })
        //33 keypress
        var box2 = document.querySelector("#box2")
        box2.addEventListener("keypress", function () {
            console.log("输入框的键盘按下就会触发")
            // 某个键盘按键被按下时触发,但是它不识别功能键和中文打字,比如 ctrl shift 箭头等
        })
    </script>

2.3输入框操作事件


    <input type="text" id="box2">
    <script>
        // 输入框操作事件
        //11 input
        var box2 = document.querySelector("#box2")
        box2.addEventListener("input", function () {
            console.log("输入框在输入字符就触发")
        })
        //22 change
        var box2 = document.querySelector("#box2")
        box2.addEventListener("change", function () {
            console.log("输入框失焦并且value改变")
        })
        //33 focus
        var box2 = document.querySelector("#box2")
        box2.addEventListener("focus", function () {
            console.log("输入框获取焦时触发")
        })
        //44 blur
        var box2 = document.querySelector("#box2")
        box2.addEventListener("blur", function () {
            console.log("输入框失焦时触发")
        })
    </script>

3、事件对象

3.1事件对象

事件对象上存储着事件发生时的相关信息(例如:event.which)

	a) 事件处理函数形参ev(event),W3C制定的标准,IE9以下不行
	b) 全局对象 window.event用于IE9以下
	// 兼容性写法 var event= ev|| window.event

3.2事件源对象

event.target	火狐只有这个
event.srcElement	IE6/78只有这个
这两个chrome都有	
兼容性写法 var ele=event.target|| event.srcElement

3.3鼠标事件触发时:

altKey 鼠标事件发生时,是否按下alt键,返回一个布尔
ctrlKey 鼠标事件发生时,是否按下ctrl键,返回一个布尔
metaKey  鼠标事件发生时,是否按下windows/commond键,返回一个布尔
shiftKey 鼠标事件发生时,是否按下shift键,返回一个布尔
pageX  鼠标点击的  X 坐标;(包含body隐藏的)
pageY  鼠标点击的  Y 坐标;(包含body隐藏的)
clientX clientY返回鼠标位置相对于浏览器窗口左上角的坐标,单位为像素(不包括body隐藏的)
screenX screenY返回鼠标位置相对于屏幕左上角的坐标,单位为像素
movementX,movementY返回一个位移值,单位为像素,表示当前位置与上一个mousemove事件之间的距离
offsetX/offsetY 相对于元素自己的x/y 跟它是否是定位的元素无关

3.4键盘事件触发时

charCode/keyCode  键码值  key  键码
37左
38上
39右
40下 
13enter

4、元素盒子模型

el.offsetWidth:本身宽度+边框线+左右内边距;
el.offsetHeight:本身高度+边框线+上下内边距;
el.offsetTop:相对第一个父级节点有定位属性的上偏移量;
el.offsetLeft:相对有定位属性的父节点左偏移量;
el.clientWidth:本身的宽度+左右内边距;
el.clientHeight:本身的高度+上下内边距;
el.clientTop:上边框线的宽度
el.clientLeft:左边框线的宽度
el.scrollWidth:盒子的实际宽度(包括滚动条不可见部分,不包括边线)
el.scrollHeight:盒子的实际高度(包括滚动条不可见部分,不包括边线)
el.scrollTop:滚动条向下滚动的距离;
el.scrollLeft:滚动条向右滚动的距离;
window.innerHeight:浏览器窗口可见区域高度;
window.innerWidth:浏览器窗口可见区域宽度;
在这里插入图片描述
详解:
clientTop:元素上边框的厚度,当没有指定边框厚底时,一般为0。

scrollTop:位于对象最顶端和窗口中可见内容的最顶端之间的距离,简单地说就是滚动后被隐藏的高度。

offsetTop:获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

clientHeight:内容可视区域的高度,也就是说页面浏览器中可以看到内容的这个区域的高度,一般是最后一个工具条以下到状态栏以上的这个区域,与页面内容无关。

scrollHeight:IE、Opera 认为 scrollHeight 是网页内容实际高度,可以小于 clientHeight。FF 认为 scrollHeight 是网页内容高度,不过最小值是 clientHeight。

offsetHeight:获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)的高度。IE、Opera 认为 offsetHeight = clientHeight + 滚动条 + 边框。FF 认为 offsetHeight 是网页内容实际高度,可以小于 clientHeight。offsetHeight在新版本的FF和IE中是一样的,表示网页的高度,与滚动条无关,chrome中不包括滚动条。

clientX、clientY:相对于浏览器窗口可视区域的X,Y坐标(窗口坐标),可视区域不包括工具栏和滚动条。IE事件和标准事件都定义了这2个属性。

pageX、pageY:类似于event.clientX、event.clientY,但它们使用的是文档坐标而非窗口坐标。这2个属性不是标准属性,但得到了广泛支持。IE事件中没有这2个属性。

offsetX、offsetY:相对于事件源元素(target或srcElement)的X,Y坐标,只有IE事件有这2个属性,标准事件没有对应的属性。

screenX、screenY:相对于用户显示器屏幕左上角的X,Y坐标。标准事件和IE事件都定义了这2个属性

5、事件链(捕获目标冒泡)

在这里插入图片描述
1.事件的三个阶段:

  • 先捕获,后目标,再冒泡,只能有一个阶段触发程序执行,比如捕获阶段触发了到了冒泡阶段就不再触发
  • 事件经过所有元素都没有被处理,这个事件消失
  • 事件传递的过程 只跟文档树的结构有关系 跟界面显示的层叠效果没有任何关系

事件捕获:结构上(非视觉上)嵌套关系的元素,会存在事件捕获的功能,即同一事件,自父元素捕获至子元素(事件源元素)。(自顶向下)

事件冒泡:结构上(非视觉上)嵌套关系的元素,会存在事件冒泡的功能,即同一事件,自子元素冒泡向父元素。(自底向上)

2.onclick 和 attachEvent只能得到冒泡阶段

3.addEventListener(type,listener[,useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false (不写默认就是false),表示在事件冒泡阶段调用事件处理程序

4.整个事件处理过程,会有个event事件对象在整个事件过程传播(W3C标准,ie8及其以下没有)
5.ie8以下不支持addEventListener
6.focus,blur,change,submit,reset,select等事件不冒泡

5.1捕获阶段

  • 两个盒子嵌套,一个父盒子一个子盒子,我们的需求是当点击父盒子时弹出 father ,当点击子盒子时弹出 son
<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // dom 事件流 三个阶段
        // 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
        // 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
        // 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段  document -> html -> body -> father -> son
        var son = document.querySelector('.son');
        son.addEventListener('click', function() {
             alert('son');
        }, true);
        var father = document.querySelector('.father');
        father.addEventListener('click', function() {
            alert('father');
        }, true);
    </script>
</body>

  • addEventListener绑定事件,如果把第三个参数设置为true,则在捕捉的时候执行事件
  • document -> html -> body -> father -> son
  • 但是因为DOM流的影响,我们点击子盒子,会先弹出 father,之后再弹出 son
  • 先看 document 的事件,没有;再看 html 的事件,没有;再看 body 的事件,没有;再看 father 的事件,有就先执行;再看 son 的事件,再执行。

5.2冒泡阶段

  • son -> father ->body -> html -> document
<body>
    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
		// 4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段  son -> father ->body -> html -> document
        var son = document.querySelector('.son');
        son.addEventListener('click', function() {
            alert('son');
        }, false);
        var father = document.querySelector('.father');
        father.addEventListener('click', function() {
            alert('father');
        }, false);
        document.addEventListener('click', function() {
            alert('document');
        })
    </script>
</body>

  • 我们点击子盒子,会弹出 son、father、document

5.3阻止冒泡事件和默认事件

  • 事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点
  • 标准写法
e.stopPropagation();
  • 非标准写法,ie8及ie8以下可用
e.cancelBubble = true;
<body>
    <div class="father">
        <div class="son">son儿子</div>
    </div>
    <script>
        // 常见事件对象的属性和方法
        // 阻止冒泡  dom 推荐的标准 stopPropagation() 
        var son = document.querySelector('.son');
        son.addEventListener('click', function(e) {
            alert('son');
            e.stopPropagation(); // stop 停止  Propagation 传播
            e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
        }, false);

        var father = document.querySelector('.father');
        father.addEventListener('click', function() {
            alert('father');
        }, false);
        document.addEventListener('click', function() {
            alert('document');
        })
    </script>
</body>

点击son就只alertson,不再alert father和document

5.4解决阻止事件冒泡的兼容性

if(e && e.stopPropagation){
      e.stopPropagation();
  }else{
      window.event.cancelBubble = true;
  }

5.5事件对象阻止默认行为

<body>
    <div>123</div>
    <a href="http://www.baidu.com">百度</a>
    <form action="http://www.baidu.com">
        <input type="submit" value="提交" name="sub">
    </form>
    <script>
        // 常见事件对象的属性和方法
        // 1. 返回事件类型
        var div = document.querySelector('div');
        div.addEventListener('click', fn);
        div.addEventListener('mouseover', fn);
        div.addEventListener('mouseout', fn);

        function fn(e) {
            console.log(e.type);

        }
        // 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;
            // 我们可以利用return false 也能阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
            return false;
            alert(11);
        }
    </script>
</body>

6、e.target 与 this

  • this是事件绑定的元素,这个函数的调用者(绑定这个事件的元素)
  • e.target是事件触发的元素,例如是点击的那个元素
<body>
    <div>123</div>
    <ul>
        <li>abc</li>
        <li>abc</li>
        <li>abc</li>
    </ul>
    <script>
        // 常见事件对象的属性和方法
        // 1. e.target 返回的是触发事件的对象(元素)  this 返回的是绑定事件的对象(元素)
        // 区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
        var div = document.querySelector('div');
        div.addEventListener('click', function(e) {
            console.log(e.target);
            console.log(this);

        })
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
                // 我们给ul 绑定了事件  那么this 就指向ul  
                console.log(this);
                console.log(e.currentTarget);

                // e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
                console.log(e.target);

            })
            // 了解兼容性
            // div.onclick = function(e) {
            //     e = e || window.event;
            //     var target = e.target || e.srcElement;
            //     console.log(target);

        // }
        // 2. 了解 跟 this 有个非常相似的属性 currentTarget  ie678不认识
    </script>
</body>

7、事件代理

7.1事件代理的原理:

不是给每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒
泡原理影响设置每个子节点

7.2事件代理案例 ul-li

案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。

<body>
    <ul>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
    </ul>
    <script>
        // 事件代理的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            // alert('知否知否,点我应有弹框在手!');
            // e.target 这个可以得到我们点击的对象
            e.target.style.backgroundColor = 'pink';
            // 点了谁,就让谁的style里面的backgroundColor颜色变为pink
        })
    </script>
</body>

8、页面渲染流程

8.1页面渲染流程

在这里插入图片描述

8.1.1页面呈现过程

不同的浏览器略微会有些不同。但基本上都是类似的

①.浏览器把html代码解析成1个Dom树,html中的每个tag都是Dom树中的1个节点,根节
点就是我们常用的document对象。dom树就是html结构,里面包含了所有的html tag,包
括用JS添加的元素。

②浏览器把所有样式(主要包括css和浏览器自带的样式设置)解析成样式结构体,在解析的
过程中会去掉浏览器不能识别的样式。

③dom tree和样式结构体结合后构建呈现树(render tree),render tree有点类似于dom tree,
但有区别,render tree能识别样式,render tree中每个node都有自己的style,而且render 
tree不包含隐藏的节点(比如display:none的节点,还有head节点),因为这些节点不会用于
呈现,而且不会影响呈现的,所以就不会包含到render tree中。但是visibility:hidden隐藏的
元素还是会包含到render tree中的,因为visibility:hidden 会影响布局,会占有位置。

④一旦render tree构建完毕后,浏览器就根据render tree来绘制页面。

8.1.2回流与重绘

① 当render tree中因为元素的数量,尺寸,布局,隐藏等改变而需要重新构建。这就称为回
流或者回档(其实我觉得叫重新布局更简单明了些)。每个页面至少需要一次回流,就是在
页面第一次加载的时候。
②当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而
不会影响布局的,比如background-color。则就叫称为重绘。
③(面试,选择题,问答题就答上面)从上面可以看出,回流必将引起重绘,而重绘不一定会引
起回流。
④重绘与回流操作的注意点
//重绘与回流操作的次数越多,计算机的性能消耗越大
进行dom操作的时候,就要考虑
 重绘 和 回流/回档
重绘 就是按照文档树的结构 重新绘制页面 渲染
回流/回档 就是页面的元素排版布局数量和节点在树中位置等发生了改变 就是回流
回流必然引起重绘  但是重绘不一定引起回流

8.1.3常见的回流和重绘操作

重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘
回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/状态状态)发生改变时,
产生重绘回流
回流必将引起重绘,而重绘不一定会引起回流
任何对render tree中元素的操作都会引起回流或者重绘
①添加、删除元素(回流+重绘)
② 隐藏元素,display:none(回流+重绘),visibility:hidden(只重绘,不回流)
③ 移动元素,比如改变top,left(jquery的animate方法就是,改变top,left不一定会影响回流),
或者移动元素到另外1个父元素中。(重绘+回流)
④ 对style的操作(对不同的属性操作,影响不一样)
⑤ 还有一种是用户的操作,比如改变浏览器大小,改变浏览器的字体大小等(回流+重绘)

function  change1 () {
    var box=document.querySelector(".box")
	// box.innerHTML="6666"//回档
	// box.style.visibility= "hidden";//重绘不回流
	// box.style.display= "none";//回流
			         }			

8.2避免高频重绘案例

  • 添加1万个格子到页面上 每个格子显示时间(ms)
    不推荐方法:
	        let tb=document.querySelector(".box")
			for(let i=0;i<100;i++){
				let tr=document.createElement("tr")
				tb.appendChild(tr)
				for(let j=0;j<100;j++){
					let dt=new Date().getTime()
					let td=document.createElement("td")
					td.innerHTML=dt
					tr.appendChild(td)
				}
			}
			// 回档了1万零100次

推荐方法

    创建一个元素来承载即将渲染的元素
	let tb = document.querySelector("#box")
		let fra1 = document.createDocumentFragment() //它在内存中还不在文档中
		for (let i = 0; i < 100; i++) {
			let tr = document.createElement("tr")
			fra1.appendChild(tr)
			for (let j = 0; j < 100; j++) {
				let dt = new Date().getTime()
				let td = document.createElement("td")
				td.innerHTML = dt
				tr.appendChild(td)
			}
		}
		tb.appendChild(fra1) //它自己不会添加到文档树中用于渲染 但是它的子代元素都会添加进去
		// 回档了1次

9、获取元素节点和元素样式属性及修改

9.1不能获取script脚本后的元素节点

解决方案一:

  • 当页面加载完成的事件触发 再去执行获取节点的方式
  • window.onload
	    function fn(){
				var box2=document.querySelector(".box2")
				console.log(box2)
			}
			window.onload=fn

解决方案二

script-- defer  async  修改src如何加载外部js资源的异步属性
代码写到js文件中:

在这里插入图片描述

9.2获取元素样式属性及修改

9.2.1用element.style获取

  1. 原生js操作样式只能操作元素的行内样式
  2. 非行内样式只能获取不能设置。
  3. 用.style获取width(行内样式)可以,但是获取height等其他样式(非行内样式)时结果为空
box.style.width = "200px"
设置的是行内样式而不是非行内样式

9.2.2window.getComputedStyle() 方法的使用

获取:

console.log(window.getComputedStyle(btn));//CSSStyleDeclaration
console.log(window.getComputedStyle(btn).backgroundColor);

设置会报错

window.getComputedStyle(btn).width = "200px";

在这里插入图片描述

box.style.width = parseInt(box.style.width) * 2 + 'px'//不会生效
box.style.width = parseInt(window.getComputedStyle(box).width) * 2 + 'px'
// 会生效

9.2.3getComputedStyle() 和 style 的异同

getComputedStyle 和 element.style 的相同点就是二者返回的都是
 CSSStyleDeclaration 对象,取相应属性值得时候都是采用的 CSS 驼峰式写法,均需要注
意 float 属性。
而不同点就是:
element.style 读取的只是元素的内联样式,即写在元素的 style 属性上的样式;而 
getComputedStyle 读取的样式是最终样式,包括了内联样式、嵌入样式和外部样式。
element.style 既支持读也支持写,我们通过 element.style 即可改写元素的样式。而 
getComputedStyle 仅支持读并不支持写入。我们可以通过使用 getComputedStyle 读取样
式,通过 element.style 修改样式。
box.style.width = parseInt(window.getComputedStyle(box).width) * 2 + 'px'

10、防抖与节流

高频率触发的业务: 如抽奖 登录 动画 网络加载等等需要做防抖或者是节流操作

10.1防抖

10.1.1防抖思想

  • 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
  • 电梯第一个人进来后,15秒后准时运送一次,这是节流。
  • 电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
  • 防抖就是当持续触发事件时,会等到停止后一段时间才开始执行。为什么需要这样呢?比如,要是我们点击一个按键,我们是不是只需要提交一次,要是我们疯狂点击,是不是就会疯狂触发。还有输入搜索,我们是不是应该输入结束才开始调用接口搜索,而不是每输入一个字就调用一次。使用防抖函数后,就使得只会触发一次,避免了无意义的触发

10.1.2防抖方案

         document.onclick = fangdou(function(e) {
				console.log(6666)
			}, 1000)
			function fangdou(cb, delay) {
				var timer = null;
				return function() {
					//return这个函数频率很高  想办法让cb()执行慢下来:防抖
					clearTimeout(timer)
					timer = setTimeout(function() {
						cb()
					}, delay)
				}
			}

10.1.3防抖方案优化


		document.onclick = fangdou2(function (e) {
			console.log(6666, e, this)
		}, 1000)
		function fangdou2(cb, delay) {
			var timer = null;
			return function () {
				//return这个函数频率很高  想办法让cb()执行慢下来:防抖
				let arg = arguments
				clearTimeout(timer)
				timer = setTimeout(() => {
					cb.apply(this, arg)
				}, delay)
			}
		}

10.2节流

10.2.1节流思想

  • 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
  • 电梯第一个人进来后,15秒后准时运送一次,这是节流。
  • 电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
  • 节流是持续触发事件,会每隔一段时间,才执行执行一次,比如在DOM元素的拖拽功能中,射击游戏,计算鼠标移动距离中。当我们计算鼠标的移动距离,要是没有使用节流函数,那么每移动1px,就会调用计算。我们可想而知,当我们轻轻滑动。就会调用触发无数次了,会给服务器带来极大的压力。但我们使用后,比如设置间隔时间,持续触发那么他就会每隔这个时间段触发一次。大大减少服务端压力。

10.2.2节流方案

     document.onmousemove=jieliu(function(){console.log(666)},20)
			function jieliu(cb,daley){
				var timer=null;
				return function(){
					// console.log(66666,timer)
					if(!timer){
					  timer=setTimeout(()=>{
						  cb();
						  timer=null
					  },daley)
					}
				}
			}

10.2.3节流方案优化

	  function jieliu2(cb, daley) {
			var timer = null;
			return function () {
				// console.log(66666,timer)
				// this是事件函数的this
				let arg = arguments
				if (!timer) {
					timer = setTimeout(() => {
						cb.apply(this, arg);//本来是window但是希望					  
						timer = null
					}, daley)
				}
			}
		}

11、缓动动画

11.1定义

缓动动画:  匀速改变元素的样式  就是匀速动画   非匀速的改变元素css样式的动画效果就
是缓动动画
设定值=当前+(目标值-当前)*百分比
目标是让div的高度为800   div.style.heiht=当前h+(800-当前w)*0.5

11.2缓动案例

11.2.1下拉菜单缓动动画

<style>
    .djxl {
        width: 200px;
        height: 40px;
        background-color: #007ACC;
        border-radius: 5px;
    }

    .caidan {
        width: 150px;
        height: 0px;
        background-color: #cc0047;
        border-radius: 5px;
        overflow: hidden;
        position: absolute;
        left: 32px;
    }

    .box {
        text-align: center;
        height: 30px;
        line-height: 30px;
        margin: 2px;
        background-color: bisque;
    }
</style>

<body>
    <button class="djxl">点击出现菜单</button>
    <div class="caidan">
        <div class="box">1</div>
        <div class="box">2</div>
        <div class="box">3</div>
        <div class="box">4</div>
        <div class="box">5</div>
    </div>
    <script>
        // 设定值=当前值+(目标值-当前值)*百分比
        window.onload = function () {
            var djxl = document.querySelector(".djxl")
            var flag = true
            var timer;
            var result;
            djxl.addEventListener("click", function () {
                var caidan = document.querySelector(".caidan")
                clearInterval(timer)
                if (flag = !flag) {
                    result = 0
                } else {
                    result = 166
                }
                timer = setInterval(() => {
                    var h = window.getComputedStyle(caidan).height
                    caidan.style.height = parseInt(h) + (result - parseInt(h)) * 0.3 + "px"
                }, 20)

            })
        }
    </script>

11.2.2信息滑入缓动动画

<style>
    .dahezi {
        position: relative;
        width: 200px;
        height: 200px;
        overflow: hidden;
    }

    .huaruk {
        width: 200px;
        height: 60px;
        line-height: 60px;
        text-align: center;
        position: absolute;
        background-color: rgba(0, 122, 204, 0.5);
        top: 200px;
    }
</style>

<body>
    <div class="dahezi">
        <img src="./tupian/images (2).jpg" alt="">
        <div class="huaruk">大帅哥</div>
    </div>
    <script>
        // 设定值=当前值+(目标值-当前值)*百分比
        var dahezi = document.querySelector(".dahezi")
        var timer;
        var flag = true;

        dahezi.addEventListener("mouseenter", () => {
            var huaruk = document.querySelector(".huaruk")
            var mubiaozhi = 140
            clearInterval(timer)
            timer = setInterval(() => {
                huaruk.style.top = huaruk.offsetTop + (mubiaozhi - huaruk.offsetTop) * 0.4 + "px"
            }, 20)
        })
        dahezi.addEventListener("mouseleave", () => {
            var mubiaozhi = 200
            clearInterval(timer)
            var huaruk = document.querySelector(".huaruk")
            timer = setInterval(() => {
                huaruk.style.top = huaruk.offsetTop + (mubiaozhi - huaruk.offsetTop) * 0.4 + "px"
            }, 20)
        })
    </script>

11.2.2缓动模态窗口+拖拽效果

<style>
    .dahezi {
        position: relative;
        width: 200px;
        height: 200px;
        overflow: hidden;
    }

    .huaruk {
        width: 200px;
        height: 60px;
        line-height: 60px;
        text-align: center;
        position: absolute;
        background-color: rgba(0, 122, 204, 0.5);
        top: 200px;
    }
</style>

<body>
    <div class="dahezi">
        <img src="./tupian/images (2).jpg" alt="">
        <div class="huaruk">大帅哥</div>
    </div>
    <script>
        // 设定值=当前值+(目标值-当前值)*百分比
        var dahezi = document.querySelector(".dahezi")
        var timer;
        var flag = true;

        dahezi.addEventListener("mouseenter", () => {
            var huaruk = document.querySelector(".huaruk")
            var mubiaozhi = 140
            clearInterval(timer)
            timer = setInterval(() => {
                huaruk.style.top = huaruk.offsetTop + (mubiaozhi - huaruk.offsetTop) * 0.4 + "px"
            }, 20)
        })
        dahezi.addEventListener("mouseleave", () => {
            var mubiaozhi = 200
            clearInterval(timer)
            var huaruk = document.querySelector(".huaruk")
            timer = setInterval(() => {
                huaruk.style.top = huaruk.offsetTop + (mubiaozhi - huaruk.offsetTop) * 0.4 + "px"
            }, 20)
        })
    </script>

12、预加载与懒加载

  • 预加载: 提前加载资源–同源加载的优化
  • 懒加载: 先不加载 等条件成立时再加载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值