JavaScript实现点击随机变色

kart 8年前
   <h2>事起缘由</h2>    <p>6月21日晚,古哥给咱们科普页面渲染机制、JS的一些性能优化和MV*架构,收益匪浅。在培训现场,古哥请船长当场用原生JS实现点击盒子随机变 色。船长的编程思路让人脑洞有点大开,Get到不少干货。借着这个例子,古哥不断灌输各种性能优化、浏览器兼容写法、代码整洁等概念。想不到一个如此简单 的例子竟有这么大的学问。于是培训归来当晚,当即打开电脑,把这个例子自己实现了一遍。于是便有了此文。</p>    <p>下面我来讲讲我是怎么做的。</p>    <h2>一. 首先搭好HTML结构和CSS样式</h2>    <pre>  <code class="language-html"><!DOCTYPE html>  <html>  <head>      <title>changeColor</title>      <style>          .colorBox {              width: 200px;              height: 200px;              margin: 20px;              background-color : rgb(100, 200, 100);              cursor: pointer;          }      </style>  </head>  <body>  <div id="colorBox" class="colorBox"></div>  </body>  </html>  </code></pre>    <p>接下来肯定是要用JS控制DOM元素啦。</p>    <h2>二. 创造随机颜色生成器</h2>    <p>首先,需要明确使用何种色彩模式。在HTML标准中,色彩模式有十六进制、RGB、HSL、RGBA、HSLA等。其中,HSL和HSLA不能兼容IE6-8。</p>    <h3>1. 创建随机数</h3>    <p>因为颜色是随机生成的,因此需要用到Math.random()函数。由于Math.random()生成0~1之间的随机数(包括0不包括1), 有时并不能满足我们的需求,因此可能需要乘除一个数。如果希望得到整数,需要对随机数进行取整,可用Math.ceil()【向上取整】或 Math.floor()【向下取整】或Math.round()【四舍五入】,或者paseInt()。</p>    <p>举个实用的栗子,如何获得两个数之间的随机数:</p>    <pre>  <code class="language-javascript">function getRandom(min, max) {      return Math.round(Math.random()*(max - min) + min);  }  </code></pre>    <p>Math.random()<em>(max – min) + min应该还是比较好理解的,用底数(min)加上随机偏移量(Math.random()</em>(max – min))就是随机数的大小。</p>    <p>为了使随机数看起来更随机一些,建议使用Math.round()。因为譬如使用Math.ceil()取整的话,min能被娶到的几率非常非常 小,只有Math.random()=0时才能取到。同理Math.floor()和paseInt()将永远也取不到max值。</p>    <p>当然,JavaScript中的随机数Math.random()并非真正意义上的随机,只能算“伪随机数”,这与它的产生算法有关,这里不展开讨论。不过Math.random()应付一般的不那么精准的项目中已经够用了。</p>    <h3>2. 创建随机颜色</h3>    <p>其实使用哪一种色彩模式的实现方式差不多,只是字符串的拼接结果不一样而已。</p>    <p><strong>(1) 使用十六进制色彩模式</strong></p>    <p>直接上代码:</p>    <pre>  <code class="language-javascript">function randomColor() {      // 这里使用十六进制颜色值      var colorArr = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"];      var colorVal = "#";      for(i = 0; i < 6; i++) {          colorVal += colorArr[Math.round(15*Math.random())];      }      return colorVal;  }  </code></pre>    <p><strong>(2) 使用RGB色彩模式</strong></p>    <p>直接上代码:</p>    <pre>  <code class="language-javascript">function randomColor() {      // 这里使用rgb颜色值      var colorVal = "rgb(";      for(i = 0; i < 3; i++) {            colorVal += Math.round(250*Math.random());          if (i < 2) {              colorVal += ",";          }      }      colorVal += ")";      return colorVal;  }  </code></pre>    <p>当然,你还可以使用rgba定义它的透明度。</p>    <p><strong>(3) 使用HSL色彩模式</strong></p>    <p>直接上代码:</p>    <pre>  <code class="language-javascript">function randomColor() {      // 这里使用HSL颜色值,但HSL不兼容IE6~8      // HSL(H, S, L),H的取值为0-360,S为0-100%,L为0-100%      // 在本例子中先设定好饱和度(S)和亮度(L),随机变化色相(H)      var colorVal,          S = "50%",          L = "50%";      colorVal = "HSL(" + Math.round(360*Math.random()) + "," + S + "," + L + ")";      return colorVal;  }  </code></pre>    <h3>3. 绑定样式修改</h3>    <p>这里需要修改盒子的background-color。我们可以直接操作<code><style></code>标签中的元素,不过最简单的当然是直接在html中标签的style属性啦。</p>    <pre>  <code class="language-javascript">this.style.backgroundColor = randomColor();  </code></pre>    <h3>4. 将使盒子变色的函数封装</h3>    <pre>  <code class="language-javascript">function changeColor() {      // 创造随机颜色      function randomColor() {          // ...      }      this.style.backgroundColor = randomColor();  }  </code></pre>    <h2>三. 给盒子绑定changeColor()事件</h2>    <h3>1. 获取DOM元素</h3>    <p>获取DOM元素的几种方法可以用document.getElementById()、document.getElementByName()、 document.getElementsByTagName()。当然还有高性能的document.querySelector(),并能兼容IE8 及其以上浏览器。</p>    <p>在这里,我使用原始的document.getElementById()。在一个页面中经常需要获取元素id的方法,所以可以考虑将其封装成函数。见下:</p>    <pre>  <code class="language-javascript">// 获取元素的id值  function getId(id) {      return document.getElementById(id);  }  </code></pre>    <h3>2. 对事件进行绑定</h3>    <p><strong>(1) 使用基于DOM对象的属性方式</strong></p>    <p>最让人容易想到的时间绑定方式就是ele.onclick = function(){},并且这种基于DOM对象的属性方式能轻易地兼容IE6及其以上浏览器,非常好用。</p>    <pre>  <code class="language-javascript">colorBox.onclick = function() {      changeColor();  }  </code></pre>    <p><strong>(2) 使用基于DOM对象的方法方式</strong><br> 绑定事件,addEventListener不能兼容IE6-8,因此IE6-8需要使用attachEvent,除了函数名、参数的不同,还有个关于 this指针的差异。在其它高版本浏览器中,绑定的事件处理函数被调用时,this指向事件绑定的object。而IE中,this指向window对 象,通过使用call或apply可以改变this指针的指向。</p>    <p>addEventListener语法:target.addEventListener(event, callback, useCapture);</p>    <p>attachEvent语法:target.attachEvent(event, fn);</p>    <p>另外,再来掰一掰addEventListener的事件流:</p>    <p>当一个事件发生时,分为三个阶段:</p>    <p>a.捕获阶段: 从根节点开始顺序而下,检测每个节点是否注册了事件处理程序。如果注册了事件处理程序,并且 useCapture 为 true,则调用该事件处理程序;(IE 中无此阶段);</p>    <p>b.目标阶段: 触发在目标对象本身注册的事件处理程序,也称正常事件派发阶段;</p>    <p>c.冒泡阶段: 从目标节点到根节点,检测每个节点是否注册了事件处理程序,如果注册了事件处理程序,并且 useCapture 为false,则调用该事件处理程序;</p>    <p>一般地,先判断使用addEventListener,后判断attachEvent。这是因为addEventListener能兼容IE9以上 和其他绝大多数浏览器,而attachEvent只适用于IE,一般用之兼容IE6~8,而IE6~8的用户较少,因此,应优先考虑先判断 addEventListener以减短JS的渲染路径,以达到绝大多数用户的更好体验。</p>    <pre>  <code class="language-javascript">// 事件绑定器  // 参数:target为DOM对象,event为事件名称(不带"on"),callback为接收事件处理的函数  function bindEvent(target, event, callback) {      if(window.addEventListener) {          return target.addEventListener(event, callback, false);      }else if(target.attachEvent) {          return target.attachEvent("on"+event, function() {              callback.apply(target);          });      }  }  </code></pre>    <h2>四. 调用</h2>    <p>在这之前,我已将使盒子变色的方法用changeColor()封装,并将构建了一个事件绑定器bindEvent()。</p>    <p>上面折腾了辣么多都还木有见到效果,别急~</p>    <p>最后当然是优雅的一键调用啦。哈哈哈哈~o(^▽^)o~</p>    <pre>  <code class="language-javascript">    var colorBox = getId("colorBox");      bindEvent(colorBox, "click", changeColor, false);  </code></pre>    <p>如果页面中还有其他盒子需要变色,只需要优雅地调用一下bindEvent()即可完成扩展。</p>    <h2>五. 性能优化</h2>    <p>1 . 可以使用自执行函数将代码块进行封装并创建伪命名空间,只要把自己所有的函数、对象和变量都写在这个闭包函数内,那么外部就不能访问,除非你允许。</p>    <p>2 . 在事件绑定中,古哥建议将事件绑定器用变量存储,那样每次调用事件绑定器时就不再需要重复判断。古哥写的事件绑定器代码如下:</p>    <pre>  <code class="language-javascript">var w3c = document.dispatchEvent;  var bind = w3c?function(target,type,handler,phrase){      target.addEventListener(type,handler,!!phrase);  } : function(target,type,handler){      target.attachEvent && target.attachEvent("on"+type,function(){          handler.apply(target);      })  }  bind(box,"click",handleClick);  </code></pre>    <p> </p>    <p>来自:http://www.dengzhr.com/js/424</p>    <p> </p>