首页

获取网页授权

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

在微信登录中,如何和获取网页授权。

一、登录微信测试公众品平台,修改网页授权基本信息,输入授权回调页面域名(自己的域名)。

然后重新建立一个tp框架 编写方法如图:

[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. }  

在自己的手机端访问,就能获取access_token;

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

设计是什么?为什么需要设计

蓝蓝设计的小编

设计不是简单的迎合消费者的需求,而是引导他们消费,不光是美化生活,更重要的是创造一种生活方式,与其说是设计一件产品,不如说是设计了一种生活方式。

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

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

三种方法的作用

在 JavaScript 中

  1. callapply 和 bind 是 Function 对象自带的三个方法,都是为了改变函数体内部 this 的指向。
  2. callapply 和 bind 三者第一个参数都是 this 要指向的对象,也就是想指定的上下文
  3. callapply 和 bind 三者都可以利用后续参数传参。
  4. bind 是返回对应 函数,便于稍后调用;apply 、call 则是立即调用 。
举个栗子
function fruits() {}

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

如果我们有一个对象 banana= {color : 'yellow'} ,我们不想重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法:

var banana = { color: 'yellow' };
apple.say.call(banana); // 此时的this的指向已经同过call()方法改变了,指向的是banana,this.color就是banana.color='yellow'; // 结果是My color is yellow 

apple.say.apply(banana); // 同理,此时的this的指向已经同过apply()方法改变了,指向的是banana,this.color就是banana.color ='yellow'; // 结果是My color is yellow

apple.say.apply(null); // nullwindow下的,此时,this 就指向了window ,但是window下并没有clolr这个属性,因此this.clolr就是window.color=undefined; // 结果是My color is undefined
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
call 和 apply 的区别

二者的作用完全一样,知识接受 参数 的方式不太一样。

call 是把参数按顺序传递进去,而 apply 则是把参数放在 数组 里面。

var array1 = [12,'foo',{name:'Joe'},-2458]; var array2 = ['Doe' , 555 , 100]; Array.prototype.push.call(array1, array2); // 这里用 call 第二个参数不会把 array2 当成一个数组,而是一个元素 // 等价于 array1.push("'Doe' , 555 , 100"); // array1.length=5; Array.prototype.push.apply(array1, array2); // 这里用 apply 第二个参数是一个数组 // 等价于:  array1.push('Doe' , 555 , 100); // array1.length=7;
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
类(伪)数组使用数组方法
var divElements = document.getElementsByTagName('div'); // 虽然 divElements 有 length 属性,但是他是一个伪数组,不能使用数组里面的方法 Array.isArray(divElements);// false var domNodes = Array.prototype.slice.call(document.getElementsByTagName('div')); // 将数组对象 Array 里的 this 指向伪数组 document.getElementsByTagName('div'),  // slice() 方法可从已有的数组中返回选定的元素,不传参数是,返回整个数组  Array.isArray(domNodes);// true
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
验证一个对象的类型可以用
Object.prototype.toString.call(obj)
    
  • 1
bind() 方法

bind() 方法会创建一个 新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入 bind() 方法的第一个参数 作为 this,传入 bind() 方法的 第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。

注意bind()方法创建的函数不会立即调用,在下面的例子中,最后 func() 才调用了函数,这是它与 callapply的区别。

var bar = function(){ console.log(this.x);
} var foo = {
    x:3 }
bar(); // undefined var func = bar.bind(foo); //此时this已经指向了foo,但是用bind()方法并不会立即执行,而是创建一个新函数,如果要直接调用的话 可以bar.bind(foo)() func(); // 3
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在 Javascript 中,多次 bind() 是无效的。更深层次的原因, bind() 的实现,相当于使用函数在内部包了一个 call / apply ,第二次 bind() 相当于再包住第一次 bind() ,故第二次以后的 bind 是无法生效的。

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设计师:程序员国宝,请你保持冷静,这是我的设计稿!

蓝蓝设计的小编

作为一名UI设计师,贼喜欢高一些非常炫酷的交互动效,而在导航设计中,有些设计更十分贴合这一点。

Flex布局-骰子demo

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

最近学习了Flex布局,

以下是阮一峰老师关于Flex的博客  。在此感谢他让我get一项新技能!

Flex语法篇:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html

Flex实战篇:http://www.ruanyifeng.com/blog/2015/07/flex-examples.html

1、色子数:1

思路:让圆点(即子元素)在横轴上居中在竖轴上居中,分别用justify-content和align-items

实现代码:

<!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、色子数:2

思路:竖列布局且在主轴方向采用justify-content的两端对齐布局,这样两个圆点会在左边呈现,然后采用align-items让其居中

实现代码:

<!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、色子数:3

思路:用到align-self属性让第二个和第三个圆点有自己的属性设置,分别在纵轴方向上居中和低端对齐

实现代码:

<!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、色子数:4

思路:先竖着放两行圆点,每行圆点里横着放两个圆点,所以最外层父元素设置align,里面的父元素设置justify-content

实现代码:

<!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、色子数:5

实现代码:

<!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、色子数:6

思路:跟四点的一样,先竖放三行在每行横放两个圆点

实现代码:

<!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>

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

设计视觉系统化,拒绝野路子

蓝蓝设计的小编

Facebook是一个连接全球数十亿人的社交工具。 面对这一视觉系统,设计师遇到了前所未有的挑战

虽然每个工具都能很好地履行其预期的功能,但它们并没有提供令人满意的整体经验。设计的UI模式,使用颜色和图像每个产品都是不同的。整体看起来不仅过时,而且与Facebook的这些专业人士在个人生活中使用也脱离联系。

我们希望制作出一致,令人满意的用户体验,值得我们的商业产品为公司和人们喜欢。我们还希望通过改进他们所依赖的工具来展示我们对这些业务的承诺。

HTML5应用程序缓存

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

HTML5引入了应用程序缓存,意味web应用可以进行缓存,在没有网络的情况下使用

应用程序缓存为应用带来的三大优势:

离线访问应用

速度更快——已缓存资源加载的更快

减少服务器负载——浏览器只从服务器下载更新过或更改过的资源

浏览器支持情况:主流浏览器都支持,IE要10以上的版本

HTML5通过在html文件添加manifest属性,启用应用程序缓存

例子:

<!DOCTYPE HTML>

<htmlmanifest="demo.appcache">

...

</html>

每个指定了 manifest 的页面在用户对其访问时都会被缓存。如果未指定 manifest 属性,则页面不会被缓存(除非在 manifest 文件中直接指定了该页面)。

manifest 文件的建议的文件扩展名是:".appcache"。

manifest 文件需要配置正确的 MIME-type,即 "text/cache-manifest"。必须在 web 服务器上进行配置。

Mainifest文件

manifest 文件是简单的文本文件,它告知浏览器被缓存的内容(以及不缓存的内容)。

例子:

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 写在manifest文件开头,是必须的

CACHE作用是标识出哪些文件需要缓存,可以是相对路径也可以是绝对路径

NETWORK可选,这一部分是要直接读取的文件,可以使用通配符 * 。

FALLBACK可选,指定了一个后备页面,当资源无法访问时,浏览器会使用该页面。

在线的情况下,浏览器发现html头部有manifest属性,会请求manifest文件,如果是第一次访问应用,浏览器就会根据manifest文件的内容下载相应的资源并且进行离线存储。如果已经访问过应用并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面,然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不做任何操作,如果文件改变了,那么就会重新下载文件中的资源并进行离线存储。

离线的情况下,浏览器就直接使用离线存储的资源。

注意:

1.服务器对离线的资源进行了更新,那么必须更新manifest文件之后这些资源才能被浏览器重新下载,如果只是更新了资源而没有更新manifest文件的话,浏览器并不会重新下载资源,也就是说还是使用原来离线存储的资源。

2.manifest文件进行缓存的时候需要十分小心,因为可能出现一种情况就是你对manifest文件进行了更新,但是http的缓存规则告诉浏览器本地缓存的manifest文件还没过期,这个情况下浏览器还是使用原来的manifest文件,所以对于manifest文件最好不要设置缓存。

3.如果更新中某个资源下载失败,则整个更新就视作失败,浏览器会依旧采用原来的资源

4.站点离线存储的容量限制是5M

浏览器在下载manifest文件中的资源的时候,它会一次性下载所有资源,如果某个资源由于某种原因下载失败,那么这次的所有更新就算是失败的,浏览器还是会使用原来的资源。

window.applicationCache对象常用事件

1.   oncached:当离线资源存储完成之后触发这个事件

2.   onchecking:当浏览器对离线存储资源进行更新检查的时候会触发这个事件

3.   ondownloading:当浏览器开始下载离线资源的时候会触发这个事件

4.   onprogress:当浏览器在下载每一个资源的时候会触发这个事件,每下载一个资源就会触发一次。

5.   onupdateready:当浏览器对离线资源更新完成之后会触发这个事件

6.   onnoupdate:当浏览器检查更新之后发现没有资源更新的时候触发这个事件

最后一点是该特性已经从web标准删除,可能在未来某个时间停止,推荐使用Service Workers 代替。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

移动端列表索引效果

蓝蓝设计的小编

移动端列表索引效果非常实用,比如:手机通讯录。你可以根据字母来查找对应的内容。下面这个例子我是参考了 MUI 里的列表索引效果,写出来的代码,代码的结构基本一样,但功能会少一些,去掉了搜索框搜索,只有单纯的字母索引,不过这也基本够用了。这个效果是基于 jQuery 库的,所以在用的时候就记得引入 jQuery 库。

高质量的UI设计学习路线

蓝蓝设计的小编

想学好ui设计,好的学习资料当然不能少,给大家UI设计课程大纲学习。

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

seo达人

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

1事件流

JavaScript与HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。可以使用侦听器来预订事件,以便事件发生时执行相应的代码。 
 
事件流的起源:就是在浏览器发展到第四代的时候,浏览器开发团队遇到一个问题:页面的哪一部分会拥有某个特定的事件?要明白这个问题问的是什么,可以想象画在一张纸上的一组同心圆。如果你把手指放在圆心上,那么你的手指指向的不是一个圆,而是纸上的所有圆。也就是说如果单击了页面的某个按钮,同时也单击了按钮的容器元素,甚至单击了整个页面。不过呢,IE提出的是冒泡流,而网景提出的是捕获流。

示例:

<!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

如果点击容器#btn,则弹出的顺序是:btn-content-document;如果点击的是容器#content,则弹出的是content-document;如果点击的是document,弹出的是document。

由此可以看出JavaScript的事件流机制

前面说过,IE提出的是冒泡流,而网景提出的是捕获流,后来在W3C组织的统一之下,JS支持了冒泡流和捕获流,但是目前低版本的IE浏览器还是只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流),所以为了能够兼容更多的浏览器,建议大家使用冒泡流。

JS事件流原理图如下: 
 
这里写图片描述 


2事件冒泡与事件捕获

由此可以知道:

1、一个完整的JS事件流是从window开始,最后回到window的一个过程

2、事件流被分为三个阶段(1~5)捕获过程、(5~6)目标过程、(6~10)冒泡过程

示例:

<!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

这个时候,如果点击一下textSpan这个元素,控制台会打印出这样的内容: 
 
这里写图片描述

从上面所画的事件传播的过程能够看出来,当点击鼠标后,会先发生事件的捕获

· 捕获阶段:首先window会获捕获到事件,之后document、documentElement、body会捕获到,再之后就是在body中DOM元素一层一层的捕获到事件,有wrapDiv、innerP。

· 目标阶段:真正点击的元素textSpan的事件发生了两次,因为在上面的JavaScript代码中,textSapn既在捕获阶段绑定了事件,又在冒泡阶段绑定了事件,所以发生了两次。但是这里有一点是需要注意,在目标阶段并不一定先发生在捕获阶段所绑定的事件,而是先绑定的事件发生,一会会解释一下。

· 冒泡阶段:会和捕获阶段相反的步骤将事件一步一步的冒泡到window

上述代码中的两个属性:e.target和e.currentTarget

target和currentTarget都是event上面的属性,target是真正发生事件的DOM元素,而currentTarget是当前事件发生在哪个DOM元素上。

可以结合控制台打印出来的信息理解下,目标阶段也就是 target == currentTarget的时候。我没有打印它们两个因为太长了,所以打印了它们的nodeName,但是由于window没有nodeName这个属性,所以是undefined。

那可能有一个疑问,我们不用addEventListener绑定的事件会发生在哪个阶段呢,我们来一个测试,顺便再演示一下我在上面的目标阶段所说的目标阶段并不一定先发生捕获阶段所绑定的事件是怎么一回事。

<script>
    var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 测试直接绑定的事件到底发生在哪个阶段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 测试直接绑定的事件到底发生在哪个阶段")
    }; // 捕获阶段绑定事件
    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

控制台打印如下:

这里写图片描述

· textSpan是被点击的元素,也就是目标元素,所有在textSpan上绑定的事件都会发生在目标阶段,在绑定捕获代码之前写了绑定的冒泡阶段的代码,所以在目标元素上就不会遵守先发生捕获后发生冒泡这一规则,而是先绑定的事件先发生。 

[在目标元素上就不会遵守先发生捕获后发生冒泡这一规则,而是先绑定的事件先发生。]

· 由于wrapDiv不是目标元素,所以它上面绑定的事件会遵守先发生捕获后发生冒泡的规则。所以很明显用onclick直接绑定的事件发生在了冒泡阶段。


3事件绑定

1、直接获取元素绑定:

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

优点:简单和稳定,可以确保它在你使用的不同浏览器中运作一致;处理事件时,this关键字引用的是当前元素,这很有帮助。

缺点:只会在事件冒泡中运行一个元素一次只能绑定一个事件处理函数,新绑定的事件处理函数会覆盖旧的事件处理函数;事件对象参数(e)仅非IE浏览器可用。


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

3、W3C方法:

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

优点:该方法同时支持事件处理的捕获和冒泡阶段;事件阶段取决于addEventListener最后的参数设置:false (冒泡) 或 true (捕获);在事件处理函数内部,this关键字引用当前元素;事件对象总是可以通过处理函数的第一个参数(e)捕获;可以为同一个元素绑定你所希望的多个事件,同时并不会覆盖先前绑定的事件

缺点:IE不支持,你必须使用IE的attachEvent函数替代。


IE下的方法:

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

优点:可以为同一个元素绑定你所希望的多个事件,同时并不会覆盖先前绑定的事件。 
 
缺点:IE仅支持事件捕获的冒泡阶段;事件监听函数内的this关键字指向了window对象,而不是当前元素(IE的一个巨大缺点);事件对象仅存在与window.event参数中;事件必须以ontype的形式命名,比如,onclick而非click;仅IE可用,你必须在非IE浏览器中使用W3C的addEventListener。

注意:不是意味这低版本的ie没有事件捕获,它也是先发生事件捕获,再发生事件冒泡,只不过这个过程无法通过程序控制。 


4解除事件

通用:

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

IE:

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

5阻止事件传播

在支持addEventListener()的浏览器中,可以调用事件对象的stopPropagation()方法以阻止事件的继续传播。如果在同一对象上定义了其他处理程序,剩下的处理程序将依旧被调用,但调用stopPropagation()之后任何其他对象上的事件处理程序将不会被调用。不仅可以阻止事件在冒泡阶段的传播,还能阻止事件在捕获阶段的传播。

IE9之前的IE不支持stopPropagation()方法,而是设置事件对象cancelBubble属性为true来实现阻止事件进一步传播。

<script>
    var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan"); // 测试直接绑定的事件到底发生在哪个阶段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 测试直接绑定的事件到底发生在哪个阶段")
    }; // 捕获阶段绑定事件
    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

这里写图片描述

实际上我们点击的是textSpan,但是由于在捕获阶段事件就被阻止了传播,所以在textSpan上绑定的事件根本就没有发生,冒泡阶段绑定的事件自然也不会发生,因为阻止事件在捕获阶段传播的特性,e.stopPropagation()很少用到在捕获阶段去阻止事件的传播,大家就以为e.stopPropagation()只能阻止事件在冒泡阶段传播。 


6阻止事件的默认行为

e.preventDefault()可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为。

IE9之前的IE中,可以通过设置事件对象的returnValue属性为false达到同样的效果。

function cancelHandler(event){ var event=event||window.event;//兼容IE //取消事件相关的默认行为 if(event.preventDefault) //标准技术 event.preventDefault(); if(event.returnValue) //兼容IE9之前的IE event.returnValue=false; return false; //用于处理使用对象属性注册的处理程序 }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

7事件委托

在JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪时间。

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click事件会一直冒泡到document层次。也就是说,我们可以为整个页面指定一个onclick事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。

在父级上定义了函数,当点击目标时,会向上冒泡,到父级执行操作。每一个子元素,都会统一冒泡到父级然后执行。

<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

如果点击页面中的li元素,然后输出li当中的颜色,我们通常会这样写:

(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

利用事件流的特性,我们只绑定一个事件处理函数也可以完成:

(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

事件委托还有一个好处就是添加进来的元素也能绑定事件:

没有使用事件委托:

<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>
蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档