[JS Interaction] Events and Element Operations

1. Event and element related properties

An event is a certain action performed by the user or the browser itself, such as: click, load and mouseover, etc., are the names of the event;

Native JavaScipt Case Collection
JavaScript + DOM Basic
JavaScript Basic to Advanced
Canvas Game Development

1.1 Window or element related events:

event describe
onload Event fired when the page or image has finished loading
onresize Event fired when the window changes
onscroll Event triggered when the window scroll bar is scrolled

1.2 Element related attributes

Attributes describe
element.clientHeight Returns the visual height of the content on the page (not including borders, margins or scrollbars)
element.clientWidth Returns the visible width of the content on the page (not including borders, margins or scrollbars)
element.offsetHeight Returns the height of any element including borders and padding, but not margins
element.offsetWidth Returns the width of the element, including borders and padding, but not margins
element.scrollTop The distance by which the top of the page or element is rolled away
element.scrollLeft The distance the page or element is scrolled to the left
element.offsetLeft An offset container that returns the relative horizontal offset position of the current element
element.offsetTop An offset container that returns the relative vertical offset position of the current element
element.offsetParent Returns the offset container of the element

1.4 Mouse Events

event describe
onclick Event triggered by mouse click
ondblclick Event triggered by mouse double click
context menu Event triggered by right mouse button
onmouseover event triggered by mouse over
onmoseout event triggered by mouse leave
onmouseenter Event triggered when the mouse pointer moves over the current element
onmouseleave Event triggered when the mouse pointer moves out of the current element
onmousedown Event triggered when the mouse is pressed
onmouseup Event triggered when the mouse is released
onmousemove mouse move event

Note :

  1. onmouseenter and onmouseleave do not support event bubbling; while onmouseout and onmouseover support event bubbling
  2. The mouseenter event is only triggered when the mouse pointer enters the selected element, and the mouseover event is also triggered when the mouse pointer enters any child element;
  3. The mouseleave event is only triggered when the mouse pointer leaves the selected element, and the mouseout event is also triggered when the mouse pointer leaves any child elements
  4. The order of execution of onclick, onmousedown, onmouseup onmousedown --> onmouseup --> onclick

1.6 Keyboard Events

event describe
onkeydown Event triggered when keyboard key is pressed
onkeyup The event triggered when the keyboard key is released
onkeypress Event fired when keyboard keys (numbers and letters) are pressed and released

Note :

  1. The sequence of three keyboard events triggered onkeydown --> onkeypress --> onkeyup
  2. keypress is mainly used to receive ANSI characters such as letters and numbers. Arrow keys and function keys cannot be triggered, such as: Alt, Ctrl, Shift, Esc and other function keys
  3. The keydown and keyup events handle any keystrokes not recognized by keypress. Such as: function keys (F1-F12), edit keys, navigation keys, and combinations of any of these keys and keyboard shift keys

1.8 Form Events

event describe
onfocus Get the focus of the form control
onblur lose focus of form control
oninput Get the event that the user is typing in the control
onchange get form change event
onselect The event that the content in the form is selected
onsubmit form submit event
onreset Form information reset event

注:onsubmit、onreset 事件由 form 元素驱动

二、事件对象

事件对象是用来记录事件发生时相关信息的对象。如: 鼠标事件发生后,获取鼠标的横坐标 event.clientX ( clientX用来获取鼠标距离浏览器左边的距离 ) 。

事件对象只有在事件被触发时才会产生,并且只能在事件处理函数内部访问;当事件处理函数运行结束后,事件对象就被销毁。

对于不同的浏览器,事件对象获取的方式不同:

  • IE8及以下浏览器版本中,只能直接从全局中获取事件对象 window.event

  • 火狐(Firefox,简称FF)低版本浏览器中,只能通过事件传递的方式,在事件函数中传递事件对象

  • 所有高版本浏览器两者都兼容

获取事件对象的兼容性写法:

element["on" + 事件类型] = function(e){
	var ev = e || window.event;
}

事件对象通用属性:

属性 描述
type 返回事件的类型

鼠标事件对象相关属性:

属性 描述
clientX 返回当事件被触发时,鼠标指针的水平坐标。
clientY 返回当事件被触发时,鼠标指针的垂直坐标
screenX 返回当某个事件被触发时,鼠标指针的水平坐标。
screenY 返回当某个事件被触发时,鼠标指针的垂直坐标。
pageX 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角x轴的坐标; 随滚动条滚动而改变
pageY 鼠标相对于浏览器(这里说的是浏览器的有效区域)左上角y轴的坐标; 随滚动条滚动而改变
offsetX 鼠标相对于事件源左上角X轴的坐标
offsetY 鼠标相对于事件源左上角Y轴的坐标

键盘事件对象相关属性:

属性 描述
key 在按下按键时返回按键的标识符
keyCode 返回onkeypress事件触发的键的值的字符代码,或者 onkeydown 或 onkeyup 事件的键的代码
which 返回onkeypress事件触发的键的值的字符代码,或者 onkeydown 或 onkeyup 事件的键的代码

注:onkeypress 事件触发的键的值的字符代码(表示ASCII字符的数字),或者 onkeydownonkeyup 事件的键的代码(表示键盘上真实键的数字)。

三、事件处理程序

事件处理程序指的是当HTML中发生某些事件时所调用的方法。

事件处理程序分为以下几种:

  1. HTML事件处理程序

    直接在html元素中使用"on"+事件类型实现,如:onclick ,使得html元素具有能够执行js 代码的特性

    这种事件处理程序有两个缺点:

    • 存在一个时差的问题,如果将 script 程序写在页面的最底部,而用户又在 html 元素一出现就触发相应的事件,这个时候事件处理程序有可能尚不具备执行条件(即:script 程序未加载,dom 从上往下依次解析html 文件)
    • html 代码与 JS 代码紧密耦合,这样在维护或修改时需要修改两个地方。所以建议摒弃 html 事件处理程序,进而使用 JS 指定事件处理程序
  2. DOM0级事件处理程序

    通过 JS 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种操作简单且具有跨浏览器的优势。

    • 使用DOM0级方法指定的事件处理程序被认为是元素的方法;因此这时候的事件处理程序是在元素的作用域中运行;即:程序中的this引用的是当前元素
    • 这种方式添加的事件处理程序会在事件流的冒泡阶段被处理

    添加方式:element[‘on’ + 事件类型] = function(){}

    移除方式:element[‘on’ + 事件类型] = null

  3. DOM2级事件处理程序

    添加方式:element.addEventListener(type,handler,boolean)

    移除方式: element.removeEventListener(type,handler,boolean)

    注意:移除时三个对应参数事件类型、事件函数、事件冒泡或捕获阶段要一一对应,匿名函数没有办法被移除。

    IE8及以下浏览器报错: 对象不支持 “addEventListener” 属性或方法;

    可以给同一个元素定义多个同种类型的事件函数;

    第三个参数默认是false,事件冒泡流阶段。多个同种类型的事件,按照渲染顺序,依次执行。

  4. IE事件处理程序

    添加方式:element.attachEvent(‘on’+事件类型,事件函数)

    移除方式:element.detachEvent(‘on’+事件类型,事件函数)

    只能在IE10及以下浏览器版本中使用,其它浏览器报错:btn.attachEvent is not a function

    也可以添加多个同种类型的事件,执行顺序按照渲染顺序逆向执行。

    与DOM0级方法的区别在于事件处理程序的作用域不同:DOM0级是在其所属元素的作用域内运行,而IE事件处理程序是在全局作用域运行,因此this等于window。

    与DOM2级方法一样,可以为同一个按钮添加两个不同事件处理程序,但是IE事件处理程序的执行顺序是以相反的顺序触发,即先触发的是后面添加的事件。

    使用detachEvent()来移除通过attachEvent()方法添加的事件,与DOM2级方法一样,匿名函数无法被移除

添加事件的事件处理程序兼容性代码:

function addEvent(elem, type, fn) {
    if (elem.addEventListener) { //支持DOM2
        elem.addEventListener(type, fn);
    } else if (elem.attachEvent) { //IE8及以下
        elem.attachEvent('on' + type, fn)
    } else {
        elem['on' + type] = fn
    }
}

移除事件的事件处理程序兼容性代码

function removeEvent(elem, type, fn) {
    if (elem.removeEventListener) {
        elem.removeEventListener(type, fn)
    } else if (elem.detachEvent) {
        elem.detachEvent("on" + type, fn)
    } else {
        elem["on" + type] = null
    }
}

添加和移除事件处理程序的兼容性代码:

var oEvent = {
        /**
         * 添加事件的函数
         * @elem 添加事件的元素
         * @type 事件类型
         * @fn  事件执行函数
         * */
        addEvent: function (elem, type, fn) {
            if (elem.addEventListener) {
                elem.addEventListener(type, fn);
            } else if (elem.attachEvent) {
                elem.attachEvent('on' + type, fn)
            } else {
                elem["on" + type] = fn;
            }
        },
        /**
         * 添加事件的函数
         * @elem 添加事件的元素
         * @type 事件类型
         * @fn  事件执行函数
         * */
        removeEvent: function (elem, type, fn) {
            if (elem.removeEventListener) {
                elem.removeEventListener(type, fn)
            } else if (elem.detachEvent) {
                elem.detachEvent("on" + type, fn)
            } else {
                elem["on" + type] = null
            }
        },
        /**
         * 定义一个函数,元素只能执行一次事件;如:点击事件,第一次点击有效,第二次点击无效
         * */
        once: function () {

        }
}

四、事件流

事件流用来描述从页面中接收事件的顺序。

事件流分为两种:事件冒泡流和事件捕获流。这两种事件流的概念几乎完全相反。

事件流出现的前提:嵌套元素中定义了同种类型的事件。

事件捕获流只能通过 DOM2 级事件处理程序实现

4.1 事件冒泡流

IE事件流叫做事件冒泡,即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(文档);也就是说一个标签元素处理完事件之后,它的父元素、父元素的父元素也都会处理事件(从内到外)。

4.2 事件捕获流

Netscape(网景)的事件流叫做事件捕获,不太具体的节点(最外层标签)应该更早接收到事件,而最具体的节点(最内层标签)最后接收到事件(事件执行的顺序是从外到内);由于老版本浏览器不支持,因此很少有人使用事件捕获。建议大家放心地使用事件冒泡,在有特殊需要时再使用事件捕获。

DOM2级事件处理程序添加事件 element.addEventListener(type, callbackfn, boolean),第三个参数boolean是一个布尔值,默认是false,表示绑定到冒泡阶段,如果是true则表示绑定到捕获阶段。

4.3 阻止事件冒泡或事件捕获的兼容代码

if(ev.stopPropagation){//DOM推荐标准
    ev.stopPropagation()
}else{//兼容IE678
    ev.cancelBubble = true;
}

IE8及以下浏览器:对象不支持“stopPropagation”属性或方法

4.4 阻止元素默认行为的兼容性代码:

只有有默认行为的对象,才有阻止的必要性。如:页面鼠标右键事件、a标签href链接、img标签中的src请求等等…

// 兼容性写法
if (event.preventDefault) {//dom标准写法
    event.preventDefault()
} else {//兼容IE678
    event.returnValue = false;
}

// 利用return false也能阻止默认行为,没有兼容问题(只限传统注册方式DOM0级事件处理程序)

对象不支持 “preventDefault” 属性或方法

4.5 事件代理

事件代理也叫事件委托。利用事件冒泡机制,给父元素指定一个事件处理程序,就可以管理父元素及其后代元素某一类型的所有事件;如:子元素要触发的事件交由父元素代为触发执行。

  1. 为什么要用事件委托?

    一般来说,dom需要有事件处理程序,我们都会直接给它设事件处理程序就好了,那如果是很多的dom需要添加事件处理呢?比如我们有100个li,每个li都有相同的click点击事件,可能我们会用for循环的方法,来遍历所有的li,然后给它们添加事件,那这么做会存在什么影响呢?

    • 操作DOM次数过多,造成浏览器的重排和重绘就越多;
      在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能,因为需要不断的与dom节点进行交互,访问dom的次数越多,引起浏览器重绘与重排的次数也就越多,就会延长整个页面的交互就绪时间,这就是为什么性能优化的主要思想之一就是减少DOM操作的原因;如果要用事件委托,就会将所有的操作放到js程序里面,与dom的操作就只需要交互一次,这样就能大大的减少与dom的交互次数,提高性能;

    • 每个事件都是一个对象,事件处理程序越多,占用的内存越多,影响前端性能;每个函数都是一个对象,是对象就会占用内存,对象越多,内存占用率就越大,自然性能就越差了(内存不够用,是硬伤,哈哈)比如上面的100个li,就要占用100个内存空间,如果是1000个,10000个呢,那只能说呵呵了,如果用事件委托,那么我们就可以只对它的父级(如果只有一个父级)这一个对象进行操作,这样我们就需要一个内存空间就够了,是不是省了很多,自然性能就会更好。

  2. 事件委托(事件代理)原理

    对“事件处理程序过多”问题的解决方案就是事件委托,事件委托利用事件冒泡(从最深的节点开始,然后逐步向上传播事件)只在他们的父素上指定一个事件处理程序,就可以管理某一类型的的所有事件。这就是事件委托,委托它们父级代为执行事件。

  3. 事件委托的实现:查找事件源,IE和DOM事件处理程序获取方式如下:

    • DOM中的事件对象:事件对象.target 获取事件目标(事件源)

    • IE中的事件对象: 事件对象.srcElement 获取事件目标(事件源)

    • 获取事件目标兼容性写法:

      element["on"+事件类型] = function(e){
          var ev = e || event;
          //获取目标对象
          //支持DOM事件的浏览器使用target来获取事件目标
          //IE8及以前版本浏览器通过srcElement来获取事件目标
          var target = ev.target || ev.srcElement; 
      }
      
  4. 事件委托的使用场景

    • 为DOM中的很多元素绑定相同事件;

    • 为DOM中尚不存在的元素绑定事件。

  5. 事件委托的优点

    • 适合事件委托的事件有:click,mousedown,mouseup,keydown,keyup,keypress
    • 减少DOM操作:减少浏览器的重绘(repaint)和重排(reflow),从而提高性能;
    • 减少内存空间的占用率,因为每一个函数都是一个对象,对象越多,内存占有率就越大,自然性能就越差,使用事件委托,只需要在其父元素中定义一个事件就可以。

五、鼠标滚轮事件

代码:

// 鼠标滚轮事件   
// onmousewheel  谷歌和IE8以上支持的鼠标滚轮事件;火狐浏览器不支持onmousewheel形式,无响应
// window.onmousewheel = function(e){
//     var ev = e || event;
//     console.log(ev);//WheelEvent {isTrusted: true, deltaX: -0, deltaY: 100, deltaZ: 0, deltaMode: 0, …}
//     console.log(ev.type);//mousewheel
// }

// DOMMouseScroll  只能使用DOM2级事件处理程序;火狐浏览器可以正常使用;谷歌和IE8以上不支持,无响应
// window.addEventListener("DOMMouseScroll",function(e){
//     console.log(e)
// })

// 鼠标滚轮事件的兼容性代码
window.onmousewheel = wheelHandler;
window.addEventListener('DOMMouseScroll', wheelHandler);
function wheelHandler(e) { //事件对象传参是DOM标准推荐的方式
    console.log(e)
}

注:鼠标滚轮事件的属性

  1. 谷歌浏览器:属性 deltaY 垂直方向滚动的距离,滚轮向下滚动,每次滚动的距离是 100px,向上滚动,每次滚动的距离是 -100px。它是固定的值。
  2. 谷歌浏览器、IE8以上浏览器,属性 wheelDelta 固定值 120,向下是负值 -120,向上是正值 +120
  3. 火狐浏览器:属性 detail 固定值 3,向上是负值 -3 ,向下是正值 +3

Guess you like

Origin blog.csdn.net/qq_39335404/article/details/132201372