event

2021/12/18

# EventTarget

# 构造

EventTarget

  • 作用:构造一个事件监听器
  • 调用:new EventTarget()
  • 增加监听:target.addEventListener()
  • 触发事件:target.dispatchEvent(new Event())

# addEventListener

  • 作用:为文档上的元素绑定事件监听,触发函数
  • 调用:element.addEventlistener(event, callback[, option | useCapture])
  • 入参:String, Function[, Object | boolean]
  • 返回:undefined
  • tip:文档上的元素指Element/Window/Document/XMLHttpRequest/其他支持事件的对象
  • DOM上onclick类的事件绑定都是以属性的形式存在DOM对象上,因此不能重复绑定
  • addEventListener可以同时绑定多个事件,因为注册的是一个事件列表

# removeEventListener

  • 作用:移除监听事件
  • 调用:eventTarget.removeEventTarget(type, callback, options)
  • 入参:String, Function[, Boolean | Object]
  • 返回:undefined







 
 

 


 
 




<body>
    <button id='btn'>按钮</button>

    <script>
        const btn = document.querySelector('#btn');
        const callback1 = () => console.log('1');
        const callback2 = () => console.log('2');
        btn.addEventListener('click', callback1);
        btn.addEventListener('click', callback2);

        btn.click(); // 1 2
        setTimeout(() => {
            console.log('移除事件1,再点击');
            btn.removeEventListener('click', callback1);
            btn.click(); // 2
        }, 2000)
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# dispatchEvent

  • 作用:向指定目标派发事件
  • 调用:element.dispatchEvent(event)
  • 入参:Event
  • 返回:undefined

只发射一次

  • 每个事件只能被发射一次,多次发射报错

# Event属性

# Event

构造

  • 作用:构造新的Event事件
  • 调用:new Event(type[, {bubbles, cancelable, composed}])
  • 入参:String[, {Boolean, Boolean, Boolean}]

# target

  • 值:事件发起节点对象
  • 获取:e.target

# currentTarget

  • 作用:拿到事件当前传播到的node对象
  • 获取:e.currentTarget
<body>
    <div>
        <button>按钮</button>
    </div>

    <script>
        const button = document.querySelector('button');
        const div = document.querySelector('div');
        div.addEventListener('click', e => {
            console.log(e.target); // <button>按钮</button>
            console.log(e.currentTarget); // <div>...</div>
        })
        button.click();
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# type

  • 值:事件的类型
  • 返回:String
<body>
    <button>按钮</button>

    <script>
        const button = document.querySelector('button');
        button.addEventListener('go', function(e) {
            console.log(e.type); // go
        });

        const e = new Event('go');
        button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13

# bubbles

  • 作用:检测事件是否会冒泡
  • 获取:event.bubbles
  • 值:Boolean










 
 

 
 
 






<body>
    <div>
        <button>按钮1</button>
    </div>

    <script>
        const div = document.querySelector('div');
        const btn = document.querySelector('button');
        btn.addEventListener('click', e => console.log(e.bubbles));

        // div盒子在冒泡阶段等click事件触发
        div.addEventListener('click', () => console.log('div说我被触发了'), false);

        // new Event默认不冒泡
        btn.dispatchEvent(new Event('click')); // false
        console.log('等两秒');

        // true div说我被触发了
        setTimeout(() => btn.dispatchEvent(new Event('click', {bubbles: true})), 2000)
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# cancelable

  • 作用:设置事件默认事件是否可被preventDefault()取消
  • 获取:event.cancelable
  • 值:Boolean
  • tip:正常传播,只是禁止了默认事件

# defaultPrevented

  • 作用:查看该事件是否调用了preventDefault方法
  • 调用:e.defaultPrevented
  • 返回:Boolean

  • dispatchEvent发射的事件好像不生效?
  • 手动触发可以
  • 点击按钮,显示true
<body>
    <button>按钮</button>

    <script>
        const button = document.querySelector('button');

        button.addEventListener('click', function(e) {
            e.preventDefault();
            console.log(e.defaultPrevented); // true
        })
        
        // 生成的事件无效?
        // const e = new Event('click');
        // e.preventDefault();
        // button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# eventPhase

  • 作用:查看当前事件传播到哪个阶段了
  • 调用:event.eventPhase
  • 返回:Number
含义
0 事件没开始传播
1 事件在捕获阶段
2 事件到达target
3 事件在冒泡阶段










 



 



 



 



 


 



<body>
    <div>
        <button>按钮</button>
    </div>

    <script>
        const button = document.querySelector('button');
        const div = document.querySelector('div');

        div.addEventListener('click', function(e) {
            console.log('div捕获:' + e.eventPhase); // 1
        }, true);

        button.addEventListener('click', function(e) {
            console.log('button捕获:' + e.eventPhase); // 2
        }, true);

        button.addEventListener('click', function(e) {
            console.log('button冒泡:' + e.eventPhase); // 2
        });

        div.addEventListener('click', function(e) {
            console.log('div冒泡:' + e.eventPhase); // 3
        });
        
        const e = new Event('click');
        console.log(e.eventPhase); // 0
        button.dispatchEvent(e);

        setTimeout(() => console.log('结束' + e.eventPhase)); // 0
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# isTrusted

  • 作用:查看该事件是不是系统信任的浏览器发起事件【用户生成的返回false】
  • 调用:event.isTrusted
  • 返回:Boolean
  • tip:只读属性
  • dispatchEvent发起的值是false,点击时浏览器发起的值是true
<body>
    <button>按钮</button>

    <script>
        const button = document.querySelector('button');
        button.addEventListener('click', function(e) {
            console.log(e.isTrusted); // false
        });

        const e = new Event('click');
        button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13

# Event方法

# preventDefault

  • 作用:阻止浏览器默认事件作用触发
  • 调用:e.preventDefault()
  • tip:不影响自定义事件,不影响事件传播

# composedPath

  • 作用:事件的传播路径
  • 调用:e.composedPath()
  • 返回:Array【栈结构】

返回值

  • 0是target,最下面是window
  • 从一开始就把路径存完了,并不是边执行边存的










 



 







<body>
    <article>
        <div>
            <button>按钮</button>
        </div>
    </article>
    <script>
        const button = document.querySelector('button');
        const div = document.querySelector('div');
        button.addEventListener('click', function(e) {
            console.log(e.composedPath()); // Array(7) [button, div ...]
        });

        div.addEventListener('click', function(e) {
            console.log(e.composedPath()); // Array(7) [button, div ...]
        },true);

        const e = new Event('click');
        button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# stopImmediatePropagation

stop stopImmediatePropagation

  • 翻译:停止立即传播
  • 作用:不再调用其他的事件回调,并且阻止传播
  • 调用:e.stopImmediatePropagation()
  • 返回:undefined

  • addEventListener同一个事件时是按序执行,stopImmediatePropagation之前的都执行,之后的都不执行
  • 并且停止事件的传播















 


 




 









<body>
    <article>
        <div>
            <button>按钮</button>
        </div>
    </article>
    <script>
        const button = document.querySelector('button');
        const div = document.querySelector('div');

        button.addEventListener('click', function(e) {
            console.log('e的点击事件1');
        });
        button.addEventListener('click', function(e) {
            console.log('e的点击事件2');
            e.stopImmediatePropagation();
        });

        // 已被阻止剩下的事件回调执行,无
        button.addEventListener('click', function(e) {
            console.log('e的点击事件3');
        });
        
        // 已被停止事件传播,无
        div.addEventListener('click', function(e) {
            console.log('到div了');
        });

        const e = new Event('click');
        button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# stopPropagation

  • 作用:停止事件传播,但本对象上的监听回调会执行完
  • 调用:e.stopPropagation()















 


 




 









<body>
    <article>
        <div>
            <button>按钮</button>
        </div>
    </article>
    <script>
        const button = document.querySelector('button');
        const div = document.querySelector('div');

        button.addEventListener('click', function(e) {
            console.log('e的点击事件1');
        });
        button.addEventListener('click', function(e) {
            console.log('e的点击事件2');
            e.stopPropagation();
        });

        // 会执行完本对象的事件回调
        button.addEventListener('click', function(e) {
            console.log('e的点击事件3');
        });
        
        // 已被停止事件传播,无
        div.addEventListener('click', function(e) {
            console.log('到div了');
        });

        const e = new Event('click');
        button.dispatchEvent(e);
    </script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 移动端事件

# clientX/pageX/screenX

  • e.targetTouches[0].clientX是相对于浏览器左边缘距离
  • e.targetTouches[0].screenX是相对于屏幕左边缘距离
  • e.targetTouches[0].pageX是相对于页面左边缘距离,有可能发生了滚动

# touch事件和mouse事件打平

  1. 鼠标mousemovetouch事件取x和y方法不一样
  2. mouse有移出屏幕的风险,会导致监听触发不符合预期

  • mouse事件有x,y,touch事件只有clientX,clientY
  • touch事件必须拿targetTouchestouches获取clientX/clientY
  • mac的触控板是touch事件

// 打平移动端位置事件
const moveListener = (el, callback) => {
  let mouseDown = false;
  const touchMove = e => callback(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
  const mouseDownEvent = () => mouseDown = true;
  const mouseUp = () => mouseDown = false;
  const mouseOut = () => mouseDown = false;
  const mouseMove = (e) => {
    if (!mouseDown) return;
    callback(e.clientX, e.clientY);
  }
  el.addEventListener("touchmove", touchMove);
  el.addEventListener("mousedown", mouseDownEvent);
  el.addEventListener("mouseup", mouseUp);
  el.addEventListener("mouseout", mouseOut);
  document.addEventListener("mouseout", mouseOut);
  el.addEventListener("mousemove", mouseMove);

  return () => {
    el.removeEventListener("touchmove", touchMove);
    el.removeEventListener("mousedown", mouseDownEvent);
    el.removeEventListener("mouseup", mouseUp);
    el.removeEventListener("mouseout", mouseOut);
    document.removeEventListener("mouseout", mouseOut);
    el.removeEventListener("mousemove", mouseMove);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
上次更新: 11/1/2024