首頁(yè)

獲取網(wǎng)頁(yè)授權(quán)

seo達(dá)人

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

在微信登錄中,如何和獲取網(wǎng)頁(yè)授權(quán)。

一、登錄微信測(cè)試公眾品平臺(tái),修改網(wǎng)頁(yè)授權(quán)基本信息,輸入授權(quán)回調(diào)頁(yè)面域名(自己的域名)。

然后重新建立一個(gè)tp框架 編寫(xiě)方法如圖:

[php] view plain copy
  1. <?php  
  2. namespace Home\Controller;  
  3. use Think\Controller;  
  4. class IndexController extends Controller {  
  5.     public function index(){  
  6.        $appid='wx27f664ab15ecb71d';  
  7.        $redirect_uri=urlencode('http://www.crimson1.top/vote/index.php/home/index/getcode');  
  8.        $url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=$appid&redirect_uri=$redirect_uri&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";  
  9.   
  10.              header("Location:".$url);  
  11.     }  
  12.   
  13.     public function getcode(){  
  14.         $code=$_GET["code"];  
  15.          $json=$this->access_token($code);  
  16.          echo $json;  
  17.     }  
  18.     public function access_token($code){  
  19.         $appid="wx27f664ab15ecb71d";  
  20.         $appsecret="015756334f2982ed1189c6d66dbc0353";  
  21.         $url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appid&secret=$appsecret&code=$code&grant_type=authorization_code";  
  22.   
  23.         $ret=https_request($url);  
  24.         return $ret;  
  25.     }  
  26. }  

在公共模塊中新建function.php

[php] view plain copy
  1. <?php  
  2. function https_request($url){  
  3.     $curl=curl_init();  
  4.     curl_setopt($curl, CURLOPT_URL, $url);  
  5.     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);  
  6.     curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);  
  7.     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
  8.     $data=curl_exec($curl);  
  9.     if(curl_errno($curl)){  
  10.         return 'ERROR'.curl_error($curl);  
  11.     }  
  12.     curl_close($curl);  
  13.     return $data;  
  14. }  

在自己的手機(jī)端訪(fǎng)問(wèn),就能獲取access_token;

藍(lán)藍(lán)設(shè)計(jì)sillybuy.com )是一家專(zhuān)注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶(hù)體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

設(shè)計(jì)是什么?為什么需要設(shè)計(jì)

藍(lán)藍(lán)設(shè)計(jì)的小編

設(shè)計(jì)不是簡(jiǎn)單的迎合消費(fèi)者的需求,而是引導(dǎo)他們消費(fèi),不光是美化生活,更重要的是創(chuàng)造一種生活方式,與其說(shuō)是設(shè)計(jì)一件產(chǎn)品,不如說(shuō)是設(shè)計(jì)了一種生活方式。

JavaScript 中的 call()、apply()、bind() 的詳解

seo達(dá)人

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

三種方法的作用

在 JavaScript 中

  1. call、apply 和 bind 是 Function 對(duì)象自帶的三個(gè)方法,都是為了改變函數(shù)體內(nèi)部 this 的指向。
  2. call、apply 和 bind 三者第一個(gè)參數(shù)都是 this 要指向的對(duì)象,也就是想指定的上下文。
  3. call、apply 和 bind 三者都可以利用后續(xù)參數(shù)傳參。
  4. bind 是返回對(duì)應(yīng) 函數(shù),便于稍后調(diào)用;apply 、call 則是立即調(diào)用 。
舉個(gè)栗子
function fruits() {}

fruits.prototype = {
   color: 'red',
   say: function() { console.log('My color is ' + this.color); 
   }
} var apple = new fruits;
apple.say(); // 此時(shí)方法里面的this 指的是fruits // 結(jié)果: My color is red
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如果我們有一個(gè)對(duì)象 banana= {color : 'yellow'} ,我們不想重新定義 say 方法,那么我們可以通過(guò) call 或 apply 用 apple 的 say 方法:

var banana = { color: 'yellow' };
apple.say.call(banana); // 此時(shí)的this的指向已經(jīng)同過(guò)call()方法改變了,指向的是banana,this.color就是banana.color='yellow'; // 結(jié)果是My color is yellow 

apple.say.apply(banana); // 同理,此時(shí)的this的指向已經(jīng)同過(guò)apply()方法改變了,指向的是banana,this.color就是banana.color ='yellow'; // 結(jié)果是My color is yellow

apple.say.apply(null); // nullwindow下的,此時(shí),this 就指向了window ,但是window下并沒(méi)有clolr這個(gè)屬性,因此this.clolr就是window.color=undefined; // 結(jié)果是My color is undefined
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
call 和 apply 的區(qū)別

二者的作用完全一樣,知識(shí)接受 參數(shù) 的方式不太一樣。

call 是把參數(shù)按順序傳遞進(jìn)去,而 apply 則是把參數(shù)放在 數(shù)組 里面。

var array1 = [12,'foo',{name:'Joe'},-2458]; var array2 = ['Doe' , 555 , 100]; Array.prototype.push.call(array1, array2); // 這里用 call 第二個(gè)參數(shù)不會(huì)把 array2 當(dāng)成一個(gè)數(shù)組,而是一個(gè)元素 // 等價(jià)于 array1.push("'Doe' , 555 , 100"); // array1.length=5; Array.prototype.push.apply(array1, array2); // 這里用 apply 第二個(gè)參數(shù)是一個(gè)數(shù)組 // 等價(jià)于:  array1.push('Doe' , 555 , 100); // array1.length=7;
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
類(lèi)(偽)數(shù)組使用數(shù)組方法
var divElements = document.getElementsByTagName('div'); // 雖然 divElements 有 length 屬性,但是他是一個(gè)偽數(shù)組,不能使用數(shù)組里面的方法 Array.isArray(divElements);// false var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div')); // 將數(shù)組對(duì)象 Array 里的 this 指向偽數(shù)組 document.getElementsByTagName('div'),  // slice() 方法可從已有的數(shù)組中返回選定的元素,不傳參數(shù)是,返回整個(gè)數(shù)組  Array.isArray(domNodes);// true
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
驗(yàn)證一個(gè)對(duì)象的類(lèi)型可以用
Object.prototype.toString.call(obj)
    
  • 1
bind() 方法

bind() 方法會(huì)創(chuàng)建一個(gè) 新函數(shù),稱(chēng)為綁定函數(shù),當(dāng)調(diào)用這個(gè)綁定函數(shù)時(shí),綁定函數(shù)會(huì)以創(chuàng)建它時(shí)傳入 bind() 方法的第一個(gè)參數(shù) 作為 this,傳入 bind() 方法的 第二個(gè)以及以后的參數(shù)加上綁定函數(shù)運(yùn)行時(shí)本身的參數(shù)按照順序作為原函數(shù)的參數(shù)來(lái)調(diào)用原函數(shù)。

注意bind()方法創(chuàng)建的函數(shù)不會(huì)立即調(diào)用,在下面的例子中,最后 func() 才調(diào)用了函數(shù),這是它與 callapply的區(qū)別。

var bar = function(){ console.log(this.x);
} var foo = {
    x:3 }
bar(); // undefined var func = bar.bind(foo); //此時(shí)this已經(jīng)指向了foo,但是用bind()方法并不會(huì)立即執(zhí)行,而是創(chuàng)建一個(gè)新函數(shù),如果要直接調(diào)用的話(huà) 可以bar.bind(foo)() func(); // 3
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在 Javascript 中,多次 bind() 是無(wú)效的。更深層次的原因, bind() 的實(shí)現(xiàn),相當(dāng)于使用函數(shù)在內(nèi)部包了一個(gè) call / apply ,第二次 bind() 相當(dāng)于再包住第一次 bind() ,故第二次以后的 bind 是無(wú)法生效的。

var bar = function(){ console.log(this.x);
} var foo = {
  x:3 } var sed = {
  x:4 } var func = bar.bind(foo).bind(sed);
func(); //3 var fiv = {
  x:5 } var func = bar.bind(foo).bind(sed).bind(fiv);
func(); //3

UI設(shè)計(jì)師:程序員國(guó)寶,請(qǐng)你保持冷靜,這是我的設(shè)計(jì)稿!

藍(lán)藍(lán)設(shè)計(jì)的小編

作為一名UI設(shè)計(jì)師,賊喜歡高一些非常炫酷的交互動(dòng)效,而在導(dǎo)航設(shè)計(jì)中,有些設(shè)計(jì)更十分貼合這一點(diǎn)。

Flex布局-骰子demo

seo達(dá)人

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

最近學(xué)習(xí)了Flex布局,

以下是阮一峰老師關(guān)于Flex的博客  。在此感謝他讓我get一項(xiàng)新技能!

Flex語(yǔ)法篇:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

Flex實(shí)戰(zhàn)篇:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html

1、色子數(shù):1

思路:讓圓點(diǎn)(即子元素)在橫軸上居中在豎軸上居中,分別用justify-content和align-items

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 200px;  height: 200px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 25px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  justify-content: center;  align-items:center;  }  .main >div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  </style>
</head>
<body>
<div class="main">
    <div class="item"></div>
</div>
</body>
</html>
2、色子數(shù):2

思路:豎列布局且在主軸方向采用justify-content的兩端對(duì)齊布局,這樣兩個(gè)圓點(diǎn)會(huì)在左邊呈現(xiàn),然后采用align-items讓其居中

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 200px;  height: 200px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 25px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  flex-direction: column;  justify-content: space-between;  align-items:center;  }  .main >div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  </style>
</head>
<body>
<div class="main">
    <div class="item"></div>
    <div class="item"></div>
</div>
</body>
</html>
3、色子數(shù):3

思路:用到align-self屬性讓第二個(gè)和第三個(gè)圓點(diǎn)有自己的屬性設(shè)置,分別在縱軸方向上居中和低端對(duì)齊

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 180px;  height: 180px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 25px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  }  .main >div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  .item:nth-child(2){  align-self:center;  }  .item:nth-child(3){  align-self:flex-end;  }  </style>
</head>
<body>
<div class="main">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
</body>
</html>
4、色子數(shù):4

思路:先豎著放兩行圓點(diǎn),每行圓點(diǎn)里橫著放兩個(gè)圓點(diǎn),所以最外層父元素設(shè)置align,里面的父元素設(shè)置justify-content

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 180px;  height: 180px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 25px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  flex-wrap:wrap;  align-content:space-between;  }  .column >div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  .column{  flex-basis:100%;  display:flex;  justify-content: space-between;  }  </style>
</head>
<body>
<div class="main">
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
</div>
</body>
</html>
5、色子數(shù):5

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 180px;  height: 180px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 25px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  flex-wrap:wrap;  align-content:space-between;  }  .column > div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  .column{  flex-basis:100%;  display:flex;  justify-content: space-between;  }  .column:nth-child(2){  justify-content: center;  }  </style>
</head>
<body>
<div class="main">
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <div class="column">
    <div class="item"></div>
    </div>
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
</div>
</body>
</html>
6、色子數(shù):6

思路:跟四點(diǎn)的一樣,先豎放三行在每行橫放兩個(gè)圓點(diǎn)

實(shí)現(xiàn)代碼:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style> *{  margin:0;  padding:0;  }  body{  background:#000;  }  .main {  width: 180px;  height: 180px;  background: #fff;  border-radius: 20px;  margin: 100px auto;  padding: 15px;  -webkit-box-sizing: border-box;  -moz-box-sizing: border-box;  box-sizing: border-box;  display: flex;  align-content:space-between;  flex-wrap:wrap;  }  .column > div{  width:40px;  height:40px;  background:#000;  border-radius:40px;  }  .column{  flex-basis:100%;  display:flex;  justify-content: space-between;  }  </style>
</head>
<body>
<div class="main">
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>
    <div class="column">
        <div class="item"></div>
        <div class="item"></div>
    </div>

</div>
</body>
</html>

藍(lán)藍(lán)設(shè)計(jì)sillybuy.com )是一家專(zhuān)注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶(hù)體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

設(shè)計(jì)視覺(jué)系統(tǒng)化,拒絕野路子

藍(lán)藍(lán)設(shè)計(jì)的小編

Facebook是一個(gè)連接全球數(shù)十億人的社交工具。 面對(duì)這一視覺(jué)系統(tǒng),設(shè)計(jì)師遇到了前所未有的挑戰(zhàn)

雖然每個(gè)工具都能很好地履行其預(yù)期的功能,但它們并沒(méi)有提供令人滿(mǎn)意的整體經(jīng)驗(yàn)。設(shè)計(jì)的UI模式,使用顏色和圖像每個(gè)產(chǎn)品都是不同的。整體看起來(lái)不僅過(guò)時(shí),而且與Facebook的這些專(zhuān)業(yè)人士在個(gè)人生活中使用也脫離聯(lián)系。

我們希望制作出一致,令人滿(mǎn)意的用戶(hù)體驗(yàn),值得我們的商業(yè)產(chǎn)品為公司和人們喜歡。我們還希望通過(guò)改進(jìn)他們所依賴(lài)的工具來(lái)展示我們對(duì)這些業(yè)務(wù)的承諾。

HTML5應(yīng)用程序緩存

seo達(dá)人

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

HTML5引入了應(yīng)用程序緩存,意味web應(yīng)用可以進(jìn)行緩存,在沒(méi)有網(wǎng)絡(luò)的情況下使用

應(yīng)用程序緩存為應(yīng)用帶來(lái)的三大優(yōu)勢(shì):

離線(xiàn)訪(fǎng)問(wèn)應(yīng)用

速度更快——已緩存資源加載的更快

減少服務(wù)器負(fù)載——瀏覽器只從服務(wù)器下載更新過(guò)或更改過(guò)的資源

瀏覽器支持情況:主流瀏覽器都支持,IE要10以上的版本

HTML5通過(guò)在html文件添加manifest屬性,啟用應(yīng)用程序緩存

例子:

<!DOCTYPE HTML>

<htmlmanifest="demo.appcache">

...

</html>

每個(gè)指定了 manifest 的頁(yè)面在用戶(hù)對(duì)其訪(fǎng)問(wèn)時(shí)都會(huì)被緩存。如果未指定 manifest 屬性,則頁(yè)面不會(huì)被緩存(除非在 manifest 文件中直接指定了該頁(yè)面)。

manifest 文件的建議的文件擴(kuò)展名是:".appcache"。

manifest 文件需要配置正確的 MIME-type,即 "text/cache-manifest"。必須在 web 服務(wù)器上進(jìn)行配置。

Mainifest文件

manifest 文件是簡(jiǎn)單的文本文件,它告知瀏覽器被緩存的內(nèi)容(以及不緩存的內(nèi)容)。

例子:

CACHE MANIFEST

# 2012-02-21 v1.0.0

CACHE:

cached.js

cached.css

 

NETWORK:

uncached.js

uncached.css

 

FALLBACK:

index.html 404.html


CACHE MANIFEST 寫(xiě)在manifest文件開(kāi)頭,是必須的

CACHE作用是標(biāo)識(shí)出哪些文件需要緩存,可以是相對(duì)路徑也可以是絕對(duì)路徑

NETWORK可選,這一部分是要直接讀取的文件,可以使用通配符 * 。

FALLBACK可選,指定了一個(gè)后備頁(yè)面,當(dāng)資源無(wú)法訪(fǎng)問(wèn)時(shí),瀏覽器會(huì)使用該頁(yè)面。

在線(xiàn)的情況下,瀏覽器發(fā)現(xiàn)html頭部有manifest屬性,會(huì)請(qǐng)求manifest文件,如果是第一次訪(fǎng)問(wèn)應(yīng)用,瀏覽器就會(huì)根據(jù)manifest文件的內(nèi)容下載相應(yīng)的資源并且進(jìn)行離線(xiàn)存儲(chǔ)。如果已經(jīng)訪(fǎng)問(wèn)過(guò)應(yīng)用并且資源已經(jīng)離線(xiàn)存儲(chǔ)了,那么瀏覽器就會(huì)使用離線(xiàn)的資源加載頁(yè)面,然后瀏覽器會(huì)對(duì)比新的manifest文件與舊的manifest文件,如果文件沒(méi)有發(fā)生改變,就不做任何操作,如果文件改變了,那么就會(huì)重新下載文件中的資源并進(jìn)行離線(xiàn)存儲(chǔ)。

離線(xiàn)的情況下,瀏覽器就直接使用離線(xiàn)存儲(chǔ)的資源。

注意:

1.服務(wù)器對(duì)離線(xiàn)的資源進(jìn)行了更新,那么必須更新manifest文件之后這些資源才能被瀏覽器重新下載,如果只是更新了資源而沒(méi)有更新manifest文件的話(huà),瀏覽器并不會(huì)重新下載資源,也就是說(shuō)還是使用原來(lái)離線(xiàn)存儲(chǔ)的資源。

2.manifest文件進(jìn)行緩存的時(shí)候需要十分小心,因?yàn)榭赡艹霈F(xiàn)一種情況就是你對(duì)manifest文件進(jìn)行了更新,但是http的緩存規(guī)則告訴瀏覽器本地緩存的manifest文件還沒(méi)過(guò)期,這個(gè)情況下瀏覽器還是使用原來(lái)的manifest文件,所以對(duì)于manifest文件最好不要設(shè)置緩存。

3.如果更新中某個(gè)資源下載失敗,則整個(gè)更新就視作失敗,瀏覽器會(huì)依舊采用原來(lái)的資源

4.站點(diǎn)離線(xiàn)存儲(chǔ)的容量限制是5M

瀏覽器在下載manifest文件中的資源的時(shí)候,它會(huì)一次性下載所有資源,如果某個(gè)資源由于某種原因下載失敗,那么這次的所有更新就算是失敗的,瀏覽器還是會(huì)使用原來(lái)的資源。

window.applicationCache對(duì)象常用事件

1.   oncached:當(dāng)離線(xiàn)資源存儲(chǔ)完成之后觸發(fā)這個(gè)事件

2.   onchecking:當(dāng)瀏覽器對(duì)離線(xiàn)存儲(chǔ)資源進(jìn)行更新檢查的時(shí)候會(huì)觸發(fā)這個(gè)事件

3.   ondownloading:當(dāng)瀏覽器開(kāi)始下載離線(xiàn)資源的時(shí)候會(huì)觸發(fā)這個(gè)事件

4.   onprogress:當(dāng)瀏覽器在下載每一個(gè)資源的時(shí)候會(huì)觸發(fā)這個(gè)事件,每下載一個(gè)資源就會(huì)觸發(fā)一次。

5.   onupdateready:當(dāng)瀏覽器對(duì)離線(xiàn)資源更新完成之后會(huì)觸發(fā)這個(gè)事件

6.   onnoupdate:當(dāng)瀏覽器檢查更新之后發(fā)現(xiàn)沒(méi)有資源更新的時(shí)候觸發(fā)這個(gè)事件

最后一點(diǎn)是該特性已經(jīng)從web標(biāo)準(zhǔn)刪除,可能在未來(lái)某個(gè)時(shí)間停止,推薦使用Service Workers 代替。

藍(lán)藍(lán)設(shè)計(jì)sillybuy.com )是一家專(zhuān)注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶(hù)體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

移動(dòng)端列表索引效果

藍(lán)藍(lán)設(shè)計(jì)的小編

移動(dòng)端列表索引效果非常實(shí)用,比如:手機(jī)通訊錄。你可以根據(jù)字母來(lái)查找對(duì)應(yīng)的內(nèi)容。下面這個(gè)例子我是參考了 MUI 里的列表索引效果,寫(xiě)出來(lái)的代碼,代碼的結(jié)構(gòu)基本一樣,但功能會(huì)少一些,去掉了搜索框搜索,只有單純的字母索引,不過(guò)這也基本夠用了。這個(gè)效果是基于 jQuery 庫(kù)的,所以在用的時(shí)候就記得引入 jQuery 庫(kù)。

高質(zhì)量的UI設(shè)計(jì)學(xué)習(xí)路線(xiàn)

藍(lán)藍(lán)設(shè)計(jì)的小編

想學(xué)好ui設(shè)計(jì),好的學(xué)習(xí)資料當(dāng)然不能少,給大家UI設(shè)計(jì)課程大綱學(xué)習(xí)。

[EX]事件捕獲,事件冒泡,事件委托

seo達(dá)人

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

1事件流

JavaScript與HTML之間的交互是通過(guò)事件實(shí)現(xiàn)的。事件,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間??梢允褂脗陕?tīng)器來(lái)預(yù)訂事件,以便事件發(fā)生時(shí)執(zhí)行相應(yīng)的代碼。 
 
事件流的起源:就是在瀏覽器發(fā)展到第四代的時(shí)候,瀏覽器開(kāi)發(fā)團(tuán)隊(duì)遇到一個(gè)問(wèn)題:頁(yè)面的哪一部分會(huì)擁有某個(gè)特定的事件?要明白這個(gè)問(wèn)題問(wèn)的是什么,可以想象畫(huà)在一張紙上的一組同心圓。如果你把手指放在圓心上,那么你的手指指向的不是一個(gè)圓,而是紙上的所有圓。也就是說(shuō)如果單擊了頁(yè)面的某個(gè)按鈕,同時(shí)也單擊了按鈕的容器元素,甚至單擊了整個(gè)頁(yè)面。不過(guò)呢,IE提出的是冒泡流,而網(wǎng)景提出的是捕獲流。

示例:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件流</title> <style type="text/css"> #content{width: 150px;height: 150px;background-color: red;} #btn{width: 80px;height: 80px;background-color: green;} </style> </head> <body> <div id="content">content <div id="btn">button</div> </div> <script type="text/javascript"> var content = document.getElementById("content"); var btn = document.getElementById('btn');
        btn.onclick = function(){ alert("btn");
        };
        content.onclick = function(){ alert("content");
        };
        document.onclick = function(){ alert("document");
        } </script> </body> </html>
    
  • 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

如果點(diǎn)擊容器#btn,則彈出的順序是:btn-content-document;如果點(diǎn)擊的是容器#content,則彈出的是content-document;如果點(diǎn)擊的是document,彈出的是document。

由此可以看出JavaScript的事件流機(jī)制

前面說(shuō)過(guò),IE提出的是冒泡流,而網(wǎng)景提出的是捕獲流,后來(lái)在W3C組織的統(tǒng)一之下,JS支持了冒泡流和捕獲流,但是目前低版本的IE瀏覽器還是只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流),所以為了能夠兼容更多的瀏覽器,建議大家使用冒泡流。

JS事件流原理圖如下: 
 
這里寫(xiě)圖片描述 


2事件冒泡與事件捕獲

由此可以知道:

1、一個(gè)完整的JS事件流是從window開(kāi)始,最后回到window的一個(gè)過(guò)程

2、事件流被分為三個(gè)階段(1~5)捕獲過(guò)程、(5~6)目標(biāo)過(guò)程、(6~10)冒泡過(guò)程

示例:

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> #wrapDiv, #innerP, #textSpan{ margin: 5px;padding: 5px;box-sizing: border-box;cursor: default; } #wrapDiv{ width: 300px;height: 300px;border: indianred 3px solid; } #innerP{ width: 200px;height: 200px;border: hotpink 3px solid; } #textSpan{ display: block;width: 100px;height: 100px;border: orange 3px solid; } </style> </head> <body> <div id="wrapDiv">wrapDiv <p id="innerP">innerP <span id="textSpan">textSpan</span> </p> </div> <script> var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 捕獲階段綁定事件 window.addEventListener("click", function(e){ console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    document.addEventListener("click", function(e){ console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    document.documentElement.addEventListener("click", function(e){ console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    document.body.addEventListener("click", function(e){ console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    innerP.addEventListener("click", function(e){ console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);

    textSpan.addEventListener("click", function(e){ console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true); // 冒泡階段綁定的事件 window.addEventListener("click", function(e){ console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    document.addEventListener("click", function(e){ console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    document.documentElement.addEventListener("click", function(e){ console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    document.body.addEventListener("click", function(e){ console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    innerP.addEventListener("click", function(e){ console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);

    textSpan.addEventListener("click", function(e){ console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false); </script> </body> </html>
    
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91

這個(gè)時(shí)候,如果點(diǎn)擊一下textSpan這個(gè)元素,控制臺(tái)會(huì)打印出這樣的內(nèi)容: 
 
這里寫(xiě)圖片描述

從上面所畫(huà)的事件傳播的過(guò)程能夠看出來(lái),當(dāng)點(diǎn)擊鼠標(biāo)后,會(huì)先發(fā)生事件的捕獲

· 捕獲階段:首先window會(huì)獲捕獲到事件,之后document、documentElement、body會(huì)捕獲到,再之后就是在body中DOM元素一層一層的捕獲到事件,有wrapDiv、innerP。

· 目標(biāo)階段:真正點(diǎn)擊的元素textSpan的事件發(fā)生了兩次,因?yàn)樵谏厦娴腏avaScript代碼中,textSapn既在捕獲階段綁定了事件,又在冒泡階段綁定了事件,所以發(fā)生了兩次。但是這里有一點(diǎn)是需要注意,在目標(biāo)階段并不一定先發(fā)生在捕獲階段所綁定的事件,而是先綁定的事件發(fā)生,一會(huì)會(huì)解釋一下。

· 冒泡階段:會(huì)和捕獲階段相反的步驟將事件一步一步的冒泡到window

上述代碼中的兩個(gè)屬性:e.target和e.currentTarget

target和currentTarget都是event上面的屬性,target是真正發(fā)生事件的DOM元素,而currentTarget是當(dāng)前事件發(fā)生在哪個(gè)DOM元素上。

可以結(jié)合控制臺(tái)打印出來(lái)的信息理解下,目標(biāo)階段也就是 target == currentTarget的時(shí)候。我沒(méi)有打印它們兩個(gè)因?yàn)樘L(zhǎng)了,所以打印了它們的nodeName,但是由于window沒(méi)有nodeName這個(gè)屬性,所以是undefined。

那可能有一個(gè)疑問(wèn),我們不用addEventListener綁定的事件會(huì)發(fā)生在哪個(gè)階段呢,我們來(lái)一個(gè)測(cè)試,順便再演示一下我在上面的目標(biāo)階段所說(shuō)的目標(biāo)階段并不一定先發(fā)生捕獲階段所綁定的事件是怎么一回事。

<script>
    var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 測(cè)試直接綁定的事件到底發(fā)生在哪個(gè)階段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 測(cè)試直接綁定的事件到底發(fā)生在哪個(gè)階段")
    }; // 捕獲階段綁定事件
    window.addEventListener("click", function(e){
        console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.addEventListener("click", function(e){
        console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.body.addEventListener("click", function(e){
        console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); innerP.addEventListener("click", function(e){
        console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); textSpan.addEventListener("click", function(){
        console.log("textSpan 冒泡 在捕獲之前綁定的")
    }, false); textSpan.onclick = function(){
        console.log("textSpan onclick")
    }; textSpan.addEventListener("click", function(e){
        console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); // 冒泡階段綁定的事件
    window.addEventListener("click", function(e){
        console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.addEventListener("click", function(e){
        console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.body.addEventListener("click", function(e){
        console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); innerP.addEventListener("click", function(e){
        console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); textSpan.addEventListener("click", function(e){
        console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); </script>
    
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

控制臺(tái)打印如下:

這里寫(xiě)圖片描述

· textSpan是被點(diǎn)擊的元素,也就是目標(biāo)元素,所有在textSpan上綁定的事件都會(huì)發(fā)生在目標(biāo)階段,在綁定捕獲代碼之前寫(xiě)了綁定的冒泡階段的代碼,所以在目標(biāo)元素上就不會(huì)遵守先發(fā)生捕獲后發(fā)生冒泡這一規(guī)則,而是先綁定的事件先發(fā)生。 

[在目標(biāo)元素上就不會(huì)遵守先發(fā)生捕獲后發(fā)生冒泡這一規(guī)則,而是先綁定的事件先發(fā)生。]

· 由于wrapDiv不是目標(biāo)元素,所以它上面綁定的事件會(huì)遵守先發(fā)生捕獲后發(fā)生冒泡的規(guī)則。所以很明顯用onclick直接綁定的事件發(fā)生在了冒泡階段。


3事件綁定

1、直接獲取元素綁定:

element.onclick = function(e){
        // ... };
    
  • 1
  • 2
  • 3

優(yōu)點(diǎn):簡(jiǎn)單和穩(wěn)定,可以確保它在你使用的不同瀏覽器中運(yùn)作一致;處理事件時(shí),this關(guān)鍵字引用的是當(dāng)前元素,這很有幫助。

缺點(diǎn):只會(huì)在事件冒泡中運(yùn)行一個(gè)元素一次只能綁定一個(gè)事件處理函數(shù),新綁定的事件處理函數(shù)會(huì)覆蓋舊的事件處理函數(shù);事件對(duì)象參數(shù)(e)僅非IE瀏覽器可用。


2、直接在元素里面使用事件屬性

3、W3C方法:

element.addEventListener('click', function(e){
        // ... }, false);
    
  • 1
  • 2
  • 3

優(yōu)點(diǎn):該方法同時(shí)支持事件處理的捕獲和冒泡階段;事件階段取決于addEventListener最后的參數(shù)設(shè)置:false (冒泡) 或 true (捕獲);在事件處理函數(shù)內(nèi)部,this關(guān)鍵字引用當(dāng)前元素;事件對(duì)象總是可以通過(guò)處理函數(shù)的第一個(gè)參數(shù)(e)捕獲;可以為同一個(gè)元素綁定你所希望的多個(gè)事件,同時(shí)并不會(huì)覆蓋先前綁定的事件

缺點(diǎn):IE不支持,你必須使用IE的attachEvent函數(shù)替代。


IE下的方法:

element.attachEvent('onclick', function(){
        // ... });
    
  • 1
  • 2
  • 3

優(yōu)點(diǎn):可以為同一個(gè)元素綁定你所希望的多個(gè)事件,同時(shí)并不會(huì)覆蓋先前綁定的事件。 
 
缺點(diǎn):IE僅支持事件捕獲的冒泡階段;事件監(jiān)聽(tīng)函數(shù)內(nèi)的this關(guān)鍵字指向了window對(duì)象,而不是當(dāng)前元素(IE的一個(gè)巨大缺點(diǎn));事件對(duì)象僅存在與window.event參數(shù)中;事件必須以ontype的形式命名,比如,onclick而非click;僅IE可用,你必須在非IE瀏覽器中使用W3C的addEventListener。

注意:不是意味這低版本的ie沒(méi)有事件捕獲,它也是先發(fā)生事件捕獲,再發(fā)生事件冒泡,只不過(guò)這個(gè)過(guò)程無(wú)法通過(guò)程序控制。 


4解除事件

通用:

element.removeEventListener('click', function(e){
        // ... }, false);
    
  • 1
  • 2
  • 3

IE:

element.detachEvent('onclick', function(){
        // ... });
    
  • 1
  • 2
  • 3

5阻止事件傳播

在支持addEventListener()的瀏覽器中,可以調(diào)用事件對(duì)象的stopPropagation()方法以阻止事件的繼續(xù)傳播。如果在同一對(duì)象上定義了其他處理程序,剩下的處理程序?qū)⒁琅f被調(diào)用,但調(diào)用stopPropagation()之后任何其他對(duì)象上的事件處理程序?qū)⒉粫?huì)被調(diào)用。不僅可以阻止事件在冒泡階段的傳播,還能阻止事件在捕獲階段的傳播。

IE9之前的IE不支持stopPropagation()方法,而是設(shè)置事件對(duì)象cancelBubble屬性為true來(lái)實(shí)現(xiàn)阻止事件進(jìn)一步傳播。

<script>
    var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 測(cè)試直接綁定的事件到底發(fā)生在哪個(gè)階段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 測(cè)試直接綁定的事件到底發(fā)生在哪個(gè)階段")
    }; // 捕獲階段綁定事件
    window.addEventListener("click", function(e){
        console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.addEventListener("click", function(e){
        console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); document.body.addEventListener("click", function(e){
        console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName); // 在捕獲階段阻止事件的傳播
        e.stopPropagation(); }, true); innerP.addEventListener("click", function(e){
        console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); textSpan.addEventListener("click", function(){
        console.log("textSpan 冒泡 在捕獲之前綁定的")
    }, false); textSpan.onclick = function(){
        console.log("textSpan onclick")
    }; textSpan.addEventListener("click", function(e){
        console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName); }, true); // 冒泡階段綁定的事件
    window.addEventListener("click", function(e){
        console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.addEventListener("click", function(e){
        console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); document.body.addEventListener("click", function(e){
        console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); innerP.addEventListener("click", function(e){
        console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); textSpan.addEventListener("click", function(e){
        console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName); }, false); </script>
    
  • 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
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78

這里寫(xiě)圖片描述

實(shí)際上我們點(diǎn)擊的是textSpan,但是由于在捕獲階段事件就被阻止了傳播,所以在textSpan上綁定的事件根本就沒(méi)有發(fā)生,冒泡階段綁定的事件自然也不會(huì)發(fā)生,因?yàn)樽柚故录诓东@階段傳播的特性,e.stopPropagation()很少用到在捕獲階段去阻止事件的傳播,大家就以為e.stopPropagation()只能阻止事件在冒泡階段傳播。 


6阻止事件的默認(rèn)行為

e.preventDefault()可以阻止事件的默認(rèn)行為發(fā)生,默認(rèn)行為是指:點(diǎn)擊a標(biāo)簽就轉(zhuǎn)跳到其他頁(yè)面、拖拽一個(gè)圖片到瀏覽器會(huì)自動(dòng)打開(kāi)、點(diǎn)擊表單的提交按鈕會(huì)提交表單等等,因?yàn)橛械臅r(shí)候我們并不希望發(fā)生這些事情,所以需要阻止默認(rèn)行為。

IE9之前的IE中,可以通過(guò)設(shè)置事件對(duì)象的returnValue屬性為false達(dá)到同樣的效果。

function cancelHandler(event){ var event=event||window.event;//兼容IE //取消事件相關(guān)的默認(rèn)行為 if(event.preventDefault) //標(biāo)準(zhǔn)技術(shù) event.preventDefault(); if(event.returnValue) //兼容IE9之前的IE event.returnValue=false; return false; //用于處理使用對(duì)象屬性注冊(cè)的處理程序 }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

7事件委托

在JavaScript中,添加到頁(yè)面上的事件處理程序數(shù)量將直接關(guān)系到頁(yè)面的整體運(yùn)行性能。導(dǎo)致這一問(wèn)題的原因是多方面的。首先,每個(gè)函數(shù)都是對(duì)象,都會(huì)占用內(nèi)存;內(nèi)存中的對(duì)象越多,性能就越差。其次,必須事先指定所有事件處理程序而導(dǎo)致的DOM訪(fǎng)問(wèn)次數(shù),會(huì)延遲整個(gè)頁(yè)面的交互就緒時(shí)間。

對(duì)“事件處理程序過(guò)多”問(wèn)題的解決方案就是事件委托。事件委托利用了事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類(lèi)型的所有事件。例如,click事件會(huì)一直冒泡到document層次。也就是說(shuō),我們可以為整個(gè)頁(yè)面指定一個(gè)onclick事件處理程序,而不必給每個(gè)可單擊的元素分別添加事件處理程序。

在父級(jí)上定義了函數(shù),當(dāng)點(diǎn)擊目標(biāo)時(shí),會(huì)向上冒泡,到父級(jí)執(zhí)行操作。每一個(gè)子元素,都會(huì)統(tǒng)一冒泡到父級(jí)然后執(zhí)行。

<ul id="color-list"> <li>red</li> <li>yellow</li> <li>blue</li> <li>green</li> <li>black</li> <li>white</li> </ul>
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果點(diǎn)擊頁(yè)面中的li元素,然后輸出li當(dāng)中的顏色,我們通常會(huì)這樣寫(xiě):

(function(){
    var color_list = document.getElementById('color-list'); var colors = color_list.getElementsByTagName('li'); for(var i=0;i<colors.length;i++){ colors[i].addEventListener('click',showColor,false); }; function showColor(e){
        var x = e.target; alert("The color is " + x.innerHTML); }; })();
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

利用事件流的特性,我們只綁定一個(gè)事件處理函數(shù)也可以完成:

(function(){
    var color_list = document.getElementById('color-list'); color_list.addEventListener('click',showColor,false); function showColor(e){
        var x = e.target; if(x.nodeName.toLowerCase() === 'li'){
            alert('The color is ' + x.innerHTML); } } })();
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

事件委托還有一個(gè)好處就是添加進(jìn)來(lái)的元素也能綁定事件:

沒(méi)有使用事件委托:

<body> <ul id="thl"> <li>001</li> <li>002</li> <li>003</li> </ul> <button onclick="fun()">touch</button> <script> var thl= document.getElementById('thl'); var aLi = thl.getElementsByTagName('li'); for (var i = 0; i < aLi.length; i++) {
      aLi[i].onclick = fn;
    } function fn (){ console.log(this.innerHTML);
    } function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
        node.appendChild(textnode);
        document.getElementById("thl").appendChild(node);
    } </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

使用了事件委托:

<script> var thl= document.getElementById('thl');
    thl.onclick = function(ev) { ev = ev || event; //兼容處理 var target = ev.target || ev.srcElement; //找到li元素 if (target.nodeName.toLowerCase() == 'li') {
              console.log(target.innerHTML);
         }
    }; function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
        node.appendChild(textnode);
        document.getElementById("thl").appendChild(node);
    } </script>
藍(lán)藍(lán)設(shè)計(jì)sillybuy.com )是一家專(zhuān)注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供卓越的UI界面設(shè)計(jì)、BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶(hù)體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

日歷

鏈接

個(gè)人資料

存檔