Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 中文字幕日本一本二本三区,99在线播放,99久久99视频

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript操作DOM常用的API

          JavaScript操作DOM常用的API

          什么是DOM

          文檔對象模型 (DOM) 是HTML和XML文檔的編程接口。它提供了對文檔的結構化的表述,并定義了一種方式可以使從程序中對該結構進行訪問,從而改變文檔的結構,樣式和內容。文檔對象模型 (DOM) 是對HTML文件的另一種展示,通俗地說,一個HTML 文件,我們可以用編輯器以代碼的形式展示它,也可以用瀏覽器以頁面的形式展示它,同一份文件通過不同的展示方式,就有了不一樣的表現形式。而DOM 將文檔解析為一個由節點和對象(包含屬性和方法的對象)組成的結構集合。簡言之,它會將web頁面和腳本或程序語言連接起來,我們可以使用腳本或者程序語言通過DOM 來改變或者控制web頁面。

          2 如何訪問DOM

          我們可以通過JavaScript 來調用document和window元素的API來操作文檔或者獲取文檔的信息。

          3 Node

          Node 是一個接口,有許多接口都從Node 繼承方法和屬性:Document, Element, CharacterData (which Text, Comment, and CDATASection inherit), ProcessingInstruction, DocumentFragment, DocumentType, Notation, Entity, EntityReference。Node 有一個nodeType的屬性表示Node 的類型,是一個整數,不同的值代表不同的節點類型。具體如下表所示:

          節點類型常量

          已棄用的節點類型常量

          假設我們要判斷一個Node 是不是一個元素,通過查表可知元素的nodeType屬性值為1,代碼可以這么寫:

          復制代碼if(X.nodeType===1){
            console.log('X 是一個元素');
          }
          

          在Node 類型中,比較常用的就是element,text,comment,document,document_fragment這幾種類型。

          3.1 Element

          Element提供了對元素標簽名,子節點和特性的訪問,我們常用HTML元素比如div,span,a等標簽就是element中的一種。Element有下面幾條特性:(1)nodeType為1(2)nodeName為元素標簽名,tagName也是返回標簽名(3)nodeValue為null(4)parentNode可能是Document或Element(5)子節點可能是Element,Text,Comment,Processing_Instruction,CDATASection或EntityReference

          3.2 Text

          Text表示文本節點,它包含的是純文本內容,不能包含html代碼,但可以包含轉義后的html代碼。Text有下面的特性:(1)nodeType為3(2)nodeName為#text(3)nodeValue為文本內容(4)parentNode是一個Element(5)沒有子節點

          3.3 Comment

          Comment表示HTML文檔中的注釋,它有下面的幾種特征:(1)nodeType為8(2)nodeName為#comment(3)nodeValue為注釋的內容(4)parentNode可能是Document或Element(5)沒有子節點

          3.4 Document

          Document表示文檔,在瀏覽器中,document對象是HTMLDocument的一個實例,表示整個頁面,它同時也是window對象的一個屬性。Document有下面的特性:(1)nodeType為9(2)nodeName為#document(3)nodeValue為null(4)parentNode為null(5)子節點可能是一個DocumentType或Element

          3.5 DocumentFragment

          DocumentFragment是所有節點中唯一一個沒有對應標記的類型,它表示一種輕量級的文檔,可能當作一個臨時的倉庫用來保存可能會添加到文檔中的節點。DocumentFragment有下面的特性:(1)nodeType為11(2)nodeName為#document-fragment(3)nodeValue為null(4)parentNode為null

          4 節點創建型API

          用如其名,這類API是用來創建節點的

          4.1 createElement

          createElement通過傳入指定的一個標簽名來創建一個元素,如果傳入的標簽名是一個未知的,則會創建一個自定義的標簽,注意:IE8以下瀏覽器不支持自定義標簽。

          語法

          復制代碼  let element=document.createElement(tagName);
          

          使用createElement要注意:通過createElement創建的元素并不屬于HTML文檔,它只是創建出來,并未添加到HTML文檔中,要調用appendChild或insertBefore等方法將其添加到HTML文檔樹中。

          例子:

          復制代碼  let elem=document.createElement("div");
            elem.id='test';
            elem.style='color: red';
            elem.innerHTML='我是新創建的節點';
            document.body.appendChild(elem);
          

          運行結果為:


          4.2 createTextNode

          createTextNode用來創建一個文本節點

          語法

          復制代碼  var text=document.createTextNode(data);
          

          createTextNode接收一個參數,這個參數就是文本節點中的文本,和createElement一樣,創建后的文本節點也只是獨立的一個節點,同樣需要appendChild將其添加到HTML文檔樹中

          例子:

          復制代碼  var node=document.createTextNode("我是文本節點");
            document.body.appendChild(node);
          

          運行結果為:


          4.3 cloneNode

          cloneNode返回調用該方法的節點的一個副本

          語法

          復制代碼  var dupNode=node.cloneNode(deep);
          

          node 將要被克隆的節點dupNode 克隆生成的副本節點deep(可選)是否采用深度克隆,如果為true,則該節點的所有后代節點也都會被克隆,如果為false,則只克隆該節點本身.

          這里有幾點要注意:(1)和createElement一樣,cloneNode創建的節點只是游離有HTML文檔外的節點,要調用appendChild方法才能添加到文檔樹中(2)如果復制的元素有id,則其副本同樣會包含該id,由于id具有唯一性,所以在復制節點后必須要修改其id(3)調用接收的deep參數最好傳入,如果不傳入該參數,不同瀏覽器對其默認值的處理可能不同

          注意如果被復制的節點綁定了事件,則副本也會跟著綁定該事件嗎?這里要分情況討論:(1)如果是通過addEventListener或者比如onclick進行綁定事件,則副本節點不會綁定該事件(2)如果是內聯方式綁定比如:<div onclick="showParent()"></div>,這樣的話,副本節點同樣會觸發事件。

          例子:

          復制代碼<body>
            <div id="parent">
              我是父元素的文本
              <br/>
              <span>
                  我是子元素
              </span>
            </div>
            <button id="btnCopy">復制</button>
          </body>
          <script>
            var parent=document.getElementById("parent");
            document.getElementById("btnCopy").onclick=function(){
            	var parent2=parent.cloneNode(true);
            	parent2.id="parent2";
            	document.body.appendChild(parent2);
            }
          </script>
          

          運行結果為:


          4.4 createDocumentFragment

          DocumentFragments 是DOM節點。它們不是主DOM樹的一部分。通常的用例是創建文檔片段,將元素附加到文檔片段,然后將文檔片段附加到DOM樹。在DOM樹中,文檔片段被其所有的子元素所代替。因為文檔片段存在于內存中,并不在DOM樹中,所以將子元素插入到文檔片段時不會引起頁面回流(reflow)(對元素位置和幾何上的計算)。因此,使用文檔片段document fragments 通常會起到優化性能的作用。

          語法

          復制代碼  let fragment=document.createDocumentFragment();
          

          例子:

          復制代碼<body>
            <ul id="ul"></ul>
          </body>
          <script>
            (function()
            {
              var start=Date.now();
              var str='', li;
              var ul=document.getElementById('ul');
              var fragment=document.createDocumentFragment();
              for(var i=0; i<1000; i++)
              {
                  li=document.createElement('li');
                  li.textContent='第'+(i+1)+'個子節點';
                  fragment.appendChild(li);
              }
              ul.appendChild(fragment);
            })();
          </script>
          

          運行結果為:


          4.5 節點創建型API總結

          節點創建型API主要包括createElement,createTextNode,cloneNode和createDocumentFragment四個方法,需要注意下面幾點:(1)它們創建的節點只是一個孤立的節點,要通過appendChild添加到文檔中(2)cloneNode要注意如果被復制的節點是否包含子節點以及事件綁定等問題(3)使用createDocumentFragment來解決添加大量節點時的性能問題

          5 頁面修改型API

          前面我們提到節點創建型API,它們只是創建節點,并沒有真正修改到頁面內容,而是要調用·appendChild·來將其添加到文檔樹中。我在這里將這類會修改到頁面內容歸為一類。修改頁面內容的api主要包括:appendChild,insertBefore,removeChild,replaceChild。

          5.1 appendChild

          appendChild我們在前面已經用到多次,就是將指定的節點添加到調用該方法的節點的子元素的末尾。

          語法

          復制代碼  parent.appendChild(child);
          

          child節點將會作為parent節點的最后一個子節點。appendChild這個方法很簡單,但是還有有一點需要注意:如果被添加的節點是一個頁面中存在的節點,則執行后這個節點將會添加到指定位置,其原本所在的位置將移除該節點,也就是說不會同時存在兩個該節點在頁面上,相當于把這個節點移動到另一個地方。如果child綁定了事件,被移動時,它依然綁定著該事件。

          例子:

          復制代碼<body>
            <div id="child">
              要被添加的節點
            </div>
            <br/>
            <br/>
            <br/>
            <div id="parent">
              要移動的位置
            </div>		
            <input id="btnMove" type="button" value="移動節點" />
          </body>
          <script>
            document.getElementById("btnMove").onclick=function(){
          	  var child=document.getElementById("child");
           	  document.getElementById("parent").appendChild(child);
            } 
          </script>
          

          運行結果:


          5.2 insertBefore

          insertBefore用來添加一個節點到一個參照節點之前

          語法

          復制代碼  parentNode.insertBefore(newNode,refNode);
          

          parentNode表示新節點被添加后的父節點newNode表示要添加的節點refNode表示參照節點,新節點會添加到這個節點之前

          例子:

          復制代碼<body>
            <div id="parent">
              父節點
              <div id="child">				
                  子元素
              </div>
            </div>
            <input type="button" id="insertNode" value="插入節點" />
          </body>
          <script>
            var parent=document.getElementById("parent");
            var child=document.getElementById("child");
            document.getElementById("insertNode").onclick=function(){
            	var newNode=document.createElement("div");
            	newNode.textContent="新節點"
            	parent.insertBefore(newNode,child);
            }
          </script>
          

          運行結果:


          關于第二個參數參照節點還有幾個注意的地方:(1)refNode是必傳的,如果不傳該參數會報錯(2)如果refNode是undefined或null,則insertBefore會將節點添加到子元素的末尾

          5.3 removeChild

          刪除指定的子節點并返回

          語法

          復制代碼  var deletedChild=parent.removeChild(node);
          

          deletedChild指向被刪除節點的引用,它等于node,被刪除的節點仍然存在于內存中,可以對其進行下一步操作。注意:如果被刪除的節點不是其子節點,則程序將會報錯。我們可以通過下面的方式來確保可以刪除:

          復制代碼if(node.parentNode){
              node.parentNode.removeChild(node);
          }
          

          運行結果:

          通過節點自己獲取節點的父節點,然后將自身刪除


          5.4 replaceChild

          replaceChild用于使用一個節點替換另一個節點

          語法

          復制代碼  parent.replaceChild(newChild,oldChild);
          

          newChild是替換的節點,可以是新的節點,也可以是頁面上的節點,如果是頁面上的節點,則其將被轉移到新的位置oldChild是被替換的節點

          例子:

          復制代碼<body>
            <div id="parent">
              父節點
              <div id="child">				
                  子元素
              </div>
            </div>
            <input type="button" id="insertNode" value="替換節點" />
          </body>
          <script>
            var parent=document.getElementById("parent");
            var child=document.getElementById("child");
            document.getElementById("insertNode").onclick=function(){
            	var newNode=document.createElement("div");
            	newNode.textContent="新節點"
            	parent.replaceChild(newNode,child)
            }
          

          運行結果:


          5.5 頁面修改型API總結

          頁面修改型API主要是這四個接口,要注意幾個特點:(1)不管是新增還是替換節點,如果新增或替換的節點是原本存在頁面上的,則其原來位置的節點將被移除,也就是說同一個節點不能存在于頁面的多個位置(2)節點本身綁定的事件會不會消失,會一直保留著。

          6 節點查詢型API

          6.1 document.getElementById

          這個接口很簡單,根據元素id返回元素,返回值是Element類型,如果不存在該元素,則返回null

          語法

          復制代碼  var element=document.getElementById(id);
          

          使用這個接口有幾點要注意:(1)元素的Id是大小寫敏感的,一定要寫對元素的id(2)HTML文檔中可能存在多個id相同的元素,則返回第一個元素(3)只從文檔中進行搜索元素,如果創建了一個元素并指定id,但并沒有添加到文檔中,則這個元素是不會被查找到的

          例子:

          復制代碼<body>
            <p id="para1">Some text here</p>
            <button onclick="changeColor('blue');">blue</button>
            <button onclick="changeColor('red');">red</button>
          </body>
          <script>
            function changeColor(newColor) {
              var elem=document.getElementById("para1");
              elem.style.color=newColor;
            }
          </script>
          

          運行結果:


          6.2 document.getElementsByTagName

          返回一個包括所有給定標簽名稱的元素的HTML集合HTMLCollection。 整個文件結構都會被搜索,包括根節點。返回的 HTML集合是動態的, 意味著它可以自動更新自己來保持和 DOM 樹的同步而不用再次調用document.getElementsByTagName()

          語法

          復制代碼  var elements=document.getElementsByTagName(name);
          

          (1)如果要對HTMLCollection集合進行循環操作,最好將其長度緩存起來,因為每次循環都會去計算長度,暫時緩存起來可以提高效率(2)如果沒有存在指定的標簽,該接口返回的不是null,而是一個空的HTMLCollection(3)name是一個代表元素的名稱的字符串。特殊字符 "*" 代表了所有元素。

          例子:

          復制代碼<body>
            <div>div1</div>
            <div>div2</div>	
            <input type="button" value="顯示數量" id="btnShowCount"/>
            <input type="button" value="新增div" id="btnAddDiv"/>	
          </body>
          <script>
            var divList=document.getElementsByTagName("div");
            document.getElementById("btnAddDiv").onclick=function(){
            	var div=document.createElement("div");
            	div.textContent="div" + (divList.length+1);
            	document.body.appendChild(div);
            }
            document.getElementById("btnShowCount").onclick=function(){
              alert(divList.length);
            }
          </script>
          

          這段代碼中有兩個按鈕,一個按鈕是顯示HTMLCollection元素的個數,另一個按鈕可以新增一個div標簽到文檔中。前面提到HTMLCollcetion元素是即時的表示該集合是隨時變化的,也就是是文檔中有幾個div,它會隨時進行變化,當我們新增一個div后,再訪問HTMLCollection時,就會包含這個新增的div。

          運行結果:


          6.3 document.getElementsByName

          getElementsByName主要是通過指定的name屬性來獲取元素,它返回一個即時的NodeList對象

          語法

          復制代碼  var elements=document.getElementsByName(name) 
          

          使用這個接口主要要注意幾點:(1)返回對象是一個即時的NodeList,它是隨時變化的(2)在HTML元素中,并不是所有元素都有name屬性,比如div是沒有name屬性的,但是如果強制設置div的name屬性,它也是可以被查找到的(3)在IE中,如果id設置成某個值,然后傳入getElementsByName的參數值和id值一樣,則這個元素是會被找到的,所以最好不好設置同樣的值給id和name

          例子:

          復制代碼<script type="text/javascript">
            function getElements()
             {
             var x=document.getElementsByName("myInput");
             alert(x.length);
             }
          </script>
          <body>
            <input name="myInput" type="text" size="20" /><br />
            <input name="myInput" type="text" size="20" /><br />
            <input name="myInput" type="text" size="20" /><br />
            <br />
            <input type="button" onclick="getElements()" value="How many elements named 'myInput'?" />
          </body>
          

          運行結果:


          6.4 document.getElementsByClassName

          這個API是根據元素的class返回一個即時的HTMLCollection

          語法

          復制代碼  var elements=document.getElementsByClassName(names); // or:
            var elements=rootElement.getElementsByClassName(names);
          
          • elements是一個實時集合,包含了找到的所有元素
          • names是一個字符串,表示要匹配的類名列表;類名通過空格分隔
          • getElementsByClassName可以在任何元素上調用,不僅僅是document。調用這個方法的元素將作為本次查找的根元素

          這個接口有下面幾點要注意:(1)返回結果是一個即時的HTMLCollection,會隨時根據文檔結構變化(2)IE9以下瀏覽器不支持(3)如果要獲取2個以上classname,可傳入多個classname,每個用空格相隔,例如

          復制代碼  var elements=document.getElementsByClassName("test1 test2");
          

          例子:

          • 獲取所有class為 'test' 的元素
          復制代碼  var elements=document.getElementsByClassName('test');
          
          • 獲取所有class同時包括 'red' 和 'test' 的元素
          復制代碼  var elements=document.getElementsByClassName('red test');
          
          • 在id為'main'的元素的子節點中,獲取所有class為'test'的元素
          復制代碼  var elements=document.getElementById('main').getElementsByClassName('test');
          
          • 我們還可以對任意的HTMLCollection 使用Array.prototype的方法,調用時傳遞HTMLCollection 作為方法的參數。這里我們將查找到所有class為'test'的div元素:
          復制代碼  var testElements=document.getElementsByClassName('test');
            var testDivs=Array.prototype.filter.call(testElements, function(testElement){
              return testElement.nodeName==='DIV';;
            });
          

          6.5 document.querySelector和document.querySelectorAll

          這兩個API很相似,通過css選擇器來查找元素,注意選擇器要符合CSS選擇器的規則

          • 6.5.1 document.querySelector

          document.querySelector返回第一個匹配的元素,如果沒有匹配的元素,則返回null

          語法

          復制代碼  var element=document.querySelector(selectors);
          

          注意,由于返回的是第一個匹配的元素,這個api使用的深度優先搜索來獲取元素。

          例子:

          復制代碼<body>
            <div>
              <div>
                <span class="test">第三級的span</span>	
              </div>
            </div>
            <div class="test">			
              同級的第二個div
            </div>
            <input type="button" id="btnGet" value="獲取test元素" />
          </body>
          <script>
            document.getElementById("btnGet").addEventListener("click",function(){
              var element=document.querySelector(".test");
              alert(element.textContent);
            })
          </script>
          

          兩個class都包含“test”的元素,一個在文檔樹的前面,但是它在第三級,另一個在文檔樹的后面,但它在第一級,通過querySelector獲取元素時,它通過深度優先搜索,拿到文檔樹前面的第三級的元素。運行結果:


          • 6.5.2 document.querySelectorAll返回的是所有匹配的元素,而且可以匹配多個選擇符

          語法

          復制代碼  var elementList=document.querySelectorAll(selectors);
          
          • elementList是一個靜態的NodeList類型的對象
          • selectors是一個由逗號連接的包含一個或多個CSS選擇器的字符串
          • 如果selectors參數中包含CSS偽元素,則返回一個空的elementList

          例子:

          復制代碼  var matches=document.querySelectorAll("div.note, div.alert");
          

          返回一個文檔中所有的class為"note"或者"alert"的div元素

          復制代碼<body>
            <div class="test">
              class為test
            </div>
            <div id="test">
              id為test
            </div>
            <input id="btnShow" type="button" value="顯示內容" />
          </body>
          <script>
            document.getElementById("btnShow").addEventListener("click",function(){
          	var elements=document.querySelectorAll("#test,.test");	
          	for(var i=0,length=elements.length;i<length;i++){
          		alert(elements[i].textContent);
          	}	
            })
          </script>
          

          這段代碼通過querySelectorAll,使用id選擇器和class選擇器選擇了兩個元素,并依次輸出其內容。要注意兩點:(1)querySelectorAll也是通過深度優先搜索,搜索的元素順序和選擇器的順序無關(2)返回的是一個非即時的NodeList,也就是說結果不會隨著文檔樹的變化而變化兼容性問題:querySelector和querySelectorAll在ie8以下的瀏覽器不支持。

          運行結果:


          7 節點關系型API

          在html文檔中的每個節點之間的關系都可以看成是家譜關系,包含父子關系,兄弟關系等等

          7.1 父關系型API

          7.1.1 parentNode

          每個節點都有一個parentNode屬性,它表示元素的父節點。Element的父節點可能是Element,Document或DocumentFragment

          7.1.2 parentElement

          返回元素的父元素節點,與parentNode的區別在于,其父節點必須是一個Element,如果不是,則返回null

          7.2 子關系型APPI

          7.2.1 childNodes

          返回一個即時的NodeList,表示元素的子節點列表,子節點可能會包含文本節點,注釋節點等

          7.2.2 children:

          一個即時的HTMLCollection,子節點都是Element,IE9以下瀏覽器不支持children屬性為只讀屬性,對象類型為HTMLCollection,你可以使用elementNodeReference.children[1].nodeName來獲取某個子元素的標簽名稱

          7.2.3 firstChild

          只讀屬性返回樹中節點的第一個子節點,如果節點是無子節點,則返回 null

          7.2.4 lastChild

          返回當前節點的最后一個子節點。如果父節點為一個元素節點,則子節點通常為一個元素節點,或一個文本節點,或一個注釋節點。如果沒有子節點,則返回null

          7.2.5 hasChildNodes

          返回一個布爾值,表明當前節點是否包含有子節點.

          7.3 兄弟關系型API

          7.3.1 previousSibling

          返回當前節點的前一個兄弟節點,沒有則返回nullGecko內核的瀏覽器會在源代碼中標簽內部有空白符的地方插入一個文本結點到文檔中.因此,使用諸如Node.firstChild和Node.previousSibling之類的方法可能會引用到一個空白符文本節點, 而不是使用者所預期得到的節點

          7.3.2 previousElementSibling

          previousElementSibling返回當前元素在其父元素的子元素節點中的前一個元素節點,如果該元素已經是第一個元素節點,則返回null,該屬性是只讀的。注意IE9以下瀏覽器不支持

          7.3.3 nextSibling

          Node.nextSibling是一個只讀屬性,返回其父節點的childNodes列表中緊跟在其后面的節點,如果指定的節點為最后一個節點,則返回nullGecko內核的瀏覽器會在源代碼中標簽內部有空白符的地方插入一個文本結點到文檔中.因此,使用諸如Node.firstChild和Node.previousSibling之類的方法可能會引用到一個空白符文本節點, 而不是使用者所預期得到的節點

          7.3.4 nextElementSibling

          nextElementSibling返回當前元素在其父元素的子元素節點中的后一個元素節點,如果該元素已經是最后一個元素節點,則返回null,該屬性是只讀的。注意IE9以下瀏覽器不支持

          8 元素屬性型API

          8.1 setAttribute

          設置指定元素上的一個屬性值。如果屬性已經存在,則更新該值; 否則將添加一個新的屬性用指定的名稱和值

          語法

          復制代碼  element.setAttribute(name, value);
          

          其中name是特性名,value是特性值。如果元素不包含該特性,則會創建該特性并賦值。

          例子:

          復制代碼<body>
            <div id="div1">ABC</div>
          </body>
          <script>  
            let div1=document.getElementById("div1"); 
            div1.setAttribute("align", "center");
          </script>
          

          運行結果:


          如果元素本身包含指定的特性名為屬性,則可以世界訪問屬性進行賦值,比如下面兩條代碼是等價的:

          復制代碼  element.setAttribute("id","test");
            element.id="test";
          

          8.2 getAttribute

          getAttribute()返回元素上一個指定的屬性值。如果指定的屬性不存在,則返回null或""(空字符串)

          語法

          復制代碼  let attribute=element.getAttribute(attributeName);  
          

          attribute是一個包含attributeName屬性值的字符串。attributeName是你想要獲取的屬性值的屬性名稱

          例子:

          復制代碼<body>
            <div id="div1">ABC</div>
          </body>
          <script>  
            let div1=document.getElementById("div1");
            let align=div1.getAttribute("align");
            alert(align);
          </script>  
          

          運行結果:


          8.3 removeAttribute

          removeAttribute()從指定的元素中刪除一個屬性

          語法

          復制代碼  element.removeAttribute(attrName)
          

          attrName是一個字符串,將要從元素中刪除的屬性名

          例子:

          復制代碼<body>
            <div id="div1" style="color:red" width="200px">ABC
             </div>
          </body>
          <script>  
            let div=document.getElementById("div1")
            div.removeAttribute("style");
          </script>
          

          在運行之前div有個style="color:red"的屬性,在運行之后這個屬性就被刪除了

          運行結果:


          9 元素樣式型API

          9.1 window.getComputedStyle

          Window.getComputedStyle()方法給出應用活動樣式表后的元素的所有CSS屬性的值,并解析這些值可能包含的任何基本計算假設某個元素并未設置高度而是通過其內容將其高度撐開,這時候要獲取它的高度就要用到getComputedStyle

          語法

          復制代碼  var style=window.getComputedStyle(element[, pseudoElt]);
          

          element是要獲取的元素,pseudoElt指定一個偽元素進行匹配。返回的style是一個CSSStyleDeclaration對象。通過style可以訪問到元素計算后的樣式

          9.2 getBoundingClientRect

          getBoundingClientRect用來返回元素的大小以及相對于瀏覽器可視窗口的位置

          語法

          復制代碼  var clientRect=element.getBoundingClientRect();
          

          clientRect是一個DOMRect對象,包含left,top,right,bottom,它是相對于可視窗口的距離,滾動位置發生改變時,它們的值是會發生變化的。除了IE9以下瀏覽器,還包含元素的height和width等數據

          9.3 直接修改元素的樣式

          例子:

          復制代碼  elem.style.color='red';
            elem.style.setProperty('font-size', '16px');
            elem.style.removeProperty('color');
          

          9.4 動態添加樣式規則

          例子:

          復制代碼  var style=document.createElement('style');
            style.innerHTML='body{color:red} #top:hover{background-color: red;color: white;}';
            document.head.appendChild(style););
          

          10 總結

          JavaScript中的API太多了,將這些API記住并熟練使用對JavaScript的學習是有很大的幫助

          作者:yyzclyang

          鏈接:https://juejin.cn/post/6844903604445249543

          數字化轉型潮流席卷各大行業的今天,越來越多的企業開始重視 BI(商業智能)技術的部署和應用,期望從不斷增長的數據資源中獲得更多業務價值,從而提升利潤、控制風險、降低成本。BI 能整合、組織和分析數據,將數據轉化為有價值的信息,為企業管理和決策提供支持,成為企業迎接變革和商業創新的決勝因素。

          由于 BI 技術的重要性,企業更希望在現有的業務平臺和系統中按需集成BI能力,從而在各類場景中充分發揮數據分析帶來的優勢,滿足企業日益多樣化的數據分析訴求,使 BI 能力與企業業務深度融合。然而,市面上常見的 BI 工具大都是獨立、打包的整體方案,很難與前端的業務系統集成在一起,在實踐中常常無法滿足需求。在這樣的背景下,嵌入式 BI 應運而生。

          所謂嵌入式 BI,就是在企業現有業務系統中按需集成各種類型的數據分析能力。這種集成工作一般需要考慮兩個要點:一方面,它本質上是現有業務系統的一次升級過程,需要關注升級內容與原系統的兼容性、穩定性、安全性等指標;另一方面,業務側一般希望深度集成專業的數據分析組件,而不是任意掛載一個簡單的模塊應付了事。這兩個要點為開發團隊提出了更高的要求和挑戰,需要團隊認真對待。

          嵌入式數據分析模塊架構探索

          對于很多中小企業而言,軟件開發團隊并不具備獨立開發 In-House 嵌入 BI 方案的能力,需要尋求外部第三方供應商的支持。行業中也出現了很多專業的外部供應商,他們探索出了一些經過市場驗證的嵌入式 BI 最佳實踐。我們以業內老牌知名企業葡萄城開發的 Wyn 商業智能嵌入式架構為例,探討數據分析模塊應該如何嵌入現有業務系統:

          如上所示,對于業務人員來說,應用功能層的數據分析儀表板、圖表、設計器、門戶等模塊,就是嵌入式 BI 方案展現出來的最終效果。其中,模塊的內容和形態一般是根據業務需求決定的,例如為某個銷售看板集成一些銷售數據動態圖表,實時反映各地區的當前銷售狀況。由于業務需求往往比較多樣化,嵌入模塊的內容和形態也非常多變,這就要求前端技術層具備更強的適應能力。

          前端技術層在過去普遍采用 URL iFrame 架構來實現模塊嵌入,如今更復雜的需求更多用 DIV 方式打造解決方案。此外,以 Wyn 商業智能為例,其 BI 模塊還可以同泛微、用友 U8+、企業微信和釘釘等常用的企業信息系統集成,增強它們的數據分析能力。

          API 層對于嵌入式 BI 方案是非常重要的。例如,API 允許根據用戶類型打開和關閉工具欄,只允許根據使用規則顯示指定的數據源,并支持創建具有不同過濾器和選項的儀表板。專業的嵌入式BI可以通過調用 API,在應用軟件內對儀表板/報表進行權限管理、分類管理、重命名、刪除等深度集成操作,而應用軟件和 BI 軟件之間的接口對最終用戶是完全透明的。當然,對于較為簡單的業務需求而言,嵌入式 BI 架構中取消 API 層,或者只有簡單的 API 層也是可以接受的。

          主流實現方案對比

          如上所述,對于開發團隊而言,嵌入式 BI 方案的技術選型關鍵在于 DIV 和IFrame 架構的選擇,以及是否加入強大的 API 層。

          IFrame 架構在早期的嵌入式 BI 市場非常流行,因其原理簡單、實現方便、開發周期較短,使企業能夠快速實現初期的嵌入式 BI 需求。但這種方式雖然簡單,局限性也是很大的。例如,使用 IFrame 就很難在系統中深度集成數據分析模塊。IFrame 更像曾經的 Flash 元素,是一種相對獨立的模塊。它與頁面的其他元素很難融合和互動,即便可以實現也需要付出大量努力和代價。

          相比之下,基于 JavaScript 的 DIV 層級的無縫嵌入方案,可以利用原生的JavaScript 將整個儀表板等以 DIV 的方式集成到項目中。嵌入的圖表元素具有高度開放的接口,能夠與其他元素進行數據交互。甚至 BI 軟件整體都可以通過DIV 架構直接嵌入到現有系統中,確保了無縫和直觀的用戶體驗。即便當前的業務需求僅僅停留在簡單的圖表展示層面,考慮到未來的升級和擴展潛力,開發團隊還是最好選擇 DIV 架構來設計 BI 嵌入方案。

          另一方面,API 層能夠大大簡化業務人員對嵌入式 BI 模塊的操作,往往是開發團隊需要重點實現的功能目標。Wyn 商業智能的嵌入式 BI 方案就提供了GraphQL API,幾乎所有界面操作均可通過 API 調用簡單完成。下圖就是一個簡單的 API 調用示例:

          GraphQL API 不需要為不同的對象操作提供不同的 URL。不同對象的不同操作均通過一個統一的 URL(http://localhost:51980/api/graphql)調用,只是各類操作提交的數據不同。可以看到,GraphQL API 的操作非常易于上手,可以大大方便開發團隊和業務團隊,滿足各類復雜的業務需求。下面來看 Wyn 商業智能提供的一個數據查詢 API 的操作示例,從中可以體會 API 的低門檻與便利性:

          當我們需要調用某個數據集,可以通過該 API 以 POST 或 GET 兩種方式完成操作。

          (示例 URL 為http://10.32.5.7:51980/api/v1/datasource/b7d93485-66f2-4356-ada5-0a163579232d/query?queryType=sql&query=select *from Categories&token=27487CA0BE14CF599444E8553E5E07F78D5D1AB8646302A2715E4802FCB95F08&format=json;調用數據集的 URL 格式為 POST/GET api/v1/dataset/{document id}/query。)

          POST 方式,有效負載格式:

          {
          "QueryType": "NONE|WAX",
          "Query": "some text like a WAX statement or empty"
          "DatasetParameters":{
          "Parameter1": "ParameterValue1"(單值),
          "Parameter2": "ParameterValue1,ParameterValue2" (多值使用逗號分隔)
          },
          "Format":Arrow | Json,
          "Options":{
          "Parameter1":"Value1"
          }
          }

          GET 方式,查詢參數

          ?format=Arrow | Json
          &
          $parameter1=value1
          &$parameter2=value2_1
          &$parameter2=value2_2
          &option1=value1
          &option2=value2

          option1, option2 ...為選項參數,前綴$表示數據集參數,多個值通過多次重復一個參數來表示。Option 選項參數具體信息如下:

          只需幾行簡單的代碼即可完成數據集的調用操作,這對嵌入式 BI 場景而言無疑是非常有價值的。API 層與 DIV 嵌入結合,可以為嵌入式 BI 場景需求提供令人滿意的解決方案。

          總體而言,雖然 iFrame 架構在入門門檻、開發成本和周期方面具有一定優勢,但隨著企業數據分析需求愈加復雜,DIV 架構很快就能表現出更強的擴展能力和適應性。團隊可以在初期選擇 iFrame 實現,并在需求提升后遷移到 DIV 方案。與此同時,開發團隊往往在一開始就要考慮 API 層的實現,為業務團隊帶來更多便利,并為后期的開發工作打好基礎。

          嵌入式 BI 選型:如何挑選最適合自己的方案?

          企業開發團隊在選擇嵌入式 BI 方案時,除了關注方案的開發周期、開發難度外,一般還要考慮定價模型、云端支持、業務系統集成支持等要素:

          • 成本。不僅要考慮初期的開發成本,還要考慮長期的總體擁有成本,將未來的功能擴展、安全性增強等需求納入成本計算。
          • 定價模型。第三方提供的嵌入式 BI 方案常常有多種定價模型可選,例如按用戶/服務器/CPU 定價,或者按照真實使用量、使用時間定價等。一般來說,相對固定的定價模型更有利于企業用戶一方。
          • 云端支持和業務系統集成支持。嵌入式 BI 能否支持公有云、私有云、本地部署、混合部署等多種模式,在云計算時代也是很重要的考慮因素。此外,與其他流行第三方企業系統(ERP、CRM、OA 等)集成的能力可以大大擴展嵌入式 BI 方案的應用范圍。
          • 授權管理/安全性。嵌入式 BI 模塊經常會與企業機密數據互動,這就要求嵌入式 BI 方案具備良好的授權管理能力和安全性,避免模塊本身成為企業安全性防線的薄弱環節,造成敏感數據的意外泄露事件。

          考慮到以上要素,實踐中中小企業和開發團隊更適合選擇成熟的第三方嵌入式 BI 方案來滿足自身需求。以 Wyn 商業智能提供的嵌入 BI 方案為例,其不僅提供了完善的功能、基于 GraphQL 的便捷 API 集成,還支持強大的授權管理、增強安全特性,兼容多種云端部署模式,且能夠方便地集成到用友、企業微信等系統中。該方案既可以嵌入部署也可以獨立使用,具備良好的伸縮能力,幫助企業持續深度挖掘數據價值。想要進一步了解關于嵌入式 BI 方案的相關內容,可以點擊以下鏈接獲取更多信息。

          者:前端Q

          轉發鏈接:https://mp.weixin.qq.com/s/ewFfXptccFs5KvjUINLGbQ

          前端

          小試牛刀,實現了六款簡單常見HTML5 Canvas特效濾鏡,并且封裝成一個純JavaScript可調用的API文件gloomyfishfilter.js。支持的特效濾鏡分別為:

          1.反色

          2.灰色調

          3.模糊

          4.浮雕

          5.雕刻

          6.合理

          濾鏡原理解釋:

          2.灰色調:獲取一個預期點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.模糊:基于一個5 * 5的卷積核

          4.浮雕與雕刻:

          根據當前預期的前一個預期RGB值與它的后一個重新的RGB值之差再加上128

          5.總體:模擬了物體在鏡子中與之對應的效果。

          雜項準備

          1、如何獲取Canvas 2d context對象

          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、如何添加一個DOM img對象到Canvas對象中

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

          3、如何從Canvas對象中獲取預定數據

          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、如何對DOM對象實現鼠標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、如何調用實現的gfilter API完成濾鏡功能

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

          6、瀏覽器支持:IE,FF,Chrome上測試通過,其中IE上支持通過以下標簽實現:

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


          效果演示:

          應用程序源代碼:

          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">灰色調</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    
                      }
              }
            },
          };

          總結

          感謝閱讀,如果你覺得我今天分享的內容,不錯,請點一個贊,謝謝!!


          主站蜘蛛池模板: 欧美日韩精品一区二区在线视频| 国产伦精品一区二区三区女| 日韩精品一区二区三区老鸭窝| 国产人妖视频一区在线观看| 无码一区二区三区在线观看| 国产精品成人一区二区三区| 国产一区二区不卡老阿姨| 成人无码一区二区三区| 狠狠综合久久av一区二区| 日本在线视频一区二区| 亚洲AV无码一区二区三区在线| 美女视频在线一区二区三区| 精品国产AⅤ一区二区三区4区| 四虎精品亚洲一区二区三区 | 无码国产精品一区二区免费vr| 无码人妻久久一区二区三区蜜桃 | 精品女同一区二区三区免费播放| 成人区人妻精品一区二区三区 | 亚洲国产精品综合一区在线 | 中文字幕一区二区区免| 国产日韩高清一区二区三区| 午夜精品一区二区三区在线视| 日本韩国黄色一区二区三区| 婷婷国产成人精品一区二| 日本中文字幕在线视频一区| 一区二区三区在线免费| 香蕉免费看一区二区三区| 精品aⅴ一区二区三区| 精品视频一区二区三区免费| 人妻体内射精一区二区三区| 亚洲一区二区三区播放在线| 亚洲av日韩综合一区二区三区 | 91久久精一区二区三区大全 | 亚洲国产精品第一区二区三区| 亚洲国产成人久久一区久久| 国产综合一区二区在线观看| 91在线精品亚洲一区二区| 亚洲AV无码国产一区二区三区| 在线不卡一区二区三区日韩| 精品国产一区二区三区久久蜜臀| 国产丝袜视频一区二区三区|