1.移動(dòng)端300ms延遲由來(lái)及解決方案
(1) 300ms延遲由來(lái)300 毫秒延遲的主要原因是解決雙擊縮放(double tap to zoom)。雙擊縮放解藻,顧名思義,即用手指在屏幕上快速點(diǎn)擊兩次巷嚣,iOS 自帶的 Safari 瀏覽器會(huì)將網(wǎng)頁(yè)縮放至原始比例。 那么這和 300 毫秒延遲有什么聯(lián)系呢评雌? 假定這么一個(gè)場(chǎng)景。用戶在 iOS Safari 里邊點(diǎn)擊了一個(gè)鏈接斤吐。由于用戶可以進(jìn)行雙擊縮放或者雙擊滾動(dòng)的操作蜕煌,當(dāng)用戶一次點(diǎn)擊屏幕之后,瀏覽器并不能立刻判斷用戶是確實(shí)要打開(kāi)這個(gè)鏈接贫母,還是想要進(jìn)行雙擊操作因块。因此靠柑,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點(diǎn)擊了屏幕隔嫡。 鑒于iPhone的成功梢杭,其他移動(dòng)瀏覽器都復(fù)制了 iPhone Safari 瀏覽器的多數(shù)約定,包括雙擊縮放咒唆,幾乎現(xiàn)在所有的移動(dòng)端瀏覽器都有這個(gè)功能误债。
(2)解決方案
1).添加viewpoint meta標(biāo)簽
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
2).FastClick
移動(dòng)端事件觸發(fā)順序:在移動(dòng)端李命,手指點(diǎn)擊一個(gè)元素,會(huì)經(jīng)過(guò):touchstart --> touchmove -> touchend -->click槽惫。
fastclick.js的原理是:FastClick的實(shí)現(xiàn)原理是在檢測(cè)到touchend事件的時(shí)候,會(huì)通過(guò)DOM自定義事件立即出發(fā)模擬一個(gè)click事件辩撑,并把瀏覽器在300ms之后真正的click事件阻止掉界斜。
?fastclick同樣可以解決移動(dòng)端點(diǎn)透現(xiàn)象。
DEMO
<!DOCTYPE html>
<html lang="en">
<head>
? ? <meta charset="UTF-8">
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
? ? <meta http-equiv="X-UA-Compatible" content="ie=edge">
? ? <title>移動(dòng)端點(diǎn)透現(xiàn)象</title>
? ? <style>
? ? ? ? * {
? ? ? ? ? ? margin: 0px;
? ? ? ? ? ? padding: 0px;
? ? ? ? }
? ? ? ? #div1 {
? ? ? ? ? ? /*紅色半透明遮蓋層A*/
? ? ? ? ? ? width: 300px;
? ? ? ? ? ? height: 300px;
? ? ? ? ? ? background-color: rgba(255, 0, 0, 0.25);
? ? ? ? }
? ? ? ? #div2 {
? ? ? ? ? ? /*黃色內(nèi)容層B*/
? ? ? ? ? ? width: 240px;
? ? ? ? ? ? height: 240px;
? ? ? ? ? ? background-color: yellow;
? ? ? ? ? ? position: absolute;
? ? ? ? ? ? left: 30px;
? ? ? ? ? ? top: 30px;
? ? ? ? ? ? z-index: -1;
? ? ? ? }
? ? ? ? #console {
? ? ? ? ? ? /*綠色狀態(tài)輸出框*/
? ? ? ? ? ? border: 1px solid green;
? ? ? ? ? ? position: absolute;
? ? ? ? ? ? top: 300px;
? ? ? ? ? ? width: 100%;
? ? ? ? }
? ? </style>
</head>
<body>
? ? <div id="div1"></div>
? ? <div id="div2">
? ? ? ? <a >去百度</a>
? ? </div>
? ? <div id="console"></div>
? ? <script src="https://cdn.bootcss.com/fastclick/1.0.6/fastclick.min.js"></script>
? ? <script type="text/javascript">
? ? ? ? window.onload = function() {
? ? ? ? ? ? if('addEventListener' in document) {
? ? ? ? ? ? ? ? document.addEventListener('DOMContentLoaded', function() {
? ? ? ? ? ? ? ? ? ? FadtClick.attach(document.body);
? ? ? ? ? ? ? ? }, false);
? ? ? ? ? ? }
? ? ? ? ? ? let div1 = document.getElementById('div1');
? ? ? ? ? ? let div2 = document.getElementById('div2');
? ? ? ? ? ? function handle(e) {
? ? ? ? ? ? ? ? let tar = e.target,eve = e.type;
? ? ? ? ? ? ? ? console.log('target:' + tar.id + " event:" + eve)
? ? ? ? ? ? ? ? if(tar.id === "div1") {
? ? ? ? ? ? ? ? ? ? div1.style.display = "none";
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? div1.addEventListener('touchend', handle);
? ? ? ? ? ? div2.addEventListener('touchstart', handle);
? ? ? ? ? ? div2.addEventListener('click', handle);
? ? ? ? }
? ? </script>
</body>
</html>
說(shuō)明:手機(jī)端瀏覽器基本已經(jīng)沒(méi)有300ms延時(shí)現(xiàn)象合冀。
2.瀏覽器事件機(jī)制中事件觸發(fā)三個(gè)階段(轉(zhuǎn)自 廊橋夢(mèng)醉)
js中時(shí)間執(zhí)行的整個(gè)過(guò)程稱(chēng)之為事件流棕叫,分為三個(gè)階段:事件捕獲階段谨设,事件目標(biāo)處理函數(shù)侣夷、事件冒泡。
當(dāng)某歌元素觸發(fā)某個(gè)事件(如:click),頂級(jí)對(duì)象document發(fā)出一個(gè)事件流帝火,順著dom的樹(shù)節(jié)點(diǎn)向觸發(fā)它的目標(biāo)節(jié)點(diǎn)流去求妹,直到達(dá)到目標(biāo)元素溉委,這個(gè)層層遞進(jìn)熄求,向下找目標(biāo)的過(guò)程為事件的捕獲階段,此過(guò)程與事件相應(yīng)的函數(shù)是不會(huì)觸發(fā)的。
到達(dá)目標(biāo)函數(shù)晋渺,便會(huì)執(zhí)行綁定在此元素上的,與事件相應(yīng)的函數(shù)昭卓,即事件目標(biāo)處理函數(shù)階段占业。
最后峰伙,從目標(biāo)元素起匣摘,再依次往頂層元素對(duì)象傳遞,途中如果有節(jié)點(diǎn)綁定了同名事件枢希,這些事件所對(duì)應(yīng)的函數(shù),在此過(guò)程中便稱(chēng)之為事件冒泡失暴。
通常情況下坯门,事件相應(yīng)的函數(shù)四在冒泡階段執(zhí)行的。addEventListener的第三個(gè)參數(shù)默認(rèn)為false逗扒,表示冒泡階段執(zhí)行(為true的時(shí)候田盈,表示捕獲階段執(zhí)行)。
使用e.stopPropgation()或e.cancelBubble = true(IE)可以阻斷事件向當(dāng)前元素的父元素冒泡缴阎。
3.?this的指向
var o = {
? ? ? ? ? ? ? ? user: 'hello',
? ? ? ? ? ? ? ? fn: function() { // this指向o
? ? ? ? ? ? ? ? ? ? console.log(this.user);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? o.fn();
? ? ? ? ? ? var test = {
? ? ? ? ? ? ? ? a: 10,
? ? ? ? ? ? ? ? fn: function(){
? ? ? ? ? ? ? ? ? ? console.log(this.a); // 12
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? test.b.fn();
? ? ? ? ? ? function Fn() {
? ? ? ? ? ? ? ? this.user = "woca";
? ? ? ? ? ? }
? ? ? ? ? ? var he = new Fn();
? ? ? ? ? ? console.log(he.user); //woca
? ? 4. apply bind call
? ? ? ? ? ? // 1. call()
? ? ? ? ? ? var a = {
? ? ? ? ? ? ? ? user: 'lalala',
? ? ? ? ? ? ? ? fn: function() {
? ? ? ? ? ? ? ? ? ? console.log(this.user);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? var b = a.fn;
? ? ? ? ? ? b(); //undefined
? ? ? ? ? ? a.fn(); // lalala
? ? ? ? ? ? //通過(guò)在call方法,給第一個(gè)參數(shù)添加要把b添加到哪個(gè)環(huán)境中简软,簡(jiǎn)單來(lái)說(shuō)蛮拔,this就會(huì)指向那個(gè)對(duì)象述暂。
? ? ? ? ? ? b.call(a); // lalala
? ? ? ? ? ? //call方法除了第一個(gè)參數(shù)以外還可以添加多個(gè)參數(shù),如下:
? ? ? ? ? ? var a = {
? ? ? ? ? ? ? ? user: 'hahaha',
? ? ? ? ? ? ? ? fn: function(arg1, arg2) {
? ? ? ? ? ? ? ? ? ? console.log(this.user); // hahaha
? ? ? ? ? ? ? ? ? ? console.log(arg1 + arg2); // 3
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? var b = a.fn;
? ? ? ? ? ? b.call(a,1,2);
? ? ? ? ? ? // 2. apply()
? ? ? ? ? ? var a = {
? ? ? ? ? ? ? ? user: 'hahaha',
? ? ? ? ? ? ? ? fn: function(arg1, arg2) {
? ? ? ? ? ? ? ? ? ? console.log(this.user); // hahaha
? ? ? ? ? ? ? ? ? ? console.log(arg1 + arg2); // 3
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? var b = a.fn;
? ? ? ? ? ? b.apply(a,[2,4]);
? ? ? ? ? ? // *注意如果call和apply的第一個(gè)參數(shù)寫(xiě)的是null建炫,那么this指向的是window對(duì)象
? ? ? ? ? ? var a = {
? ? ? ? ? ? ? ? user: "balabala",
? ? ? ? ? ? ? ? fn: function(){
? ? ? ? ? ? ? ? ? ? console.log(this); // window
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? var b = a.fn;
? ? ? ? ? ? b.apply(null);
? ? ? ? ? ? // call和apply的入?yún)^(qū)別:call若干個(gè)畦韭,apply是數(shù)組
? ? ? ? ? ? var a = {
? ? ? ? ? ? ? ? user: 'limei',
? ? ? ? ? ? ? ? fn:function(a,b,c) {
? ? ? ? ? ? ? ? ? ? console.log(this.user); // limei
? ? ? ? ? ? ? ? ? ? console.log(a,b,c); // 10 1 2
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? var b = a.fn;
? ? ? ? ? ? var c = b.bind(a,10);
? ? ? ? ? ? c(1,2);
? ? ? ? ? ? /** 總結(jié):
? ? ? ? ? ? ? * call和apply都是改變上下文中的this并立即執(zhí)行這個(gè)函數(shù),
? ? ? ? ? ? ? * bind方法可以讓對(duì)應(yīng)的函數(shù)想什么時(shí)候調(diào)就什么時(shí)候調(diào)用肛跌,并且可以將參數(shù)在執(zhí)行的時(shí)候添加
? ? ? ? ? ? */