整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          SVG優(yōu)雅顯示Email防止機(jī)器人竊取

          現(xiàn)實(shí)中,我們時(shí)常需要在網(wǎng)頁中展示你的聯(lián)系方式,其中Email郵件地址通常需要提供在頁面上。但是在網(wǎng)絡(luò)機(jī)器人泛濫的互聯(lián)中,如果直接顯示你郵件,則很可能被他們識(shí)別并拷貝,然后對(duì)你的郵件地址實(shí)施郵件轟炸。為了避免這個(gè)問題,需要利用技術(shù)手段來保護(hù)你的地址,使其只能被人眼看到,并且支持直接鏈接發(fā)送郵件,但是不能被網(wǎng)絡(luò)機(jī)器人識(shí)別到,一般常用的方法是通過JS,Html,CSS對(duì)地址隱藏,但是編寫代碼有點(diǎn)繁瑣,可能還要引入額外的JS庫才能實(shí)現(xiàn),而且還有一個(gè)缺點(diǎn)就是對(duì)一些限制級(jí)別的設(shè)備上,瀏覽器可能會(huì)禁用掉JS功能,這樣會(huì)導(dǎo)致頁面不能正常工作。此處給大家介紹一種基于SVG方法的郵件地址保護(hù)技術(shù),可以極大程度的保護(hù)你免受機(jī)器人騷擾以及保證在瀏覽器禁用JS情況下仍然可以正常工作。

          優(yōu)點(diǎn)

          在JavaScript禁用的情況下工作

          主要優(yōu)點(diǎn) 這種基于SVG的電子郵件保護(hù)方法沒有用的任何的JavaScript代碼。

          因此,即使訪問者瀏覽器禁用了JavaScript,頁面上顯示的電子郵件地址仍然可用、可訪問和受到保護(hù),同時(shí)保持安全并免受垃圾郵件機(jī)器人的攻擊。

          允許標(biāo)準(zhǔn)mailto:鏈接

          與其他不需要JavaScript的方法(例如,通過插入不可見的HTML注釋或插入可見元素并隨后通過CSS隱藏它們來混淆電子郵件地址)不同,這基于SVG的方法 允許標(biāo)準(zhǔn) mailto:鏈接。主要區(qū)別是:mailto:鏈接存在于外部 SVG文檔內(nèi)部,而不是 內(nèi)部引用的HTML文檔。

          像圖像一樣隱藏內(nèi)容,像文本一樣可復(fù)制

          第三個(gè)優(yōu)點(diǎn)是嵌入式SVG類似于圖像,但不是圖像。作為嵌入超文本文檔中的替換元素,SVG可以像圖像一樣有效地隱藏垃圾郵件地址的電子郵件地址。

          但嚴(yán)格來說,SVG是圖形文檔,而非實(shí)際圖像。

          因此,與圖像不同,人類訪問者仍然可以通過右鍵單擊電子郵件地址來復(fù)制電子郵件地址 <text>嵌入SVG中的元素。這對(duì)于傳統(tǒng)圖像方法來說,無法多做到手動(dòng)復(fù)制地址(但是可以使用圖像文本識(shí)別OCR技術(shù)來實(shí)現(xiàn))。

          基本方法

          我們以一個(gè)最簡單的Emil鏈接地址共享為例。示例中由兩個(gè)兩個(gè)文件組成:其中SVG圖形文檔通過<object>標(biāo)簽方式嵌入到主HTML頁面中,基本語法如下:

          <object data="svg-email-protection.svg" type="image/svg+xml" /></object>。

          注意,同一個(gè)SVG圖形文檔支持在多個(gè)地方,進(jìn)行嵌入。主頁面HTML(main.htm)源代碼如下,一個(gè)很簡單的頁面:

          <!DOCTYPE html>
          <html lang="en-GB">
          <head>
          <meta charset="utf-8">
          <title>SVG Email Protection</title>
          <style>
          .cc {
          width: 180px;
          height: 24px;
          vertical-align: middle;
          }
          </style>
          </head>
          <body>
          <p>請(qǐng)郵件聯(lián)系我: <object class="cc" data="svg-email-protection.svg" type="image/svg+xml"></object></p>
          </body>
          </html>

          SVG文檔(svgprot-chongchong)代碼:

          <svg xmlns="http://www.w3.org/2000/svg"
          lang="en-GB"
          aria-labelledby="title"
          viewBox="0 0 200 24">
          <title id="title"> SVG Email Protection</title>
          <defs>
          <style type="text/css"><![CDATA[
          rect {
          width: 200px;
          height: 24px;
          fill: rgb(255, 255, 255);
          }
          a:focus rect,
          rect:hover {
          rx: 4px;
          ry: 4px;
          fill: rgb(0, 0, 255);
          }
          text {
          font-size: 16px;
          fill: rgb(0, 0, 255);
          pointer-events: none;
          }
          a:focus text,
          rect:hover + text {
          fill: rgb(255, 255, 255);
          font-weight: 900;
          text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2);
          text-decoration: underline 1px solid rgb(255, 255, 255);
          text-underline-offset: 5px;
          }
          ]]></style>
          </defs>
          <a href="mailto:chongchong[at]ijz.me" aria-label="點(diǎn)擊發(fā)郵件">
          <rect />
          <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle"> chongchong[at]ijz.me</text>
          </a>
          </svg>

          將以上兩個(gè)文件放到同意目錄,然后用瀏覽器打開主頁面main.hm就可以看到效果了

          總結(jié)

          本文給大家介紹了一種基于SVG文檔的優(yōu)雅的郵件保護(hù)方法,可以極大的免受網(wǎng)絡(luò)機(jī)器人竊取你的郵件地址進(jìn)行騷擾攻擊,同時(shí)支持emailto鏈接,支持無JS瀏覽器下正常工作,支持手動(dòng)郵件復(fù)制等優(yōu)點(diǎn),當(dāng)然該方法也是只能抵擋一般性規(guī)模化工作的Web機(jī)器人攻擊,如果遇到高級(jí)機(jī)器人,比如可以模仿真人訪問行為的,可以分析語法找到SVG文件進(jìn)行獲取地址的高級(jí)機(jī)器人則無防御能力。

          內(nèi)容是《Web前端開發(fā)之Javascript視頻》的課件,請(qǐng)配合大師哥《Javascript》視頻課程學(xué)習(xí)。

          MouseEvent鼠標(biāo)事件:

          DOM2級(jí)事件中定義了7個(gè),DOM3級(jí)事件增加了2個(gè)鼠標(biāo)事件:

          • click:單擊或者回車(一般是左按鈕,可以通過鍵盤和鼠標(biāo)進(jìn)行);
          • dbclick:雙擊(從技術(shù)上說,這個(gè)事件不是DOM事件規(guī)范中規(guī)定);
          • mousedown:按下任意鼠標(biāo)鍵;
          • mouseup:釋放鼠標(biāo)按鈕時(shí)觸發(fā);
          • mousemove:在元素內(nèi)部移動(dòng)時(shí)重復(fù)地觸發(fā);
          • mouseover:當(dāng)鼠標(biāo)進(jìn)入元素時(shí)觸發(fā);
          • mouseout:在鼠標(biāo)光標(biāo)位于一個(gè)元素上方,再將其移入另一個(gè)元素時(shí)觸發(fā);又移入的另一個(gè)元素可能位于前一個(gè)元素的外部,也可能是這個(gè)元素的子元素;
          • mouseenter:在鼠標(biāo)光標(biāo)從元素外部首次移動(dòng)到元素范圍之內(nèi)時(shí)觸發(fā);類似于mouseover,但該事件不冒泡,而且在光標(biāo)移動(dòng)到后代元素上不會(huì)觸發(fā),該事件由IE引入,在DOM3級(jí)事件中被納入規(guī)范;
          • mouseleave:在位于元素上方的鼠標(biāo)光標(biāo)移動(dòng)到元素范圍之外時(shí)觸發(fā),類似于mouseout,但該事件不冒泡,而且在光移動(dòng)到后代元素上不會(huì)觸發(fā),該事件由IE引入,在DOM3級(jí)事件中被納入規(guī)范;
          • contextmenu:鼠標(biāo)右擊出現(xiàn)上下文菜單時(shí)觸發(fā),這個(gè)事件是在HTML5中定義的,其可以取消;

          鼠標(biāo)事件中還有一類滾輪事件,只包括一個(gè)mousewheel事件,但此事件已歸WheelEvent類了;

          document.addEventListener("click", function(event){
              console.log(event);  // MouseEvent
          },false);
          document.addEventListener("mousewheel", function(event){
              console.log(event);  // WheelEvent
          },false);

          可以檢測瀏覽器是否支持所有事件,如:

          var isSupported = document.implementation.hasFeature("MouseEvent", "3.0");

          頁面上的所有元素都支持鼠標(biāo)事件;除了mouseenter和mouseleave,其他所有鼠標(biāo)事件都會(huì)冒泡,也可以取消,而取消鼠標(biāo)事件將會(huì)影響瀏覽器的默認(rèn)行為,也會(huì)影響其他事件;

          click事件:

          在一個(gè)元素上被按下和放開時(shí),click事件就會(huì)被觸發(fā),包括鼠標(biāo)單擊(通常是左按鈕)或鍵盤回車,或者在腳本中為一個(gè)對(duì)象執(zhí)行了click()方法也會(huì)觸發(fā)該事件;

          var btn = document.getElementById("btn");
          btn.click();

          在一個(gè)focusable元素上單擊時(shí),該元素就獲得了焦點(diǎn),就會(huì)觸發(fā)focus事件和click事件;

          function handler(event){
          console.log(event.type);
          }
          var txt = document.getElementById("txt");
          txt.addEventListener("click", handler,false);
          txt.addEventListener("focus", handler,false);

          其觸發(fā)的順序?yàn)椋篺ocus、click;

          只有在同一個(gè)元素上相繼觸發(fā)mousedown和mouseup事件,才會(huì)觸發(fā)click事件;如果mousedown或mouseup中一個(gè)被取消,就不會(huì)觸發(fā)click事件,類似只有觸發(fā)兩次click事件才會(huì)觸發(fā)一次dbclick事件;

          這4個(gè)鼠標(biāo)事件觸發(fā)順序:
          mousedown –> mouseup –> click –> mousedown –> mouseup –> click –> dbclick;

          mouseover和mouseout事件:
          當(dāng)鼠標(biāo)進(jìn)入或移出元素時(shí)觸發(fā)這兩個(gè)事件;

          示例:鼠標(biāo)懸停改變表格行的背景色,如:

          <style>
          #mytable{width: 400px; border-collapse: collapse;}
          #mytable td{ height: 20px; border: 1px solid #000;}
          </style>
          <table id="mytable">
          <tr>
          <td></td> <td></td> <td></td>
          </tr>
          <!-- 多行 -->
          </table>
          <script>
          // 表格名稱、奇數(shù)行背景、偶數(shù)行背景、鼠標(biāo)經(jīng)過背景、點(diǎn)擊后背景
          function changeBg(table, oddColor, evenColor,overColor, clickColor){
          var rows = document.getElementById(table).rows;
          for(var i=0; i < rows.length; i++){
          var tr = rows[i];
          tr.style.backgroundColor = (tr.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
          tr.original = true;
          tr.addEventListener("click", function(event){
          if(this.original){
          this.original = false;
          this.style.backgroundColor = clickColor;
          }else{
          this.original = true;
          this.style.backgroundColor = (this.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
          }
          });
          tr.addEventListener("mouseover", function(){
          if(this.original)
          this.style.backgroundColor = overColor;
          });
          tr.addEventListener("mouseout", function(){
          if(this.original)
          this.style.backgroundColor = (this.sectionRowIndex % 2 == 0) ? oddColor : evenColor;
          });
          }
          }
          changeBg("mytable", "#FFF", "#ccc", "#cfc", "#f00");
          </script>

          mouseover和mouseout事件會(huì)冒泡,因此,當(dāng)觸發(fā)mouseout事件時(shí),有可能鼠標(biāo)真的離開了目標(biāo)元素,但也有可能是從這個(gè)元素移動(dòng)到它的子元素上,或者從一個(gè)子元素移動(dòng)到另一個(gè)子元素,所以在這種情況下,需要判斷鼠標(biāo)的確切位置;

          <div id="mydiv">
          <div id="div1">div1</div>
          <div id="div2">div2</div>
          </div>
          <script>
          var oDiv = document.getElementById("mydiv");
          oDiv.addEventListener("mouseover", function(event){
          console.log("mouseover:" + event.target.id);
          },false);
          oDiv.addEventListener("mouseout", function(event){
          console.log("mouseout:" + event.target.id);
          },false);
          </script>

          DOM3提供了兩個(gè)不冒泡的對(duì)應(yīng)版本mouseenter和mouseleave,如:

          oDiv.addEventListener("mouseenter", function(event){
          console.log("mouseenter:" + event.target.id);
          },false);
          oDiv.addEventListener("mouseleave", function(event){
          console.log("mouseleave:" + event.target.id);
          },false);

          示例:圖片遮罩,如:

          <style>
          *{margin:0; padding: 0;}
          ul,li{list-style: none;}
          ul{display:flex; flex-wrap: wrap;}
          li{width: 200px;}
          li>a{display: block; width: 100%; position: relative;}
          li img{width:200px;}
          </style>
          <ul id="mylist">
          <li><a href="#" title="天下第一山"><img src="images/1.jpg"></a></li>
          <li><a href="#" title="zeronetwork"><img src="images/2.jpg"></a></li>
          <li><a href="#" title="Javascript"><img src="images/3.jpg"></a></li>
          <li><a href="#" title="Web前端開發(fā)"><img src="images/4.jpg"></a></li>
          </ul>
          <script>
          window.onload = function(){
          var mylist = document.getElementById("mylist");
          var aList = mylist.getElementsByTagName("a");
          for(var i=0,len=aList.length; i<len; i++){
          var a = aList[i];
          var mask = null;
          a.addEventListener("mouseenter", function(event){
          mask = this.getElementsByClassName("mask")[0];
          if(!mask){
          mask = document.createElement("div");
          mask.className = "mask";
          }
          mask.style.backgroundColor = "rgba(0,0,0,0.8)";
          var computedStyle = document.defaultView.getComputedStyle(this, null);
          mask.style.width = computedStyle.width;
          mask.style.height = computedStyle.height;
          mask.style.position = "absolute";
          mask.style.color = "#FFF";
          mask.style.textAlign = "center";
          mask.style.lineHeight = computedStyle.height;
          mask.innerHTML = this.title;
          this.insertBefore(mask, this.firstChild);
          },false);
          a.addEventListener("mouseleave", function(event){
          var mask = this.getElementsByClassName("mask")[0];
          console.log(this);
          if(mask){
          this.removeChild(mask);
          }
          },false);
          }
          }
          </script>

          mouseleave和mouseenter事件的行為與CSS的:hover 偽類非常相似;

          mousemove事件,會(huì)頻繁觸發(fā),所以,在其事件處理程序中不能放置計(jì)算密集的任務(wù),或者使用事件節(jié)流的方式;

          鼠標(biāo)事件對(duì)象:

          鼠標(biāo)事件屬于MouseEvent類,該類指的是用戶與指針設(shè)備( 如鼠標(biāo) )交互時(shí)發(fā)生的事件,其繼承自UIEvent類;
          MouseEvent類定義了一組專屬于鼠標(biāo)事件的屬性,描述了當(dāng)事件發(fā)生時(shí)鼠標(biāo)的位置和按鍵的狀態(tài),也包含了是否有輔助鍵被按下等所有信息;

          客戶區(qū)坐標(biāo)位置:
          clientX與clientY屬性:取得鼠標(biāo)相對(duì)于瀏覽器視口的坐標(biāo)位置;

          var oDiv = document.getElementById("mydiv");
          EventUtil.addHandler(oDiv, "click", function(event){
          event = EventUtil.getEvent(event);
          console.log(event);
          console.log(event.clientX + "," + event.clientY);
          });

          注,這個(gè)位置不包括頁面滾動(dòng)的距離,如果加上窗口的滾動(dòng)偏移量,就會(huì)把鼠標(biāo)位置轉(zhuǎn)換成文檔坐標(biāo);
          所有瀏覽器也都實(shí)現(xiàn)了x和y屬性,其是clientX和clientY的別名;

          示例:計(jì)算鼠標(biāo)拖動(dòng)的直線距離,如:

          var obj = {};
          function downHandler(event){
          obj.x = event.x;
          obj.y = event.y;
          }
          function upHandler(event){
          obj.mx = event.x - obj.x;
          obj.my = event.y - obj.y;
          obj.d = Math.sqrt((Math.pow(obj.mx,2) + Math.pow(obj.my,2)));
          console.log(obj.mx, obj.my, obj.d);
          }
          document.addEventListener("mousedown", downHandler, false);
          document.addEventListener("mouseup", upHandler, false);

          示例:自定義鼠標(biāo)樣式,如:

          document.documentElement.style.cursor = "none";
          var cursor = document.createElement("span");
          cursor.style.width = "20px";
          cursor.style.height = "20px";
          cursor.style.position = "absolute";
          cursor.style.backgroundColor = "#000";
          document.body.appendChild(cursor);
          document.addEventListener("mousemove", function(event){
          cursor.style.left = event.clientX - cursor.offsetWidth / 2 + "px";
          cursor.style.top = event.clientY - cursor.offsetHeight / 2 + "px";
          },false);

          文檔坐標(biāo)位置:
          pageX和pageY屬性:取得鼠標(biāo)光標(biāo)在文檔中的位置;

          console.log(event.pageX + "," + event.pageY);

          這個(gè)位置是包括滾動(dòng)距離的,在文檔沒有滾動(dòng)的情況下,pageX、pageY與clientX、clientY值相等;
          IE8及以下不支持文檔坐標(biāo),不過使用客戶區(qū)坐標(biāo)和滾動(dòng)信息可以計(jì)算出來,也就是需要用到scrollLeft和scrollTop屬性,如:

          var oDiv = document.getElementById("mydiv");
          EventUtil.addHandler(oDiv, "click", function(event){
          event = EventUtil.getEvent(event);
          var pageX = event.pageX,
          pageY = event.pageY;
          if(pageX == undefined)
          pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
          if(pageY == undefined)
          pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
          console.log(pageX + ":" + pageY);
          });

          屏幕坐標(biāo)位置:screenX與screenY屬性:取得相對(duì)于屏幕的位置;

          console.log(event.screenX + ":" + event.screenY);

          元素坐標(biāo)位置:
          offsetX和offsetY屬性,返回與目標(biāo)元素(target)的內(nèi)填充邊(padding edge)在X和Y軸方向上的偏移量;坐標(biāo)原點(diǎn)為padding區(qū)左上角,因此,如果目標(biāo)元素有邊框,鼠標(biāo)的位置位于邊框上,該屬性值為負(fù)值;

          var oDiv = document.getElementById("mydiv");
          oDiv.style.position = "relative";
          oDiv.style.left = "100px";
          oDiv.style.top = "50px";
          document.addEventListener("click", function(event){
          console.log("offsetX:" + event.offsetX + ",offsetY:" + event.offsetY);
          },false);

          如果元素滾動(dòng)了,也包括offsetLeft和offsetTop值;

          示例:繪圖:

          <style>
          canvas{border: 1px solid;}
          </style>
          <canvas id="mydraw" width="560" height="360"></canvas>
          <script>
          var isDrawing = false;
          var x=0, y=0;
          var mydraw = document.getElementById("mydraw");
          var context = mydraw.getContext("2d");
          mydraw.addEventListener("mousedown", function(event){
          x = event.offsetX, y = event.offsetY;
          isDrawing = true;
          });
          mydraw.addEventListener("mousemove", function(event){
          if(isDrawing === true){
          drawLine(context, x, y, event.offsetX, event.offsetY);
          x = event.offsetX, y = event.offsetY;
          }
          });
          window.addEventListener("mouseup", function(event){
          if(isDrawing === true){
          drawLine(context, x, y, event.offsetX, event.offsetY);
          x = 0, y = 0;
          isDrawing = false;
          }
          });
          function drawLine(content, x1, y1, x2, y2){
          context.beginPath();
          context.strokeStyle = "black";
          context.lineWidth = 1;
          context.moveTo(x1, y1);
          context.lineTo(x2, y2);
          context.stroke();
          context.closePath();
          }
          </script>

          movementX和movementY屬性:

          返回當(dāng)前事件和上一個(gè)mousemove事件之間鼠標(biāo)在水平或垂直方向上的移動(dòng)值;

          即:currentEvent.movementX = currentEvent.screenX - previousEvent.screenX;

          currentEvent.movementY = currentEvent.screenY - previousEvent.screenY;
          document.addEventListener("mousemove", function(event){
          console.log(event.movementX);
          },false);

          但I(xiàn)E不支持,并且此屬性只有在mousemove事件中才能返回正確的值;

          輔助鍵:

          DOM規(guī)定了4個(gè)屬性:shiftkey、ctrlKey、altkey和metaKey,表示當(dāng)事件發(fā)生時(shí)shift、ctrl、alt和meta4個(gè)鍵的按下狀態(tài),均為布爾值,如果按下為true,反之為false;

          var btn = document.getElementById("btn");
          EventUtil.addHandler(btn, "click", handler);
          function handler(event){
          event = EventUtil.getEvent(event);
          var keys = new Array();
          if(event.shiftKey)
          keys.push("shift");
          if(event.altKey)
          keys.push("alt");
          if(event.ctrlKey)
          keys.push("ctrl");
          if(event.metaKey)
          keys.push("meta");
          console.log("keys:" + keys.join(","));
          }

          標(biāo)準(zhǔn)瀏覽器支持,但I(xiàn)E不支持metaKey屬性;

          getModifierState(key)方法:返回指定修飾鍵的當(dāng)前狀態(tài);
          參數(shù)key可以為Control、Alt、Shift和Meta,注意,大小寫是敏感的;

          btn.addEventListener("click", function(event){
          console.log(event.getModifierState("Control"));
          },false);

          relatedTarget相關(guān)元素:

          在發(fā)生mouseover和mouseout事件時(shí),會(huì)涉及到多個(gè)元素;對(duì)mouseover而言,事件的主目標(biāo)是獲得光標(biāo)的元素,而相關(guān)元素就是那個(gè)失去光標(biāo)的元素(這個(gè)相關(guān)元素也可以把它叫做次目標(biāo)元素);對(duì)mouseout事件而言,事件的主目標(biāo)是失去光標(biāo)的元素,而相關(guān)元素則是獲得光標(biāo)的元素;
          DOM通過event對(duì)象的relatedTarget屬性提供了相關(guān)元素的信息,該屬性只針于mouseover、mouseout、mouseenter、mouseleave、focusin、focusout、dragenter(拖動(dòng)元素進(jìn)入)事件時(shí)才有值;對(duì)于其他事件,該屬性為null;

          var oDiv = document.getElementById("mydiv");
          oDiv.addEventListener("mouseover", function(event){
          console.log(event);
          },false);
          oDiv.addEventListener("mouseout", function(event){
          console.log(event);
          },false);

          IE8及以下不支持relatedTarget屬性,但提供了保存著同樣信息不同的屬性,在mouseover事件觸發(fā)時(shí),fromElement屬性中保存了相關(guān)元素,toElement屬性為事件目標(biāo);在mouseout事件觸發(fā)時(shí),toElement屬性保存了相關(guān)元素,fromElement屬性為事件目標(biāo);

          document.addEventListener("mouseover", function(event){
          console.log(event.fromElement);
          console.log(event.toElement);
          },false);

          跨瀏覽器取得相關(guān)元素,添加到eventutil文件中;

          getRelatedTarget: function(event){
          if(event.relatedTaret)
          return event.relatedTaret;
          else if(event.toElement)
          return event.toElement;
          else if(event.fromElement)
          return event.fromElement;
          else
          return null;
          }

          應(yīng)用:

          var oDiv = document.getElementById("mydiv");
          EventUtil.addHandler(oDiv, "mouseout", function(event){
          event = EventUtil.getEvent(event);
          var target = EventUtil.getTarget(event);
          var relatedTarget = EventUtil.getRelatedTarget(event);
          console.log(relatedTarget);
          console.log(relatedTarget.tagName);
          })

          鼠標(biāo)按鈕:
          對(duì)于mousedown和mouseup事件來說,在其event對(duì)象存在一個(gè)button屬性,表示按下或釋放的哪個(gè)鼠標(biāo)按鈕;可能有3個(gè)值:0主按鈕;1中間按鈕鼠標(biāo)滾輪);2次按鈕;

          btn.addEventListener("mouseup", function(event){
          console.log(event.button);
          },false);

          IE8及以下也提供了button,但其值與DOM的button屬性有很大差異:0 沒有按下按鈕;1按下主按鈕;2次按鈕;3同時(shí)按下主次按鈕;4中間按鈕;5同時(shí)按下主和中間按鈕;6次和中間按鈕;7同時(shí)按下三個(gè);

          跨瀏覽器取得button屬性,在eventutil文件中添加:

          getButton: function(event){
          if(document.implementation.hasFeature("MouseEvents","2.0"))
          return event.button;
          else{
          switch(event.button){
          case 0:
          case 1:
          case 3:
          case 5:
          case 7:
          return 0;
          case 2:
          case 6:
          return 2;
          case 4:
          return 1;
          }
          }
          }

          buttons屬性:
          當(dāng)鼠標(biāo)事件觸發(fā)的時(shí),如果多個(gè)鼠標(biāo)按鈕被按下,將會(huì)返回一個(gè)或者多個(gè)代表鼠標(biāo)按鈕的位掩碼:

          • 0:沒有按鍵或者是沒有初始化;
          • 1:鼠標(biāo)左鍵;
          • 2:鼠標(biāo)右鍵;
          • 4:鼠標(biāo)滾輪或者是中鍵;
          • 8:第四按鍵 (通常是“瀏覽器后退”按鍵);
          • 16:第五按鍵 (通常是“瀏覽器前進(jìn)”);

          buttons的值為各鍵對(duì)應(yīng)值做按位與(+)計(jì)算后的值,例如,如果右鍵(2)和滾輪鍵(4)被同時(shí)按下,buttons的值為 2 + 4 = 6,如:

          btn.addEventListener("mousedown", function(event){
          console.log(event.button);
          console.log(event.buttons);
          },false);

          屬性button和buttons 是不同的,buttons可指示任意鼠標(biāo)事件中鼠標(biāo)的按鍵情況,而 button只能保證在由按下和釋放一個(gè)或多個(gè)按鍵時(shí)觸發(fā)的事件中獲得正確的值;

          which屬性:
          當(dāng)鼠標(biāo)事件觸發(fā)時(shí),表示被按下的按鈕,其返回特定按鍵的數(shù)字,0為無、1為左鍵、2為中間滾輪、3為右鍵;其是非標(biāo)準(zhǔn)屬性,但所有瀏覽器都支持;

          btn.addEventListener("mousedown", function(event){
          console.log(event.which);
          console.log(event.button);
          },false);

          注意,此時(shí)應(yīng)該注冊(cè)mousedown或mouseup事件而不是click事件,因?yàn)橛覔艋虬聪轮虚g滾動(dòng)不會(huì)觸發(fā)click事件;

          detail屬性:
          DOM2在event對(duì)象中提供了detail屬性,用于給出有關(guān)事件的更多信息;對(duì)于鼠標(biāo)click、mousedown和mouseup事件來說,detail中包含了一個(gè)數(shù)值,表示目標(biāo)元素被單擊了多少次,其它事件返回0;detail從1開始計(jì)數(shù),每次單擊都會(huì)遞增;

          console.log(event.detail);

          用此屬性就可以判斷用戶是單擊、雙擊還是三擊;如果鼠標(biāo)在mousedown和mouseup之間移動(dòng)了位置,則detail被重置為0;

          IE也通過下列屬性為鼠標(biāo)事件提供了更多信息:

          • altLeft :布爾值,是否按下了Alt,如果為true,則altKey的值也為true;
          • ctrlLeft:布爾值,是否按下了ctrl,如果為true,則ctrlKey的值也為true;
          • shiftLeft:布爾值,是否按下了shift,如果為true,則shiftKey的值也為true;

          這些屬性只有IE支持;

          示例:拖動(dòng)文檔元素,當(dāng)鼠標(biāo)按下或釋放時(shí),會(huì)觸發(fā)mousedown和mouseup事件,因此,通過這兩個(gè)事件,可以探測和響應(yīng)鼠標(biāo)的拖動(dòng);如:

          function drag(elementToDrag, event){
              var scroll = {x:0, y:0};
              var startX = event.clientX + scroll.x;
              var startY = event.clientY + scroll.y;
          
              var origX = elementToDrag.offsetLeft;
              var origY = elementToDrag.offsetTop;
          
              var deltaX = startX - origX;
              var deltaY = startY - origY;
          
              if(document.addEventListener){
              document.addEventListener("mousemove", moveHandler, true);
              document.addEventListener("mouseup", upHandler, true);
              }else if(document.attachEvent){
          
              elementToDrag.setCapture();
              elementToDrag.attachEvent("onmousemove", moveHandler);
              elementToDrag.attachEvent("onmouseup", upHandler);
              // 作為mouseup事件看待鼠標(biāo)捕獲的丟失
              elementToDrag.attachEvent("onlosecapture", upHandler);
              }
              // 處理了這個(gè)事件,不讓任何其他元素看到它
              if(event.stopPropagation)
              event.stopPropagation();
              else
              event.cancelBubble = true;
              // 現(xiàn)在阻止任何默認(rèn)操作
              if(event.preventDefault)
              event.preventDefault();
              else
              event.returnValue = false;
          
              // 當(dāng)元素正在被拖動(dòng)時(shí),這就是捕獲mousemove事件的處理程序
              // 它用于移動(dòng)這個(gè)元素
              function moveHandler(e){
              if(!e) e = window.event;
              // 移動(dòng)這個(gè)元素到當(dāng)前鼠標(biāo)位置
              // 通過滾動(dòng)條的位置和初始單擊的偏移量來調(diào)整
              // var scroll = getScrollOffsets();
              var scroll = {x:0,y:0};
              elementToDrag.style.left = (e.clientX + scroll.x - deltaX) + "px";
              elementToDrag.style.top = (e.clientY + scroll.y - deltaY) + "px";
              // 同時(shí)不讓任何其他元素看到這個(gè)事件
              if(e.stopPropagation)
              e.stopPropagation();
              else
              e.cancelBubble = true;
              }
              // 這是捕獲在拖動(dòng)結(jié)束時(shí)發(fā)生的最終mouseup事件的處理程序
              function upHandler(e){
              if(!e) e = window.event;
              // 注銷捕獲事件處理程序
              if(document.removeEventListener){
              document.removeEventListener("mouseup", upHandler, true);
              document.removeEventListener("mousemove", moveHandler, true);
              }else if(document.detachEvent){
              elementToDrag.detachEvent("onlosecapture", upHandler);
              elementToDrag.detachEvent("onmouseup", upHandler);
              elementToDrag.detachEvent("onmousemove", moveHandler);
              elementToDrag.releaseCapture();
              }
              // 并且不讓事件進(jìn)一步傳播
              if(e.stopPropagation)
              e.stopPropagation();
              else
              e.cancelBubble = true;
              }
          }

          應(yīng)用:

          <div style="position: absolute;left:100px;top:100px; width:150px;background-color: purple;">
          <div style="background-color: gray;" onmousedown="drag(this.parentNode, event);">標(biāo)題欄-拖動(dòng)我</div>
          <p>Lorem ...</p>
          </div>

          CSS的pointer-events屬性:

          指定在什么情況下 (如果有) 某個(gè)特定的元素可以成為鼠標(biāo)事件的target;主要用于 SVG元素;
          可能的值為:

          • auto:默認(rèn)效果,對(duì)于SVG內(nèi)容,該值與visiblePainted效果相同;
          • none:元素永遠(yuǎn)不會(huì)成為鼠標(biāo)事件的target;但是,當(dāng)其后代元素的pointer-events屬性指定其他值時(shí),鼠標(biāo)事件可以指向后代元素,在這種情況下,鼠標(biāo)事件將在捕獲或冒泡階段觸發(fā)父元素的事件偵聽器;
          • visiblePainted、visibleFill、visibleStroke、visible、painted、fill、stroke、all;

          該屬性可以:

          • 阻止用戶的點(diǎn)擊動(dòng)作產(chǎn)生任何效果;
          • 阻止缺省鼠標(biāo)指針的顯示;
          • 阻止CSS里的hover和active狀態(tài)的變化觸發(fā)事件;
          • 阻止JavaScript點(diǎn)擊動(dòng)作觸發(fā)的事件;
          <style>
          /* 鏈接不會(huì)跳轉(zhuǎn) */
          a[href="https://www.zeronetwork.cn/"]{
          pointer-events: none;
          }
          </style>
          <a href="https://www.zeronetwork.cn/">零點(diǎn)網(wǎng)絡(luò)</a>
          <script>
          var link = document.querySelector("a");
          function handler(event){
          console.log(event);
          }
          // 以下均無效
          link.addEventListener("click",handler,false);
          link.addEventListener("mouseover",handler,false);
          link.addEventListener("drag",handler,false);
          </script>

          此屬性可以通過控制臺(tái)改變,如在控制臺(tái)輸入:document.querySelector("a").style.pointerEvents = "auto";此時(shí),超鏈接就可以觸發(fā)了;

          <style>
          /* 使所有img對(duì)任何鼠標(biāo)事件(如拖動(dòng)、懸停、單擊等)無反應(yīng) */
          img{
          pointer-events: none;
          }
          </style>
          <img src="images/1.jpg" />
          <script>
          var img = document.querySelector("img");
          function handler(event){
          console.log(event);
          }
          // 以下均無效
          img.addEventListener("click",handler,false);
          img.addEventListener("mouseover",handler,false);
          img.addEventListener("drag",handler,false);
          </script>

          除了指示該元素不是鼠標(biāo)事件的目標(biāo)之外,值none表示鼠標(biāo)事件“穿透”該元素并且指定該元素“下面”的任何元素;如:

          <style>
          .container{position: relative; width: 200px; height: 150px;}
          .mask{width: 100%; height: 100%; background-color: rgba(0, 0, 0, .5);
          position: absolute; pointer-events: none; color:#FFF}
          .container img{width: 100%; height: 100%;}
          </style>
          <div class="container">
          <div class="mask"></div>
          <a href="https://www.zeronetwork.cn"><img src="images/1.jpg" /></a>
          </div>
          <script>
          var link = document.querySelector(".container>a");
          link.addEventListener("mouseover", function(event){
          var mask = event.currentTarget.parentNode.querySelector(".mask");
          mask.innerHTML = event.currentTarget.title;
          },false);
          link.addEventListener("mouseout", function(event){
          var mask = event.currentTarget.parentNode.querySelector(".mask");
          mask.innerHTML = "";
          },false);
          </script>

          示例:取得一個(gè)元素的相對(duì)鼠標(biāo)坐標(biāo),如:

          <style>
          .parent{ width:400px; height:400px; padding: 50px; margin:100px; background:#f20; }
          .child{ width:200px; height:200px; padding:50px; background:#ff0;}
          .child-child{ width:50px; height:50px; background:#00d;}
          </style>
          <div class="parent" id="parent">
          <div class="child">
          <div class="child-child"></div>
          </div>
          </div>
          <script>
          var parent = document.getElementById("parent");
          parent.addEventListener("click",function(event){
          console.info(event.offsetX);
          });
          </script>

          使用pointer-events屬性后再獲取,如為child和child-child類分別添加pointer-events屬性,此時(shí)打印的值就是相對(duì)于parent元素的坐標(biāo)了;

          使用pointer-events來阻止元素成為鼠標(biāo)事件目標(biāo)不一定意味著元素上的事件偵聽器永遠(yuǎn)不會(huì)觸發(fā),如果元素后代明確指定了pointer-events屬性并允許其成為鼠標(biāo)事件的目標(biāo),那么指向該元素的任何事件在事件傳播過CSS添加pointer-events:none,再為其子元素添加pointer-events:all,此時(shí)在子元素上單擊就可以觸發(fā)注冊(cè)在父元素上的事件處理程序;

          當(dāng)然,位于父元素但不在后代元素上的鼠標(biāo)活動(dòng)都不會(huì)被父元素和后代元素捕獲(鼠標(biāo)活動(dòng)將會(huì)穿過父元素而指向位于其下面的元素);

          var subchild = document.querySelector(".child-child");
          subchild.addEventListener("click",function(event){
          console.log("child-child");
          parent.style.pointerEvents = "auto";
          });

          該屬性也可用來提高滾動(dòng)時(shí)的幀頻;例如,當(dāng)頁面滾動(dòng)時(shí),如果恰巧鼠標(biāo)懸停在某些元素上,則會(huì)觸發(fā)其上的hover效果或觸發(fā)onmouseover事件,有可能會(huì)造成滾動(dòng)出現(xiàn)問題,此時(shí),如果對(duì)body元素應(yīng)用pointer-events:none,則會(huì)禁用了包括hover在內(nèi)的鼠標(biāo)事件,從而提高滾動(dòng)性能;

          <style>
          #mydiv:hover{
          background-color: lightgreen !important;
          }
          </style>
          <div id="mydiv" style="height: 300px;background-color: purple;"></div>
          <div style="height: 1000px;"></div>
          <script>
          var mydiv = document.getElementById("mydiv");
          mydiv.addEventListener("mouseover", function(event){
          console.log(event);
          },false);
          </script>

          滾動(dòng)頁面時(shí)觸發(fā)了mouseover事件及hover效果,可以在scroll事件中進(jìn)行相應(yīng)的處理,如:

          var timeoutId = null;
          window.addEventListener("scroll", function(event){
          document.body.style.pointerEvents = "none";
          if(timeoutId){
          clearTimeout(timeoutId);
          timeoutId = null;
          }else{
          timeoutId = setTimeout(function(){
          console.log("解禁了");
          document.body.style.pointerEvents = "auto";
          },500);
          }
          },false);

          部分瀏覽器不支持該屬性,可以判斷其支持情況,如:

          var supportsPointerEvents = (function(){
          var dummy = document.createElement("_");
          if(!('pointerEvents' in dummy.style))
          return false;
          dummy.style.pointerEvents = 'auto';
          // 如果是真的屬性,則賦值不成功
          dummy.style.pointerEvents = 'x';
          document.body.appendChild(dummy);
          var result = getComputedStyle(dummy).pointerEvents === 'auto';
          document.body.removeChild(dummy);
          return result;
          })();
          console.log(supportsPointerEvents);

          WheelEvent滾輪事件:

          當(dāng)用戶通過鼠標(biāo)滾輪與頁面交互,在垂直方向上滾動(dòng)頁面時(shí)(無論向上還是向下),就會(huì)觸發(fā)mousewheel事件;該事件可以在任何元素上觸發(fā),最終會(huì)冒泡到document或window對(duì)象,也可以阻止其默認(rèn)行為;

          document.addEventListener("mousewheel", function(event){
              console.log(event);  // WheelEvent
          },false);

          WheelEvent類:

          表示用戶滾動(dòng)鼠標(biāo)滾輪或類似輸入設(shè)備時(shí)觸發(fā)的事件,用以替代MouseWheelEvent和MouseScrollEvent,mousewheel實(shí)際上是屬于MouseWheelEvent類,而后面要講的Firefox中的DOMMouseScroll屬于MouseScrollEvent類,它們兩者都不屬于標(biāo)準(zhǔn),兼容性也不好,為了統(tǒng)一兩者,就出現(xiàn)了標(biāo)準(zhǔn)的WheelEvent類;

          WheelEvent類繼承自MouseEvent類(MouseEvent類繼承自UIEvent類),所有也可以把它看作是鼠標(biāo)事件,因此,對(duì)于WheelEvent事件對(duì)象來說,其中也保存著大量與MouseEvent事件同樣的屬性,例如,四對(duì)有關(guān)獲取坐標(biāo)的屬性、which(值為0)、relatedTarget(為null)等等;還包括輔助鍵的屬性;

          mousewheel事件中的event對(duì)象,除了保存鼠標(biāo)事件的所有標(biāo)準(zhǔn)信息外,還包含一個(gè)特殊的wheelDelta屬性,其指定用戶滾動(dòng)滾輪有多遠(yuǎn),當(dāng)用戶向前滾動(dòng)鼠標(biāo)滾輪時(shí),該屬性值是120的倍數(shù),當(dāng)向后滾動(dòng)時(shí),該值是-120的倍數(shù);

          EventUtil.addHandler(document, "mousewheel", function(event){
              event = EventUtil.getEvent(event);
              console.log(event);
              console.log(event.wheelDelta);
          })

          如果要判斷用戶滾動(dòng)的方向,只要檢測wheelDelta屬性的正負(fù)號(hào)即可;在Opera9.5之前的版本中,wheelDelta的值的正負(fù)號(hào)是顛倒的;

          除了wheelDelta屬性外,事件對(duì)象還有wheelDeltaX和wheelDeltaY屬性,并且wheelDelta和wheelDeltaY的值一直相同;

          console.log(event.wheelDelta);
          console.log(event.wheelDeltaY);
          console.log(event.wheelDeltaX);

          IE不支持這兩個(gè)屬性;
          Firefox不支持mousewheel事件,但支持一個(gè)名為DOMMouseScroll的類似事件,也是在鼠標(biāo)滾輪滾動(dòng)時(shí)觸發(fā),它也被視為鼠標(biāo)事件,也包含與鼠標(biāo)事件有關(guān)的所有鼠標(biāo);而有關(guān)鼠標(biāo)滾輪的信息則保存在detail屬性中,該屬性與wheelDelta作用相同;當(dāng)向前滾動(dòng)鼠標(biāo)滾輪時(shí),該屬性返回-3的位數(shù),反之返回3的位數(shù);

          可以把該事件添加到頁面中的任何元素,而且該事件會(huì)冒泡到window對(duì)象;

          EventUtil.addHandler(document, "DOMMouseScroll", function(event){
              event = EventUtil.getEvent(event);
              console.log(event);
              console.log(event.detail);  // 向前為-3,向后是3
          })

          detail屬性值與wheelDelta的值的關(guān)系是:wheelDelta等于detail乘以-40;

          可以跨瀏覽器取得鼠標(biāo)滾輪增值(delta),并添加到eventutil.js中,如:

              getWheelDelta: function(event){
                  if(event.wheelDelta){
                      return event.wheelDelta;
                  }else
                      return -event.detail * 40;
              }

          應(yīng)用時(shí),需要同時(shí)注冊(cè)mousewheel和DOMMouseScroll事件,如:

          function handlerMouseWheel(event){
              event = EventUtil.getEvent(event);
              var delta = EventUtil.getWheelDelta(event);
              console.log(delta);
          }
          EventUtil.addHandler(document, "mousewheel", handlerMouseWheel);
          EventUtil.addHandler(document, "DOMMouseScroll", handlerMouseWheel);

          另外,DOMMouseEvent事件對(duì)象中還有一個(gè)axis屬性,其返回一個(gè)long型常量值,表明鼠標(biāo)滾輪滾動(dòng)的方向,當(dāng)返回常量HORIZONTAL_AXIS,值為1時(shí),表示由鼠標(biāo)滾輪的橫向滾動(dòng)觸發(fā)的,當(dāng)返回VERTICAL_AXIS,值為2時(shí),表示是由鼠標(biāo)滾輪的縱向滾動(dòng)觸發(fā)的;

          wheel事件:
          DOM3事件定義了一個(gè)名為wheel事件,用于替代mousewheel和DOMMouseScroll事件;事件對(duì)象中保存著deltaX、deltaY及deltaZ屬性:用來獲取三個(gè)不同的鼠標(biāo)滾軸;大多數(shù)鼠標(biāo)滾輪是一維或二維的,所以并不能使用deltaZ屬性;

          EventUtil.addHandler(document, "wheel", function(event){
              event = EventUtil.getEvent(event);
              console.log(event);  // WheelEvent
              console.log(event.wheelDelta);  // -120
              console.log(event.wheelDeltaY);  // -120
              console.log(event.deltaX);  // -0
              console.log(event.deltaY);  // chrome返回100,F(xiàn)irefox返回63
              console.log(event.deltaZ);  // 0
          });

          這些值必須乘以-1.2,才和mousewheel事件的wheelDelta值和正負(fù)號(hào)相匹配;

          wheel事件對(duì)象還有一個(gè)deltaMode屬性,只讀,其返回long常量值,表示各delta*的值的單位,其值及所表示的單位如下:

          常量值描述

          • DOM_DELTA_PIXEL0x00滾動(dòng)量單位為像素
          • DOM_DELTA_LINE0x01滾動(dòng)量單位為行
          • DOM_DELTA_PAGE0x02滾動(dòng)量單位為頁
          console.log(event.deltaMode);

          示例:在Enclose.js文件中定義enclose()函數(shù),可以把一個(gè)圖片裝載到一個(gè)容器中,并且能移動(dòng)這個(gè)容器,也能改變?nèi)萜鞯拇笮。纾?/p>

          function enclose(content, framewidth, frameheight, contentX, contentY){
              // 這些參數(shù)不僅僅是初始值,它們保存當(dāng)前狀態(tài),能被mousewheel處理程序使用和修改
              framewidth = Math.max(framewidth, 50);
              frameheight = Math.max(frameheight, 50);
              contentX = Math.min(contentX, 0) || 0;
              contentY = Math.min(contentY, 0) || 0;
              // 創(chuàng)建frame元素,且設(shè)置CSS類和樣式
              var frame = document.createElement("div");
              frame.className = "enclose";
              frame.style.width = framewidth + "px";
              frame.style.height = frameheight + "px";
              frame.style.overflow = "hidden"; // 沒有滾動(dòng)條,不能溢出
              frame.style.boxSizing = "border-box"; // 能簡化調(diào)整frame大小的計(jì)算
              content.parentNode.insertBefore(frame, content);
              frame.appendChild(content);
              // 確定元素相對(duì)于frame的位置
              content.style.position = "relative";
              content.style.left = contentX + "px";
              content.style.top = contentY + "px";
              var isFirefox = (navigator.userAgent.indexOf('Gecko') != -1);
              // 注冊(cè)mousewheel事件處理程序
              frame.onwheel = wheelHandler;
              frame.onmousewheel = wheelHandler;
              if(isFirefox)
                  frame.addEventListener("DOMMouseScroll", wheelHandler, false);
              function wheelHandler(event){
                  var e = event || window.event;
                  var deltaX = e.deltaX / 3.33 || // wheel事件
                             e.wheelDeltaX / 4 || // mousewheel事件
                                             0    // 屬性未定義
                  var deltaY = e.deltaY / 3.33 || 
                             e.wheelDeltaY / 4 ||
              (e.wheelDeltaY === undefined &&     // 如果沒有2D屬性
                             e.wheelDelta / 4) || // 就使用1D的滾輪屬性
                               e.detail * -1.2 || // DOMMouseScroll事件
                                             0;   // 屬性未定義
                  if(isFirefox && e.type !== "DOMMouseScroll")
                      frame.removeEventListener("DOMMouseScroll", wheelHandler, false);
                  // 獲取內(nèi)容元素的當(dāng)前尺寸
                  var contentbox = content.getBoundingClientRect();
                  var contentwidth = contentbox.right - contentbox.left;
                  var contentheight = contentbox.bottom - contentbox.top;
                  // 如果按下Alt鍵,就可以調(diào)整frame大小
                  if(e.altKey){
                      if(deltaX){
                          framewidth -= deltaX; // 新寬度,但不能比內(nèi)容大
                          framewidth = Math.min(framewidth, contentwidth);
                          framewidth = Math.max(framewidth, 50); // 不能小于50
                          frame.style.width = framewidth + "px";
                      }
                      if(deltaY){
                          frameheight -= deltaY; 
                          frameheight = Math.min(frameheight, contentheight);
                          frameheight = Math.max(frameheight - deltaY, 50);
                          frame.style.height = frameheight + "px";
                      }
                  }else{ // 沒有按Alt鍵,就可以平移frame中的內(nèi)容
                      if(deltaX){
                          var minoffset = Math.min(framewidth - contentwidth, 0);
                          // 把deltaX添加到contentX中,但不能小于minoffset
                          contentX = Math.max(contentX + deltaX, minoffset);
                          contentX = Math.min(contentX, 0);
                          content.style.left = contentX + "px";
                      }
                      if(deltaY){
                          var minoffset = Math.min(frameheight - contentheight, 0);
                          contentY = Math.max(contentY + deltaY, minoffset);
                          contentY = Math.min(contentY, 0);
                          content.style.top = contentY + "px";
                      }
                  }
                  if(e.preventDefault)
                      e.preventDefault();
                  if(e.stopPropagation)
                      e.stopPropagation();
                  e.cancelBubble = true;
                  e.returnValue = false;
                  return false;
              }
          }

          應(yīng)用:

          <style>
          div.enclose{border: 10px solid; margin:10px}
          </style>
          <img id="content" src="images/1.jpg" />
          <script>
          window.onload = function(){
              enclose(document.getElementById("content"),400,200,-200,-300);
          }
          </script>

          不要混淆wheel事件和scroll事件:wheel事件的默認(rèn)動(dòng)作取決于瀏覽器實(shí)現(xiàn),因此wheel事件不一定會(huì)觸發(fā)scroll事件;即便滾輪事件引發(fā)了文檔內(nèi)容的滾動(dòng)行為,也不表示wheel事件中的delta*值恰好反映文檔內(nèi)容的滾動(dòng)方向;因此,不要依賴delta*屬性獲知文檔內(nèi)容的滾動(dòng)方向,可在文檔內(nèi)容滾動(dòng)事件中監(jiān)視target的scrollLeft和scrollTop的變化以推斷滾動(dòng)方向;

          VG 動(dòng)畫有很多種實(shí)現(xiàn)方法,也有很大SVG動(dòng)畫庫,現(xiàn)在我們就來介紹 svg動(dòng)畫實(shí)現(xiàn)方法都有哪些?

          一、SVG 的 animation

          SVG animation 有五大元素,他們控制著各種不同類型的動(dòng)畫,分別為:

          • set
          • animate
          • animateColor
          • animateTransform
          • animateMotion

          1.1、set

          set 為動(dòng)畫元素設(shè)置延遲,此元素是SVG中最簡單的動(dòng)畫元素,但是他并沒有動(dòng)畫效果。

          使用語法:

          <set attributeName="" attributeType="" to="" begin="" />
          • attributeName :是要改變的元素屬性名稱。
          • attributeType :是表明attributeName屬性值的列表,支持三個(gè)固定參數(shù) CSS/XML/auto,如x,y以及transform屬于XML,opacity屬于CSS。auto是瀏覽器自動(dòng)判別的意思,也是默認(rèn)值,如果你不知道該選哪個(gè)就填auto,瀏覽器自己判別。
          • to :動(dòng)畫結(jié)束的屬性值。
          • begin :動(dòng)畫延遲時(shí)間。

          eg:繪制一個(gè)半徑為200的圓,4秒之后,半徑變?yōu)?0。

          <svg width="320" height="320">
           <circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
            <set attributeName="r" attributeType="XML" to="50" begin="4s" />
           </circle>
          </svg>

          1.2、animate

          是基礎(chǔ)的動(dòng)畫元素,實(shí)現(xiàn)單屬性的過渡效果。

          使用語法:

          <animate 
           attributeName="r" 
           from="200" to="50" 
           begin="4s" dur="2s" 
           repeatCount="2"
          ></animate>
          • from :過渡效果的屬性開始值。
          • to:過渡效果的屬性結(jié)束值。
          • begin:動(dòng)畫開始時(shí)間。
          • dur:動(dòng)畫過渡時(shí)間,控制動(dòng)畫速度。
          • repeatCount:動(dòng)畫重復(fù)次數(shù)。

          eg:繪制一個(gè)半徑為200的圓,4秒之后半徑在2秒內(nèi)從200逐漸變?yōu)?0。

          <circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
           <animate attributeName="r" from="200" to="50" 
            begin="4s" dur="2s" repeatCount="2"></animate>
          </circle>

          1.3、animateColor

          控制顏色動(dòng)畫,animate也可以實(shí)現(xiàn)這個(gè)效果,所以該屬性目前已被廢棄。

          1.4、animateTransform

          實(shí)現(xiàn)transform變換動(dòng)畫效果,與css3的transform變換類似。實(shí)現(xiàn)平移、旋轉(zhuǎn)、縮放等效果。

          使用語法:

          <animateTransform attributeName="transform"  type="scale" 
           from="1.5" to="0" 
           begin="2s"  dur="3s" 
           repeatCount="indefinite"></animateTransform>
          • repeatCount:重復(fù)次數(shù),設(shè)置為 indefinite 表示無限循環(huán),一直執(zhí)行。
          • type:添加 transform 變換類型。
          • eg:繪制一個(gè)半徑為200的圓,4秒之后開始縮放,在2秒內(nèi)從1.5縮小到0倍。
          <svg width="320" height="320">
           <circle cx="0" cy="0" r="200" style="stroke: none; fill: #0000ff;">
            <animateTransform attributeName="transform" begin="4s"  
             dur="2s" type="scale" from="1.5" to="0" 
             repeatCount="indefinite"></animateTransform>
           </circle>
          </svg>

          1.5、animateMotion

          可以定義動(dòng)畫路徑,讓SVG各個(gè)圖形,沿著指定路徑運(yùn)動(dòng)。

          使用語法:

          <animateMotion 
           path="M 0 0 L 320 320" 
          begin="4s" dur="2s"></animateMotion>
          • path:定義路徑,使用語法與《HTML5(八)——SVG 之 path 詳解》path的d屬性一致。
          • begin:延遲時(shí)間。
          • dur:動(dòng)畫執(zhí)行時(shí)間。

          eg:繪制一個(gè)半徑為10的圓,延遲4秒從左上角運(yùn)動(dòng)的右下角。

          <svg width="320" height="320">
           <circle cx="0" cy="0" r="10" style="stroke: none; fill: #0000ff;">
            <animateMotion 
             path="M 0 0 L 320 320" 
             begin="4s" dur="2s"
             ></animateMotion>
           </circle>
          </svg>

          實(shí)際制作動(dòng)畫的時(shí)候,動(dòng)畫太單一不酷,需要同時(shí)改變多個(gè)屬性時(shí),上邊的四種元素可以互相組合,同類型的動(dòng)畫也能組合。以上這些元素雖然能夠?qū)崿F(xiàn)動(dòng)畫,但是無法動(dòng)態(tài)地添加事件,所以接下來我們就看看 js 如何制作動(dòng)畫。

          二、JavaScript 控制

          上篇文章我們介紹js可以操作path,同樣也可以操作SVG的內(nèi)置形狀元素,還可以給任意元素添加事件。

          給SVG元素添加事件方法與普通元素一樣,可以只用on+事件名 或者addEventListener添加。

          eg:使用SVG繪制地一條線,點(diǎn)擊線條地時(shí)候改變 x1 ,實(shí)現(xiàn)旋轉(zhuǎn)效果。

          <svg width="800" height="800" id="svg">
              <line id="line" x1="100" y1="100" 
              x2="400" y2="300" 
              stroke="black" stroke-width="5"></line>  
            </svg>
          <script>
           window.onload = function(){
            var line = document.getElementById("line")
            line.onclick = function(){
             let start = parseInt(line.getAttribute("x1")),
                 end=400,dis = start-end
             requestAnimationFrame(next)
             let count = 0;
             function next(){
              count++
              let a = count/200,cur = Math.abs(start+ dis*a)
              line.setAttribute('x1',cur)
              if(count<200)requestAnimationFrame(next)
             }
            }
           }
          </script>

          js制作的SVG動(dòng)畫,主要利用 requestAnimationFrame 來實(shí)現(xiàn)一幀一幀的改變。

          我們上述制作的 SVG 圖形、動(dòng)畫等,運(yùn)行在低版本IE中,發(fā)現(xiàn)SVG只有IE9以上才支持,低版本的并不能支持,為了兼容低版本瀏覽器,可以使用 VML ,VML需要添加額外東西,每個(gè)元素需要添加 v:元素,樣式中還需要添加 behavier ,經(jīng)常用于繪制地圖。由于使用太麻煩,所以我們借助 Raphael.js 庫。

          三、Rapha?l.js (拉斐爾)

          Raphael.js是通過SVG/VML+js實(shí)現(xiàn)跨瀏覽器的矢量圖形,在IE瀏覽器中使用VML,非IE瀏覽器使用SVG,類似于jquery,本質(zhì)還是一個(gè)javascript庫,使用簡單,容易上手。

          使用之前需要先引入Raphael.js庫文件。cdn的地址為:https://cdn.bootcdn.net/ajax/libs/raphael/2.3.0/raphael.js

          3.1、創(chuàng)建畫布

          Rapheal有兩種創(chuàng)建畫布的方式:

          第一種:瀏覽器窗口上創(chuàng)建畫布

          創(chuàng)建語法:

          var paper = Raphael(x,y,width,height)

          x,y是畫布左上角的坐標(biāo),此時(shí)畫布的位置是絕對(duì)定位,有可能會(huì)與其他html元素重疊。width、height是畫布的寬高。

          第二種:在一個(gè)元素中創(chuàng)建畫布

          創(chuàng)建語法:

          var paper = Raphael(element, width, height);

          element是元素節(jié)點(diǎn)本身或ID width、height是畫布的寬度和高度。

          3.2、繪制圖形

          畫布創(chuàng)建好之后,該對(duì)象自帶SVG內(nèi)置圖形有矩形、圓形、橢圓形。他們的方法分別為:

          paper.circle(cx, cy, r); // (cx , cy)圓心坐標(biāo) r 半徑
          paper.rect(x, y, width, height, r); // (x,y)左上角坐標(biāo) width寬度 height高度 r圓角半徑(可選)
          paper. ellipse(cx, cy, rx, ry); // (cx , cy)圓心坐標(biāo) rx水平半徑 ry垂直半徑

          eg:在div中繪制一個(gè)圓形,一個(gè)橢圓、一個(gè)矩形。

          <div id="box"></div>
          <script>
           var paper = Raphael("box",300,300)
           paper.circle(150,150,150)
           paper.rect(0,0,300,300)
           paper.ellipse(150,150,100,150)
          </script>

          運(yùn)行結(jié)果如下:

          除了簡單圖形之外,還可以繪制復(fù)雜圖形,如三角形、心型,這時(shí)就使用path方法。

          使用語法:paper.path(pathString)

          pathString是由一個(gè)或多個(gè)命令組成,每個(gè)命令以字母開始,多個(gè)參數(shù)是由逗號(hào)分隔。

          eg:繪制一個(gè)三角形。

          let sj = paper.path("M 0,0 L100,100 L100,0 'Z'")

          還可以繪制文字,如果需要換行,使用 \n 。

          文字語法:paper.text(x,y,text)

          (x,y)是文字坐標(biāo),text是要繪制的文字。

          3.3、設(shè)置屬性

          圖形繪制之后,我們通常會(huì)添加stroke、fill、stroke-width等讓圖形更美觀,Raphael使用attr給圖形設(shè)置屬性。

          使用語法:circle.attr({"屬性名","屬性值","屬性名","屬性值",...})

          如果只有屬性名沒有屬性值,則是獲取屬性,如果有屬性值,則是設(shè)置屬性。

          注意:如果只設(shè)置一個(gè)屬性時(shí),可以省略‘{}’。如:rect.attr('fill','pink')

          eg:給上邊的矩形添加邊框和背景色。

          <div id="box"></div>
          <script>
           var paper = Raphael("box",300,300)
           let rect = paper.rect(100,100,150,200)
           rect.attr({'fill':'red','stroke':'blue','stroke-width':'10'})
          </script>

          3.4、添加事件

          RaphaelJS一般具有以下事件:
          click、dblclick、drag、hide、hover、mousedown、mouseout、mouseup、mouseover等以及對(duì)應(yīng)的解除事件,只要在前面加上“un”就可以了(unclick、undblclick)。

          使用語法:

          obj.click(function(){
           //需要操作的內(nèi)容
          })

          3.5、添加動(dòng)畫

          animate為指定圖形添加動(dòng)畫并執(zhí)行。

          使用語法:

          obj.animate({
           "屬性名1":屬性值1,
           "屬性名2":屬性值2,
            ...
          },time,type)

          屬性名和屬性值就根據(jù)你想要的動(dòng)畫類型加就ok。

          time:動(dòng)畫所需時(shí)間。

          type:指動(dòng)畫緩動(dòng)類型。常用值有:

          • linear - 線性漸變
          • ease-in | easeIn | < - 由慢到快
          • ease-out | easeOut | > - 由快到慢
          • ease-in-out | easeInOut | <> - 由慢到快再到慢
          • back-in | backIn - 開始時(shí)回彈
          • back-out | backOut - 結(jié)束時(shí)回彈
          • elastic - 橡皮筋
          • bounce - 彈跳

          eg:點(diǎn)擊矩形,矩形緩緩變大。

          <div id="box"></div>
          <script>
           var paper = Raphael("box",800,500)
           let rect = paper.rect(100,100,150,100)
           rect.attr({'fill':'red','stroke':'blue','stroke-width':'10'})
           rect.attr('fill','pink')
           rect.click(function(){
            rect.animate({
             "width":300,
             "height":300
            },1000,"bounce")
           })
          </script>

          復(fù)制上邊的代碼,分別在各個(gè)瀏覽器和低版本IE瀏覽器運(yùn)行,發(fā)現(xiàn)都可以正常運(yùn)行。SVG的動(dòng)畫庫挺多了,我們介紹了拉斐爾,有興趣的小伙伴可以自行找找其他庫。


          主站蜘蛛池模板: 国产乱码一区二区三区爽爽爽| 中文字幕一区二区三区有限公司| 亚洲国模精品一区| 中文字幕一区在线播放| 日韩伦理一区二区| 亚洲午夜精品一区二区麻豆 | 青青青国产精品一区二区| 亚洲乱色熟女一区二区三区丝袜| 国产成人片视频一区二区| 美女AV一区二区三区| 夜色阁亚洲一区二区三区| 久久亚洲色一区二区三区| 久久精品国产一区二区三区| 日韩一区二区精品观看| 一区二区三区四区在线视频| 久久99久久无码毛片一区二区| 亚洲线精品一区二区三区| 国模丽丽啪啪一区二区| 麻豆国产一区二区在线观看| 国产乱人伦精品一区二区在线观看| 日韩精品免费一区二区三区| 精品伦精品一区二区三区视频| 一区二区三区四区视频| 精品国产一区二区三区AV| 国产在线一区二区三区在线| 国产另类TS人妖一区二区| 国产99久久精品一区二区| 国产成人av一区二区三区在线| 精品国产香蕉伊思人在线在线亚洲一区二区 | 中文字幕日韩一区二区三区不| 国产一区二区免费视频| 九九无码人妻一区二区三区| 国产一区二区三区久久精品| 老鸭窝毛片一区二区三区| 久久久精品人妻一区二区三区蜜桃| 日本免费一区二区三区最新vr| 人妻少妇精品视频一区二区三区| 日本无码一区二区三区白峰美 | 肥臀熟女一区二区三区| 久久久久久人妻一区二区三区| 日韩精品一区二区三区大桥未久|