整合營銷服務(wù)商

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

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

          純JavaScript實(shí)現(xiàn)HTML5 Canvas 6種特效濾鏡

          者:前端Q

          轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/ewFfXptccFs5KvjUINLGbQ

          前端

          小試牛刀,實(shí)現(xiàn)了六款簡(jiǎn)單常見HTML5 Canvas特效濾鏡,并且封裝成一個(gè)純JavaScript可調(diào)用的API文件gloomyfishfilter.js。支持的特效濾鏡分別為:

          1.反色

          2.灰色調(diào)

          3.模糊

          4.浮雕

          5.雕刻

          6.合理

          濾鏡原理解釋:

          2.灰色調(diào):獲取一個(gè)預(yù)期點(diǎn)RGB值r,g,b則新的RGB值

          newr =(r * 0.272)+(g * 0.534)+(b * 0.131);

          newg =(r * 0.349)+(g * 0.686)+(b * 0.168);

          newb =(r * 0.393)+(g * 0.769)+(b * 0.189);

          3.模糊:基于一個(gè)5 * 5的卷積核

          4.浮雕與雕刻:

          根據(jù)當(dāng)前預(yù)期的前一個(gè)預(yù)期RGB值與它的后一個(gè)重新的RGB值之差再加上128

          5.總體:模擬了物體在鏡子中與之對(duì)應(yīng)的效果。

          雜項(xiàng)準(zhǔn)備

          1、如何獲取Canvas 2d context對(duì)象

          var canvas = document.getElementById("target");
          
          canvas.width = source.clientWidth;
          
          canvas.height = source.clientHeight;
          
          **if**(!canvas.getContext) {
          
             console.log("Canvas not supported. Please install a HTML5compatible browser.");
          
             **return**;
          
          }
          
          // get 2D context of canvas and draw image
          
          tempContext = canvas.getContext("2d");

          2、如何添加一個(gè)DOM img對(duì)象到Canvas對(duì)象中

          var source = document.getElementById("source");
          
          tempContext.drawImage(source, 0, 0, canvas.width,canvas.height);

          3、如何從Canvas對(duì)象中獲取預(yù)定數(shù)據(jù)

          var canvas = document.getElementById("target");
          
          var len = canvas.width * canvas.height * 4;
          
          var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          
          var binaryData = canvasData.data;

          4、如何對(duì)DOM對(duì)象實(shí)現(xiàn)鼠標(biāo)ClickEvent綁定

          function bindButtonEvent(element, type, handler) 
          {  
          
          if(element.addEventListener){ 
          
                element.addEventListener(type, handler,**false**); 
          
             }else{ 
          
                element.attachEvent('on'+type, handler);// for IE6,7,8
          
             } 
          
          }

          5、如何調(diào)用實(shí)現(xiàn)的gfilter API完成濾鏡功能

          <scriptsrc=*"gloomyfishfilter.js"*></script> //導(dǎo)入API文件
          
          gfilter.colorInvertProcess(binaryData, len); //調(diào)用 API

          6、瀏覽器支持:IE,F(xiàn)F,Chrome上測(cè)試通過,其中IE上支持通過以下標(biāo)簽實(shí)現(xiàn):

          <meta http-equiv="X-UA-Compatible"*content=*"chrome=IE8"> 


          效果演示:

          應(yīng)用程序源代碼:

          CSS部分:

          #svgContainer {
            width:800px;
            height:600px;
            background-color:#EEEEEE;
          }
          
          #sourceDiv { float: left; border: 2px solid blue} 
          #targetDiv { float: right;border: 2px solid red}

          filter1.html中HTML源代碼:

          <!DOCTYPE html>
          <html>
          <head>
          <meta http-equiv="X-UA-Compatible" content="chrome=IE8">
          <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
          <title>Canvas Filter Demo</title>
          <link href="default.css" rel="stylesheet" />
          <script src="gloomyfishfilter.js"></scrip>
          </head>
          <body>
            <h1>HTML Canvas Image Process - By Gloomy Fish</h1>
            <div id="svgContainer">
              <div id="sourceDiv">
                <img id="source" src="../test.png" />
              </div>
              <div id="targetDiv">
                <canvas id="target"></canvas>
              </div>
            </div>
            <div id="btn-group">
              <button type="button" id="invert-button">反色</button>
              <button type="button" id="adjust-button">灰色調(diào)</button>
              <button type="button" id="blur-button">模糊</button>
              <button type="button" id="relief-button">浮雕</button>
              <button type="button" id="diaoke-button">雕刻</button>
              <button type="button" id="mirror-button">鏡像</button>
            </div>
          </body>
          </html>

          filter1.html中JavaScript源代碼:

          var tempContext = null; // global variable 2d context
              window.onload = function() {
                var source = document.getElementById("source");
                var canvas = document.getElementById("target");
                canvas.width = source.clientWidth;
                canvas.height = source.clientHeight;
          
                if (!canvas.getContext) {
                    console.log("Canvas not supported. Please install a HTML5 compatible browser.");
                    return;
                }
          
                // get 2D context of canvas and draw image
                tempContext = canvas.getContext("2d");
                tempContext.drawImage(source, 0, 0, canvas.width, canvas.height);
          
                    // initialization actions
                    var inButton = document.getElementById("invert-button");
                    var adButton = document.getElementById("adjust-button");
                    var blurButton = document.getElementById("blur-button");
                    var reButton = document.getElementById("relief-button");
                    var dkButton = document.getElementById("diaoke-button");
                    var mirrorButton = document.getElementById("mirror-button");
          
                    // bind mouse click event
                    bindButtonEvent(inButton, "click", invertColor);
                    bindButtonEvent(adButton, "click", adjustColor);
                    bindButtonEvent(blurButton, "click", blurImage);
                    bindButtonEvent(reButton, "click", fudiaoImage);
                    bindButtonEvent(dkButton, "click", kediaoImage);
                    bindButtonEvent(mirrorButton, "click", mirrorImage);
              }
          
              function bindButtonEvent(element, type, handler)  
          {  
                if(element.addEventListener) {  
                   element.addEventListener(type, handler, false);  
                } else {  
                   element.attachEvent('on'+type, handler); // for IE6,7,8
                }  
              }  
          
              function invertColor() {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
                var binaryData = canvasData.data;
          
                    // Processing all the pixels
                    gfilter.colorInvertProcess(binaryData, len);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }
          
              function adjustColor() {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
                    var binaryData = canvasData.data;
          
                    // Processing all the pixels
                    gfilter.colorAdjustProcess(binaryData, len);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }
          
              function blurImage() 
          {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          
                    // Processing all the pixels
                    gfilter.blurProcess(tempContext, canvasData);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }
          
              function fudiaoImage() 
          {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          
                    // Processing all the pixels
                    gfilter.reliefProcess(tempContext, canvasData);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }
          
              function kediaoImage() 
          {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          
                    // Processing all the pixels
                    gfilter.diaokeProcess(tempContext, canvasData);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }
          
              function mirrorImage() 
          {
                var canvas = document.getElementById("target");
                var len = canvas.width * canvas.height * 4;
                var canvasData = tempContext.getImageData(0, 0, canvas.width, canvas.height);
          
                    // Processing all the pixels
                    gfilter.mirrorProcess(tempContext, canvasData);
          
                    // Copying back canvas data to canvas
                    tempContext.putImageData(canvasData, 0, 0);
              }

          濾鏡源代碼(gloomyfishfilter.js):

          var gfilter = {
              type: "canvas",
              name: "filters",
              author: "zhigang",
              getInfo: function () {
                  return this.author + ' ' + this.type + ' ' + this.name;
              },
          
              /**
               * invert color value of pixel, new pixel = RGB(255-r, 255-g, 255 - b)
               * 
               * @param binaryData - canvas's imagedata.data
               * @param l - length of data (width * height of image data)
               */
             colorInvertProcess: function(binaryData, l) {
              for (var i = 0; i < l; i += 4) {
                    var r = binaryData[i];
                    var g = binaryData[i + 1];
                    var b = binaryData[i + 2];
          
                    binaryData[i] = 255-r;
                    binaryData[i + 1] = 255-g;
                    binaryData[i + 2] = 255-b;
                }
             },
          
             /**
              * adjust color values and make it more darker and gray...
              * 
              * @param binaryData
              * @param l
              */
            colorAdjustProcess: function(binaryData, l) {
              for (var i = 0; i < l; i += 4) {
                    var r = binaryData[i];
                    var g = binaryData[i + 1];
                    var b = binaryData[i + 2];
          
                    binaryData[i] = (r * 0.272) + (g * 0.534) + (b * 0.131);
                    binaryData[i + 1] = (r * 0.349) + (g * 0.686) + (b * 0.168);
                    binaryData[i + 2] = (r * 0.393) + (g * 0.769) + (b * 0.189);
                }
            },
          
            /**
             * deep clone image data of canvas
             * 
             * @param context
             * @param src
             * @returns
             */
            copyImageData: function(context, src)
            {
                var dst = context.createImageData(src.width, src.height);
                dst.data.set(src.data);
                return dst;
            },
          
            /**
             * convolution - keneral size 5*5 - blur effect filter(模糊效果)
             * 
             * @param context
             * @param canvasData
             */
            blurProcess: function(context, canvasData) {
              console.log("Canvas Filter - blur process");
              var tempCanvasData = this.copyImageData(context, canvasData);
              var sumred = 0.0, sumgreen = 0.0, sumblue = 0.0;
              for ( var x = 0; x < tempCanvasData.width; x++) {    
                      for ( var y = 0; y < tempCanvasData.height; y++) {    
          
                          // Index of the pixel in the array    
                          var idx = (x + y * tempCanvasData.width) * 4;       
                          for(var subCol=-2; subCol<=2; subCol++) {
                            var colOff = subCol + x;
                            if(colOff <0 || colOff >= tempCanvasData.width) {
                              colOff = 0;
                            }
                            for(var subRow=-2; subRow<=2; subRow++) {
                              var rowOff = subRow + y;
                              if(rowOff < 0 || rowOff >= tempCanvasData.height) {
                                rowOff = 0;
                              }
                              var idx2 = (colOff + rowOff * tempCanvasData.width) * 4;    
                                var r = tempCanvasData.data[idx2 + 0];    
                                var g = tempCanvasData.data[idx2 + 1];    
                                var b = tempCanvasData.data[idx2 + 2];
                                sumred += r;
                                sumgreen += g;
                                sumblue += b;
                            }
                          }
          
                          // calculate new RGB value
                          var nr = (sumred / 25.0);
                          var ng = (sumgreen / 25.0);
                          var nb = (sumblue / 25.0);
          
                          // clear previous for next pixel point
                          sumred = 0.0;
                          sumgreen = 0.0;
                          sumblue = 0.0;
          
                          // assign new pixel value    
                          canvasData.data[idx + 0] = nr; // Red channel    
                          canvasData.data[idx + 1] = ng; // Green channel    
                          canvasData.data[idx + 2] = nb; // Blue channel    
                          canvasData.data[idx + 3] = 255; // Alpha channel    
                      }
              }
            },
          
            /**
             * after pixel value - before pixel value + 128
             * 浮雕效果
             */
            reliefProcess: function(context, canvasData) {
              console.log("Canvas Filter - relief process");
              var tempCanvasData = this.copyImageData(context, canvasData);
              for ( var x = 1; x < tempCanvasData.width-1; x++) 
              {    
                      for ( var y = 1; y < tempCanvasData.height-1; y++)
                      {    
          
                          // Index of the pixel in the array    
                          var idx = (x + y * tempCanvasData.width) * 4;       
                  var bidx = ((x-1) + y * tempCanvasData.width) * 4;
                  var aidx = ((x+1) + y * tempCanvasData.width) * 4;
          
                          // calculate new RGB value
                          var nr = tempCanvasData.data[aidx + 0] - tempCanvasData.data[bidx + 0] + 128;
                          var ng = tempCanvasData.data[aidx + 1] - tempCanvasData.data[bidx + 1] + 128;
                          var nb = tempCanvasData.data[aidx + 2] - tempCanvasData.data[bidx + 2] + 128;
                          nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr);
                          ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng);
                          nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb);
          
                          // assign new pixel value    
                          canvasData.data[idx + 0] = nr; // Red channel    
                          canvasData.data[idx + 1] = ng; // Green channel    
                          canvasData.data[idx + 2] = nb; // Blue channel    
                          canvasData.data[idx + 3] = 255; // Alpha channel    
                      }
              }
            },
          
            /**
             *   before pixel value - after pixel value + 128
             *  雕刻效果
             * 
             * @param canvasData
             */
            diaokeProcess: function(context, canvasData) {
              console.log("Canvas Filter - process");
              var tempCanvasData = this.copyImageData(context, canvasData);
              for ( var x = 1; x < tempCanvasData.width-1; x++) 
              {    
                      for ( var y = 1; y < tempCanvasData.height-1; y++)
                      {    
          
                          // Index of the pixel in the array    
                          var idx = (x + y * tempCanvasData.width) * 4;       
                  var bidx = ((x-1) + y * tempCanvasData.width) * 4;
                  var aidx = ((x+1) + y * tempCanvasData.width) * 4;
          
                          // calculate new RGB value
                          var nr = tempCanvasData.data[bidx + 0] - tempCanvasData.data[aidx + 0] + 128;
                          var ng = tempCanvasData.data[bidx + 1] - tempCanvasData.data[aidx + 1] + 128;
                          var nb = tempCanvasData.data[bidx + 2] - tempCanvasData.data[aidx + 2] + 128;
                          nr = (nr < 0) ? 0 : ((nr >255) ? 255 : nr);
                          ng = (ng < 0) ? 0 : ((ng >255) ? 255 : ng);
                          nb = (nb < 0) ? 0 : ((nb >255) ? 255 : nb);
          
                          // assign new pixel value    
                          canvasData.data[idx + 0] = nr; // Red channel    
                          canvasData.data[idx + 1] = ng; // Green channel    
                          canvasData.data[idx + 2] = nb; // Blue channel    
                          canvasData.data[idx + 3] = 255; // Alpha channel    
                      }
              }
            },
          
            /**
             * mirror reflect
             * 
             * @param context
             * @param canvasData
             */
            mirrorProcess : function(context, canvasData) {
              console.log("Canvas Filter - process");
              var tempCanvasData = this.copyImageData(context, canvasData);
              for ( var x = 0; x < tempCanvasData.width; x++) // column
              {    
                      for ( var y = 0; y < tempCanvasData.height; y++) // row
                      {    
          
                          // Index of the pixel in the array    
                          var idx = (x + y * tempCanvasData.width) * 4;       
                  var midx = (((tempCanvasData.width -1) - x) + y * tempCanvasData.width) * 4;
          
                          // assign new pixel value    
                          canvasData.data[midx + 0] = tempCanvasData.data[idx + 0]; // Red channel    
                          canvasData.data[midx + 1] = tempCanvasData.data[idx + 1]; ; // Green channel    
                          canvasData.data[midx + 2] = tempCanvasData.data[idx + 2]; ; // Blue channel    
                          canvasData.data[midx + 3] = 255; // Alpha channel    
                      }
              }
            },
          };

          總結(jié)

          感謝閱讀,如果你覺得我今天分享的內(nèi)容,不錯(cuò),請(qǐng)點(diǎn)一個(gè)贊,謝謝!!

          avaScript 可以說是交互之王,它作為腳本語言加上許多 Web Api 進(jìn)一步擴(kuò)展了它的特性集,更加豐富界面交互的可操作性。這類 API 的例子包括WebGL APICanvas APIDOM API,還有一組不太為人所知的 CSS API

          由于JSX和無數(shù)JS框架的出現(xiàn),使通過JS APIDOM交互的想法真正流行起來,但是在 CSS 中使用類似技術(shù)似乎并沒有很多。當(dāng)然,存在像CSS-in-JS這類解決方案,但是最流行的解決方案還是基于轉(zhuǎn)譯(transpilation),無需額外運(yùn)行即可生成 CSS。這肯定對(duì)性能有好處,因?yàn)?strong>CSS API的使用可能導(dǎo)致額外的重繪,這與DOM API的使用一樣。但這不是咱們想要的。如果哪天公司要求咱們,既要操縱 DOM 元素的樣式和 CSS 類,還要像使用 HTML 一樣使用 JS 創(chuàng)建完整的樣式表,該怎么辦?

          內(nèi)聯(lián)樣式

          在咱們深入一些復(fù)雜的知識(shí)之前,先回來顧一下一些基礎(chǔ)知識(shí)。例如,咱們可以通過修改它的.style屬性來編輯給定的HTMLElement的內(nèi)聯(lián)樣式。

          const el = document.createElement('div')
          
          el.style.backgroundColor = 'red'
          // 或者 
          el.style.cssText = 'background-color: red'
          // 或者
          el.setAttribute('style', 'background-color: red')
          

          直接在.style對(duì)象上設(shè)置樣式屬性將需要使用駝峰式命名作為屬性鍵,而不是使用短橫線命名。如果咱們需要設(shè)置更多的內(nèi)聯(lián)樣式屬性,則可以通過設(shè)置.style.cssText屬性,以更加高效的方式進(jìn)行設(shè)置 。

          我自己是一名從事了多年開發(fā)的web前端老程序員,目前辭職在做自己的web前端私人定制課程,今年年初我花了一個(gè)月整理了一份最適合2019年學(xué)習(xí)的web前端學(xué)習(xí)干貨,各種框架都有整理,送給每一位前端小伙伴,想要獲取的可以關(guān)注我的頭條號(hào)并在后臺(tái)私信我:前端,即可免費(fèi)獲取

          請(qǐng)記住給cssText設(shè)置后原先的css樣式被清掉了,因此,要求咱們一次死一堆樣式 。

          如果這種設(shè)置內(nèi)聯(lián)樣式過于繁瑣,咱們還可以考慮將.style與Object.assign()一起使用,以一次設(shè)置多個(gè)樣式屬性。

          // ...
          Object.assign(el.style, {
           backgroundColor: "red",
           margin: "25px"
          })
          

          這些“基本知識(shí)”比咱們想象的要多得多。.style對(duì)象實(shí)現(xiàn)CSSStyleDeclaration接口。這說明它帶還有一些有趣的屬性和方法,這包括剛剛使用的.cssText,還包括.length(設(shè)置屬性的數(shù)量),以及.item()、.getPropertyValue()和.setPropertyValue()之類的方法:

          // ...
          const propertiesCount = el.style.length
          for(let i = 0; i < propertiesCount; i++) {
           const name = el.style.item(i) // 'background-color'
           const value = el.style.getPropertyValue(name) // 're'
           const priority = el.style.getPropertyPriority(name) // 'important'
          
           if(priority === 'important') {
           el.style.removeProperty()
           }
          }
          

          這里有個(gè)小竅門-在遍歷過程中.item()方法具有按索引訪問形式的備用語法。

          // ...
          el.style.item(0) === el.style[0]; // true
          

          CSS 類

          接著,來看看更高級(jí)的結(jié)構(gòu)——CSS類,它在檢索和設(shè)置時(shí)具有字符串形式是.classname。

          // ...
          el.className = "class-one class-two";
          el.setAttribute("class", "class-one class-two");
          

          設(shè)置類字符串的另一種方法是設(shè)置class屬性(與檢索相同)。但是,就像使用.style.cssText屬性一樣,設(shè)置.className將要求咱們?cè)谧址邪ńo定元素的所有類,包括已更改和未更改的類。

          當(dāng)然,可以使用一些簡(jiǎn)單的字符串操作來完成這項(xiàng)工作,還有一種就是使用較新的.classList屬性,這個(gè)屬性,IE9 不支持它,而 IE10 和 IE11 僅部分支持它

          classlist屬性實(shí)現(xiàn)了DOMTokenList,有一大堆有用的方法。例如.add()、.remove()、.toggle()和.replace()允許咱們更改當(dāng)前的 CSS 類集合,而其他的,例如.item()、.entries()或.foreach()則可以簡(jiǎn)化這個(gè)索引集合的遍歷過程。

          // ...
          const classNames = ["class-one", "class-two", "class-three"];
          classNames.forEach(className => {
           if(!el.classList.contains(className)) {
           el.classList.add(className);
           }
          });
          

          Stylesheets

          一直以來,Web Api 還有一個(gè)StyleSheetList接口,該接口由document.styleSheets屬性實(shí)現(xiàn)。document.styleSheets 只讀屬性,返回一個(gè)由 StyleSheet 對(duì)象組成的 StyleSheetList,每個(gè) StyleSheet 對(duì)象都是一個(gè)文檔中鏈接或嵌入的樣式表。

          for(styleSheet of document.styleSheets){
           console.log(styleSheet);
          }
          

          通過打印結(jié)果咱們可以知道,每次循環(huán)打印的是 CSSStyleSheet 對(duì)象,每個(gè) CSSStyleSheet 對(duì)象由下列屬性組成:

          屬性描述media獲取當(dāng)前樣式作用的媒體。disabled打開或禁用一張樣式表。href返回 CSSStyleSheet 對(duì)象連接的樣式表地址。title返回 CSSStyleSheet 對(duì)象的title值。type返回 CSSStyleSheet 對(duì)象的type值,通常是text/css。parentStyleSheet返回包含了當(dāng)前樣式表的那張樣式表。ownerNode返回CSSStyleSheet對(duì)象所在的DOM節(jié)點(diǎn),通常是<link>或<style>。cssRules返回樣式表中所有的規(guī)則。ownerRule如果是通過@import導(dǎo)入的,屬性就是指向表示導(dǎo)入的規(guī)則的指針,否則值為null。IE不支持這個(gè)屬性。

          ** CSSStyleSheet對(duì)象方法: **

          方法描述insertRule()在當(dāng)前樣式表的 cssRules 對(duì)象插入CSS規(guī)則。deleteRule()在當(dāng)前樣式表刪除 cssRules 對(duì)象的CSS規(guī)則。

          有了StyleSheetList的全部?jī)?nèi)容,咱們來CSSStyleSheet本身。在這里就有點(diǎn)意思了, CSSStyleSheet擴(kuò)展了StyleSheet接口,并且只有這種只讀屬性,如.ownerNode,.href,.title或.type,它們大多直接從聲明給定樣式表的地方獲取。回想一下加載外部CSS文件的標(biāo)準(zhǔn)HTML代碼,咱們就會(huì)明白這句話是啥意思:

          <head>
          <link rel="stylesheet" type="text/css" href="style.css" title="Styles">
          </head>
          

          現(xiàn)在,咱們知道HTML文檔可以包含多個(gè)樣式表,所有這些樣式表都可以包含不同的規(guī)則,甚至可以包含更多的樣式表(當(dāng)使用@import時(shí))。CSSStyleSheet有兩個(gè)方法:、.insertrule()和.deleterule() 來增加和刪除 Css 規(guī)則。

          // ...
          const ruleIndex = styleSheet.insertRule("div {background-color: red}");
          styleSheet.deleteRule(ruleIndex);
          

          .insertRule(rule,index):此函數(shù)可以在cssRules規(guī)則集合中插入一個(gè)指定的規(guī)則,參數(shù)rule是標(biāo)示規(guī)則的字符串,參數(shù)index是值規(guī)則字符串插入的位置。

          deleteRule(index):此函數(shù)可以刪除指定索引的規(guī)規(guī)則,參數(shù)index規(guī)定規(guī)則的索引。

          CSSStyleSheet也有自己的兩個(gè)屬性:.ownerRule和.cssRule。雖然.ownerRule與@import相關(guān),但比較有趣的是.cssRules。簡(jiǎn)單地說,它是CSSRuleList的CSSRule,可以使用前面提到的.insertrule()和.deleterule()方法修改它。請(qǐng)記住,有些瀏覽器可能會(huì)阻止咱們從不同的來源(域)訪問外部CSSStyleSheet的.cssRules屬性。

          那么什么是 CSSRuleList?

          CSSRuleList是一個(gè)數(shù)組對(duì)象包含著一個(gè)有序的CSSRule對(duì)象的集合。每一個(gè)CSSRule可以通過rules.item(index)的形式訪問, 或者rules[index]。這里的rules是一個(gè)實(shí)現(xiàn)了CSSRuleList接口的對(duì)象, index是一個(gè)基于0開始的,順序與CSS樣式表中的順序是一致的。樣式對(duì)象的個(gè)數(shù)是通過rules.length表達(dá)。

          對(duì)于CSSStyleRule對(duì)象:

          每一個(gè)樣式表CSSStyleSheet對(duì)象可以包含若干CSSStyleRule對(duì)象,也就是css樣式規(guī)則,如下:

          <style type="text/css">
           h1{color:red}
           div{color:green}
          </style>
          

          在上面的代碼中style標(biāo)簽是一個(gè)CSSStyleSheet樣式表對(duì)象,這個(gè)樣式表對(duì)象包含兩個(gè)CSSStyleRule對(duì)象,也就是兩個(gè)css樣式規(guī)則。

          CSSStyleRule對(duì)象具有下列屬性:

          1.type:返回0-6的數(shù)字,表示規(guī)則的類型,類型列表如下:

          0:CSSRule.UNKNOWN_RULE。

          1:CSSRule.STYLE_RULE (定義一個(gè)CSSStyleRule對(duì)象)。

          2:CSSRule.CHARSET_RULE (定義一個(gè)CSSCharsetRule對(duì)象,用于設(shè)定當(dāng)前樣式表的字符集,默認(rèn)與當(dāng)前網(wǎng)頁相同)。

          3:CSSRule.IMPORT_RULE (定義一個(gè)CSSImportRule對(duì)象,就是用@import引入其他的樣式表)

          4:CSSRule.MEDIA_RULE (定義一個(gè)CSSMediaRule對(duì)象,用于設(shè)定此樣式是用于顯示器,打印機(jī)還是投影機(jī)等等)。

          5:CSSRule.FONT_FACE_RULE (定義一個(gè)CSSFontFaceRule對(duì)象,CSS3的@font-face)。

          6:CSSRule.PAGE_RULE (定義一個(gè)CSSPageRule對(duì)象)。

          2.cssText:返回一個(gè)字符串,表示的是當(dāng)前規(guī)則的內(nèi)容,例如:

          div{color:green}
          

          3.parentStyleSheet:返回所在的CSSStyleRule對(duì)象。

          4.parentRule:如果規(guī)則位于另一規(guī)則中,該屬性引用另一個(gè)CSSRule對(duì)象。

          5.selectorText:返回此規(guī)則的選擇器,如上面的div就是選擇器。

          6.style:返回一個(gè)CSSStyleDeclaration對(duì)象。

          // ...
          const ruleIndex = styleSheet.insertRule("div {background-color: red}");
          const rule = styleSheet.cssRules.item(ruleIndex);
          
          rule.selectorText; // "div"
          rule.style.backgroundColor; // "red"
          

          實(shí)現(xiàn)

          現(xiàn)在,咱們對(duì) CSS 相關(guān)的 JS Api有了足夠的了解,可以創(chuàng)建咱們自己的、小型的、基于運(yùn)行時(shí)的CSS-in-JS實(shí)現(xiàn)。咱們的想法是創(chuàng)建一個(gè)函數(shù),它傳遞一個(gè)簡(jiǎn)單的樣式配置對(duì)象,生成一個(gè)新創(chuàng)建的CSS類的哈希名稱供以后使用。

          實(shí)現(xiàn)流程很簡(jiǎn)單,咱們需要一個(gè)能夠訪問某種樣式表的函數(shù),并且只需使用.insertrule()方法和樣式配置就可以運(yùn)行了。先從樣式表部分開始:

          function createClassName(style) {
           // ...
           let styleSheet;
           for (let i = 0; i < document.styleSheets.length; i++) {
           if (document.styleSheets[i].CSSInJS) {
           styleSheet = document.styleSheets[i];
           break;
           }
           }
           if (!styleSheet) {
           const style = document.createElement("style");
           document.head.appendChild(style);
           styleSheet = style.sheet;
           styleSheet.CSSInJS = true;
           }
           // ...
          }
          

          如果你使用的是ESM或任何其他類型的JS模塊系統(tǒng),則可以在函數(shù)外部安全地創(chuàng)建樣式表實(shí)例,而不必?fù)?dān)心其他人對(duì)其進(jìn)行訪問。但是,為了演示例,咱們將stylesheet上的.CSSInJS屬性設(shè)置為標(biāo)志的形式,通過標(biāo)志來判斷是否要使用它。

          現(xiàn)在,如果如果還需要?jiǎng)?chuàng)建一個(gè)新的樣式表怎么辦? 最好的選擇是創(chuàng)建一個(gè)新的<style/>標(biāo)記,并將其附加到HTML文檔的<head/>上。這會(huì)自動(dòng)將新樣式表添加到document.styleSheets列表,并允許咱們通過<style/>標(biāo)記的.sheet屬性對(duì)其進(jìn)行訪問,是不是很機(jī)智?

          function createRandomName() {
           const code = Math.random().toString(36).substring(7);
           return `css-${code}`;
          }
          
          function phraseStyle(style) {
           const keys = Object.keys(style);
           const keyValue = keys.map(key => {
           const kebabCaseKey = 
           key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
           const value = 
           `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;
          
           return `${kebabCaseKey}:${value};`;
           });
          
           return `{${keyValue.join("")}}`;
          }
          

          除了上面的小竅門之外。自然,咱們首先需要一種為CSS類生成新的隨機(jī)名稱的方法。然后,將樣式對(duì)象正確地表達(dá)為可行的CSS字符串的形式。這包括駝峰命名和短橫線全名之間的轉(zhuǎn)換,以及可選的像素單位(px)轉(zhuǎn)換的處理。

          function createClassName(style) {
           const className = createRandomName();
           let styleSheet;
           // ...
           styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
           return className;
          }
          

          完整代碼如下:

          HTML

          <div id="el"></div>
          

          JS

          function createRandomName() {
           const code = Math.random().toString(36).substring(7);
           return `css-${code}`;
          }
          
          function phraseStyle(style) {
           const keys = Object.keys(style);
           const keyValue = keys.map(key => {
           const kebabCaseKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
           const value = `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;
           return `${kebabCaseKey}:${value};`;
           });
           return `{${keyValue.join("")}}`;
          }
          
          function createClassName(style) {
           const className = createRandomName();
           let styleSheet;
           for (let i = 0; i < document.styleSheets.length; i++) {
           if (document.styleSheets[i].CSSInJS) {
           styleSheet = document.styleSheets[i];
           break;
           }
           }
           if (!styleSheet) {
           const style = document.createElement("style");
           document.head.appendChild(style);
           styleSheet = style.sheet;
           styleSheet.CSSInJS = true;
           }
           styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
           return className;
          }
          
          const el = document.getElementById("el");
          
          const redRect = createClassName({
           width: 100,
           height: 100,
           backgroundColor: "red"
          });
          
          el.classList.add(redRect);
          

          運(yùn)行效果:

          總結(jié)

          正如本文咱們所看到的,使用 JS 操作CSS 是一件非常有趣的事,咱們可以挖掘很多好用的 API,上面的例子只是冰山一角,在CSS API(或者更確切地說是API)中還有更多方法,它們正等著被揭開神秘面紗。



          原文:https://css-tricks.com/an-introduction-and-guide-to-the-css-object-model-cssom/

          眾號(hào)【傳智播客博學(xué)谷】回復(fù)關(guān)鍵詞:前端 PS Java(100G) Python(80G) 大數(shù)據(jù) 區(qū)塊鏈 測(cè)試 PPT JS(40g+300教程) HTML 簡(jiǎn)歷 領(lǐng)取相關(guān)學(xué)習(xí)資料!

          一、HTML

          1、<image>標(biāo)簽上title屬性與alt屬性的區(qū)別是什么?

          alt屬性是為了給那些不能看到你文檔中圖像的瀏覽者提供文字說明的。且長(zhǎng)度必須少于100個(gè)英文字符或者用戶必須保證替換文字盡可能的短。

          這包括那些使用本來就不支持圖像顯示或者圖像顯示被關(guān)閉的瀏覽器的用戶,視覺障礙的用戶和使用屏幕閱讀器的用戶等。

          title屬性為設(shè)置該屬性的元素提供建議性的信息。使用title屬性提供非本質(zhì)的額外信息。參考《alt和title屬性的區(qū)別及應(yīng)用》

          2、分別寫出以下幾個(gè)HTML標(biāo)簽:文字加粗、下標(biāo)、居中、字體

          加粗:<b>、<strong>

          下標(biāo):<sub>

          居中:<center>

          字體:<font>、<basefont>、參考《HTML標(biāo)簽列表》

          3、請(qǐng)寫出至少5個(gè)html5新增的標(biāo)簽,并說明其語義和應(yīng)用場(chǎng)景

          section:定義文檔中的一個(gè)章節(jié)

          nav:定義只包含導(dǎo)航鏈接的章節(jié)

          header:定義頁面或章節(jié)的頭部。它經(jīng)常包含 logo、頁面標(biāo)題和導(dǎo)航性的目錄。

          footer:定義頁面或章節(jié)的尾部。它經(jīng)常包含版權(quán)信息、法律信息鏈接和反饋建議用的地址。

          aside:定義和頁面內(nèi)容關(guān)聯(lián)度較低的內(nèi)容——如果被刪除,剩下的內(nèi)容仍然很合理。

          參考《HTML5 標(biāo)簽列表》

          4、請(qǐng)說說你對(duì)標(biāo)簽語義化的理解?

          a. 去掉或者丟失樣式的時(shí)候能夠讓頁面呈現(xiàn)出清晰的結(jié)構(gòu)

          b. 有利于SEO:和搜索引擎建立良好溝通,有助于爬蟲抓取更多的有效信息:爬蟲依賴于標(biāo)簽來確定上下文和各個(gè)關(guān)鍵字的權(quán)重;

          c. 方便其他設(shè)備解析(如屏幕閱讀器、盲人閱讀器、移動(dòng)設(shè)備)以意義的方式來渲染網(wǎng)頁;

          d. 便于團(tuán)隊(duì)開發(fā)和維護(hù),語義化更具可讀性,遵循W3C標(biāo)準(zhǔn)的團(tuán)隊(duì)都遵循這個(gè)標(biāo)準(zhǔn),可以減少差異化。

          5、Doctype作用? 嚴(yán)格模式與混雜模式如何區(qū)分?它們有何意義?

          聲明位于文檔中的最前面,處于 標(biāo)簽之前。告知瀏覽器以何種模式來渲染文檔。

          嚴(yán)格模式的排版和 JS 運(yùn)作模式是,以該瀏覽器支持的最高標(biāo)準(zhǔn)運(yùn)行。

          在混雜模式中,頁面以寬松的向后兼容的方式顯示。模擬老式瀏覽器的行為以防止站點(diǎn)無法工作。

          DOCTYPE不存在或格式不正確會(huì)導(dǎo)致文檔以混雜模式呈現(xiàn)。

          6、你知道多少種Doctype文檔類型?

          標(biāo)簽可聲明三種 DTD 類型,分別表示嚴(yán)格版本、過渡版本以及基于框架的 HTML 文檔。

          HTML 4.01 規(guī)定了三種文檔類型:Strict、Transitional 以及 Frameset。

          XHTML 1.0 規(guī)定了三種 XML 文檔類型:Strict、Transitional 以及 Frameset。

          Standards (標(biāo)準(zhǔn))模式(也就是嚴(yán)格呈現(xiàn)模式)用于呈現(xiàn)遵循最新標(biāo)準(zhǔn)的網(wǎng)頁,

          Quirks(包容)模式(也就是松散呈現(xiàn)模式或者兼容模式)用于呈現(xiàn)為傳統(tǒng)瀏覽器而設(shè)計(jì)的網(wǎng)頁。

          7、HTML與XHTML——二者有什么區(qū)別

          a. XHTML 元素必須被正確地嵌套。

          b. XHTML 元素必須被關(guān)閉。

          c. 標(biāo)簽名必須用小寫字母。

          d. XHTML 文檔必須擁有根元素。

          參考《XHTML 與 HTML 之間的差異》

          8、html5有哪些新特性、移除了那些元素?

          a. HTML5 現(xiàn)在已經(jīng)不是 SGML 的子集,主要是關(guān)于圖像,位置,存儲(chǔ),多任務(wù)等功能的增加。

          b. 拖拽釋放(Drag and drop) API

          c. 語義化更好的內(nèi)容標(biāo)簽(header,nav,footer,aside,article,section)

          d. 音頻、視頻API(audio,video)

          e. 畫布(Canvas) API

          f. 地理(Geolocation) API

          g. 本地離線存儲(chǔ) localStorage 長(zhǎng)期存儲(chǔ)數(shù)據(jù),瀏覽器關(guān)閉后數(shù)據(jù)不丟失

          h. sessionStorage 的數(shù)據(jù)在頁面會(huì)話結(jié)束時(shí)會(huì)被清除

          i. 表單控件,calendar、date、time、email、url、search

          j. 新的技術(shù)webworker, websocket等

          移除的元素:

          a. 純表現(xiàn)的元素:basefont,big,center, s,strike,tt,u;

          b. 對(duì)可用性產(chǎn)生負(fù)面影響的元素:frame,frameset,noframes;

          9、iframe的優(yōu)缺點(diǎn)?

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

          a. 解決加載緩慢的第三方內(nèi)容如圖標(biāo)和廣告等的加載問題

          b. iframe無刷新文件上傳

          c. iframe跨域通信

          缺點(diǎn):

          a. iframe會(huì)阻塞主頁面的Onload事件

          b. 無法被一些搜索引擎索引到

          c. 頁面會(huì)增加服務(wù)器的http請(qǐng)求

          d. 會(huì)產(chǎn)生很多頁面,不容易管理。

          參考《iframe的一些記錄》

          10、Quirks模式是什么?它和Standards模式有什么區(qū)別?

          在寫程序時(shí)我們也會(huì)經(jīng)常遇到這樣的問題,如何保證原來的接口不變,又提供更強(qiáng)大的功能,尤其是新功能不兼容舊功能時(shí)。IE6以前的頁面大家都不會(huì)去寫DTD,所以IE6就假定 如果寫了DTD,就意味著這個(gè)頁面將采用對(duì)CSS支持更好的布局,而如果沒有,則采用兼容之前的布局方式。這就是Quirks模式(怪癖模式,詭異模式,怪異模式)。

          區(qū)別:總體會(huì)有布局、樣式解析和腳本執(zhí)行三個(gè)方面的區(qū)別。

          a. 盒模型:在W3C標(biāo)準(zhǔn)中,如果設(shè)置一個(gè)元素的寬度和高度,指的是元素內(nèi)容的寬度和高度,而在Quirks 模式下,IE的寬度和高度還包含了padding和border。

          b. 設(shè)置行內(nèi)元素的高寬:在Standards模式下,給等行內(nèi)元素設(shè)置wdith和height都不會(huì)生效,而在quirks模式下,則會(huì)生效。

          c. 設(shè)置百分比的高度:在standards模式下,一個(gè)元素的高度是由其包含的內(nèi)容來決定的,如果父元素沒有設(shè)置百分比的高度,子元素設(shè)置一個(gè)百分比的高度是無效的用

          d. 設(shè)置水平居中:使用margin:0 auto在standards模式下可以使元素水平居中,但在quirks模式下卻會(huì)失效。

          11、請(qǐng)闡述table的缺點(diǎn)

          a. 太深的嵌套,比如table>tr>td>h3,會(huì)導(dǎo)致搜索引擎讀取困難,而且,最直接的損失就是大大增加了冗余代碼量。

          b. 靈活性差,比如要將tr設(shè)置border等屬性,是不行的,得通過td

          c. 代碼臃腫,當(dāng)在table中套用table的時(shí)候,閱讀代碼會(huì)顯得異常混亂

          d. 混亂的colspan與rowspan,用來布局時(shí),頻繁使用他們會(huì)造成整個(gè)文檔順序混亂。

          e. 不夠語義

          參考《為什么說table表格布局不好?》

          12、簡(jiǎn)述一下src與href的區(qū)別

          src用于替換當(dāng)前元素;href用于在當(dāng)前文檔和引用資源之間確立聯(lián)系。

          src是source的縮寫,指向外部資源的位置,指向的內(nèi)容將會(huì)嵌入到文檔中當(dāng)前標(biāo)簽所在位置

          href是Hypertext Reference的縮寫,指向網(wǎng)絡(luò)資源所在位置,建立和當(dāng)前元素(錨點(diǎn))或當(dāng)前文檔(鏈接)之間的鏈接

          公眾號(hào)【傳智播客博學(xué)谷】回復(fù)關(guān)鍵詞:前端 PS Java Python 大數(shù)據(jù) 區(qū)塊鏈 測(cè)試 PPT JS HTML 簡(jiǎn)歷 領(lǐng)取相關(guān)學(xué)習(xí)資料!


          主站蜘蛛池模板: 婷婷亚洲综合一区二区| 国产一区二区成人| 国产精品综合AV一区二区国产馆| 亚洲国产精品一区二区三区久久| 国产成人精品一区二三区熟女 | 精品国产一区二区三区香蕉| 精品一区二区无码AV| 亚洲日本精品一区二区| 亚洲国产成人久久一区久久| 欧美一区内射最近更新| 手机看片福利一区二区三区| 亚洲电影唐人社一区二区| 无码中文人妻在线一区| 午夜影视日本亚洲欧洲精品一区 | 亚洲国产精品一区二区久| 国产成人一区二区三区高清| 无码精品国产一区二区三区免费 | 成人免费av一区二区三区| 亚洲啪啪综合AV一区| 亚洲Av无码国产一区二区| 一区二区三区国模大胆| 成人区人妻精品一区二区不卡| 亚洲日本va午夜中文字幕一区| 亚洲一区二区在线免费观看| 狠狠色婷婷久久一区二区三区| 亚洲老妈激情一区二区三区| 一色一伦一区二区三区| 在线观看国产区亚洲一区成人| 激情内射亚洲一区二区三区爱妻| 又硬又粗又大一区二区三区视频| 一区免费在线观看| 亚洲国产精品第一区二区三区| 国产精品第一区揄拍无码| 国产产一区二区三区久久毛片国语| 极品人妻少妇一区二区三区| 亚洲欧美日韩中文字幕在线一区| 国产成人精品第一区二区| 欧美日韩精品一区二区在线观看| 在线观看精品视频一区二区三区| 国产激情无码一区二区三区| 精品无码一区二区三区水蜜桃|