文章加密

;

2018年11月4日 星期日

=> arrow function 與 addEventListener, cancelable

https://stackoverflow.com/questions/24900875/whats-the-meaning-of-an-arrow-formed-from-equals-greater-than-in-javas

1. they do not bind their own values of this
2. Arrow functions are always anonymous.  即function foo(){}
3. Arrow functions are part of the ECMAscript 6 specification, but not part of "normal" JavaScript in use in most browsers today. 

in place of expressions like function (foo) {...}, you can see below:
例1
var a = [
  "We're up all night 'til the sun",
  "We're up all night to get some",
  "We're up all night for good fun",
  "We're up all night to get lucky"
];

// These two assignments are equivalent:

// Old-school:
var a2 = a.map(function(s){ return s.length });

// ECMAscript 6 using arrow functions
var a3 = a.map( s => s.length );

// both a2 and a3 will be equal to [31, 30, 31, 31]

例2
function Foo() {
    this.name = name;
    this.count = 0;
    this.startCounting();
}

Foo.prototype.startCounting = function() {
  var self = this;
  setInterval(function () {
    // this is the Window, not Foo {}, as you might expect
    console.log(this); // [object Window]
    // that's why we reassign this to self before setInterval()
    console.log(self.count);
    self.count++;
  },1000)
}

new Foo();
可寫成
function Foo() {
    this.name = name;
    this.count = 0;
    this.startCounting();
}

Foo.prototype.startCounting = function() {
  setInterval(() => {        
    console.log(this); // [object Object]
    console.log(this.count); // 1, 2, 3
    this.count++;
  },1000)
}

new Foo();




https://blog.techbridge.cc/2017/07/15/javascript-event-propagation/


1. 關於這些事件的傳遞順序,只要記住兩個原則就好:


先捕獲,再冒泡
當事件傳到 target 本身,沒有分捕獲跟冒泡

2.eventPhase,是一個數字,表示這個事件在哪一個 Phase 觸發。
html:
// PhaseType
const unsigned short CAPTURING_PHASE = 1;
const unsigned short AT_TARGET = 2;
const unsigned short BUBBLING_PHASE = 3;

3.實例說明

<!DOCTYPE html>
<html>
<body>
<ul id="list">
<li id="list_item">
<a id="list_item_link" target="_blank" href="http://google.com">
</a>
</li>
</ul>
</body>
</html>
js:
const get = (id) => document.getElementById(id);
const $list = get('list');
const $list_item = get('list_item');
const $list_item_link = get('list_item_link');
// list 的冒泡
$list.addEventListener('click', (e) => {
console.log('list bubbling', e.eventPhase);
}, false)
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
}, true)
// list_item 的冒泡
$list_item.addEventListener('click', (e) => {
console.log('list_item bubbling', e.eventPhase);
}, false)
// list_item 的捕獲
$list_item.addEventListener('click', (e) => {
console.log('list_item capturing', e.eventPhase);
}, true)
// list_item_link 的冒泡
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link bubbling', e.eventPhase);
}, false)
// list_item_link 的捕獲
$list_item_link.addEventListener('click', (e) => {
console.log('list_item_link capturing', e.eventPhase);
}, true)

一樣點擊超連結,輸出的結果是:
list capturing 1
list_item capturing 1
list_item_link bubbling 2
list_item_link capturing 2
list_item bubbling 3
list bubbling 3


4. 事件鏈這麼長,一定有方法可以中斷這一條鏈,讓事件的傳遞不再繼續,就是:e.stopPropagation (取消事件傳遞),但對於同一個層級,其他的 listener 還是會被執行到。

若是你想要讓其他同一層級的 listener 也不要被執行,可以改用e.stopImmediatePropagation();

5. e.preventDefault (取消預設行為) ,preventDefault跟 JavaScript 的事件傳遞「一點關係都沒有」,你加上這一行之後,事件還是會繼續往下傳遞。

Once preventDefault has been called it will remain in effect throughout the remainder of the event’s propagation. 意思就是說一旦 call 了preventDefault,在之後傳遞下去的事件裡面也會有效果。

以上面的例子,$list改寫成下方這樣,則不會跳出google.com新頁面,但所有console.log內容都會和原本所呈現的結果一樣
// list 的捕獲
$list.addEventListener('click', (e) => {
console.log('list capturing', e.eventPhase);
e.preventDefault();
}, true)


應用 做數據統計及分析










1
2
3
window.addEventListener('click', (e) => {
console.log(e.target);
}, true)
利用事件傳遞機制的特性,在window上面使用捕獲,就能保證一定是第一個被執行的事件,你就可以在這個 function 裡面偵測頁面中每一個元素的點擊,可以傳回去做數據統計及分析。




cancelable動作:檢測事件是否為 preventDefault() 方法可以取消与事件关联的默认动作 ,結果會回傳true, 或false。所有 Cancelable 为 true 的事件类型理论上都是可以有 {passive: true} 优化的。

passive: addEventListener() 的第三个参数之一,出現這個參數的理由是 浏览器无法预先知道一个监听器会不会调用 preventDefault(),它能做的只有等监听器执行完后再去执行默认行为,而监听器执行是要耗时的,有些甚至耗时很明显,这样就会导致页面卡顿
passive 的意思是“顺从的”,表示它不会对事件的默认行为说 no,也就是 preventDefault() 无效。
鉴于这个新特性本来就是为解决滚动和触摸事件的卡顿而发明的,目前 Chrome 和 Firefox 支持优化的事件类型也仅限这类事件,比如 touchstart,touchmove,wheel 等事件。
即便为下面这些类型的事件添加 passive 的监听器,目前浏览器们也不会优化:
  • click 事件: 左键点击这个链接,等待 3 秒后才会打开新页面(可能被浏览器识别成弹窗)
  • contextmenu 事件:右键点击这句文本,等待 3 秒后才会打开右键菜单 
  • beforeinput 事件(只有 Chrome 52 及以上支持):在右侧输入时会有 300 毫秒的卡顿 
总结一下就是 {passive: true} 不能保证浏览器对所有事件类型的默认行为进行优化

http://www.cnblogs.com/ziyunfei/p/5545439.html

event.defaultPrevented:

回傳一個布林值,表示事件的預設行為是否被取消,也就是事件物件是否曾執行 preventDefault() 方法

event.stopPropagation():stops the move upwards, but on the current element all other handlers will run.
event.stopImmediatePropagation():stop the bubbling and prevent handlers on the current element from running.

dispatchEvent:是「建立→初始化→觸發」的最後一步驟。而事件有多種建立方式,例如用 ​document.createEvent 並用 initEvent 或其他特殊 methods ,像是 initMouseEvent 或 initUIEvent 來初始化。
或是用new Event建立,再用addEventListener監聽,最後再用dispatchEvent觸發。
也就是說,欲使用dispatchEvent必須要有一定的前置作業!

綜合上述各個新詞彙,應用如下
let event = new Event("foo", {  // 创建一个 type 为 foo 的事件对象,可以被阻止默认行为。這是創建了一個叫foo的「動作」!
  "cancelable": true
})

document.addEventListener("foo", function(event) { // 在 document 上绑定 foo 事件的监听函数。為了更熟悉,可以想像foo替換成click,這樣就是監聽click動作
  console.log(event.defaultPrevented) // false
  event.preventDefault()
  console.log(event.defaultPrevented) // 还是 false,preventDefault() 无效
}, {
  passive: true
})
 
document.dispatchEvent(event) // 觸發自定义事件

輸出結果會有 Unable to preventDefault inside passive event listener invocation.警告

另外,我們要注意:event.currentTarget (=this) v.s. event.target(触发事件的元素,觀念為caturing→target→bubbling) 
currentTarget有可能會比較大,為parent element。
而target會是特定element,不會是parent element。

在 removeEventListener 的时候永远不需写 passive 和 once,但 capture 可能要!理由显而易见,一个监听器同时是 passive 和非 passive(以及同时是 once 和非 once)是说不通的,如果你添加了两者,那么后添加的不算,浏览器会认为添加过了

沒有留言:

張貼留言