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
s一個非常重要的作用就是對dom進行操作,所謂的dom,可以理解為html代碼里的一個個節點。比如,body標簽元素就是一個dom。本文對js的dom操作進行一些總結。
按照慣例,先上一個剛寫好的小例子,代碼在最后給出:
現在,來看看js對dom的一些操作吧。
首先,給出一個html模板,接下來開始用js來做一些有趣的事情吧,css樣式的繪制就不細說了,先上代碼:
css
*{margin: 0;padding: 0;} .parent { width: 305px; height: 302px; background: #d7e6ea; margin: 100px auto; } .parent .child { width: 80px; height: 80px; background: deepskyblue; float: left; margin-top: 10px; margin-left: 9px; margin-right: 12px; margin-bottom: 12px; box-shadow: 3px -3px 2px #9898c7; text-align: center; line-height: 80px; font-family: "微軟雅黑"; font-size: 28px; text-shadow: 2px 2px 2px yellowgreen; }
html
<body> <div class='parent'> <div class='child'>1</div> <div class='child'>2</div> <div class='child'>3</div> <div class='child'>4</div> <div class='child'>5</div> <div class='child'>6</div> <div class='child'>7</div> <div class='child'>8</div> <div class='child'>9</div> </div> </body>
效果圖
從代碼中,我們可以看到,body是一個大節點,里面套了一個class屬性為parent的div盒子,然后我們又在這個盒子里面放了9個小盒子。
1.最簡單的dom方法封裝
在本系列中,假設我們不考慮用jQuery。
現在給第三個盒子添加一個id。
<div id='targetBox' class='child'>3</div>
如何拿到這個盒子呢?
很顯然,最先想到的肯定是document.getElementById() 方法,于是就有了這樣的代碼。
var box=document.getElementById('targetBox'); box.style.background='#FEAF51';
效果:
當然,我們很多時候都不希望每次都把document.getElementById(id)給寫一遍,那么,是不是可以將這一個過程封裝起來呢?
于是,自然而然的,我們會這么寫:
//獲取JavaScript的dom對象 function dom(id){ return document.getElementById(id); }; var box=dom('targetBox'); box.style.background='#FEAF51';
完美運行,我們知道,在jQuery中,是這樣的:
var box=$('#targetBox');
那么,為了讓代碼更加山寨,不妨將dom方法稍微改進一下嘞!
//獲取JavaScript的dom對象 function dom(id){ if(id.toString().indexOf('#') !=-1) { id=id.replace('#',''); } return document.getElementById(id); }; var box=dom('#targetBox'); box.style.background='#FEAF51';
2.如何獲取dom元素在父盒子中的位置?
剛才,我們已經獲得了編號為3的div盒子,要得到它在父盒子的角標位置,首先肯定要拿到它的父盒子對象吧。
像這樣:
var box=dom('#targetBox'); var parent=box.parentElement;
parent打印出來是這樣的:
看來很順利呢,接下來因為要知道目標元素在父盒子的位置,則需要拿到父盒子所有的孩子節點。
像這樣:
var children=parent.children;
打印結果:
接下來就要遍歷這些孩子節點啦,children 的數據類型是object。
然而,在js中我們可以遍歷數組,卻無法直接遍歷object,咋辦呢?
原來,這是一個特殊的object,因為它有一個length屬性。有length屬性的object,可以通過以下方式轉換成數組(注:當然,這邊也可以直接獲取獲取object中的length,然后來遍歷。):
Array.prototype.slice.call(object);
舉個例子:
var obj={length:2,0:'first',1:'second'}; objArr=Array.prototype.slice.call(obj); alert(objArr);
結果:
注1: length是幾個,就轉換幾個,如果你length寫1,那么只彈出first。
注2: key必須為數字,而且與數組的角標是對應的。
這里不深究call的的意思,我會在以后重新寫這方面的內容。
回到正題,現在可以拿到數組形式的children了!
var children=Array.prototype.slice.call(parent.children);
開始遍歷:
for(var i=0,len=children.length;i < len;i++){ if(children[i]==box){ alert(i); } }
結果:
彈出來下標是2,因為數組下標的起始值是從0開始的。
上面的循環結構還欠缺了一個東西,就是一旦找到box之后,因為及時退出循環才是。像這樣:
for(var i=0,len=children.length;i < len;i++){ if(children[i]==box){ alert(i); break; } }
這樣便可以一定程度地提高性能。順便附上forEach的寫法:
children.forEach(function(child,index){ if(child==box){ alert(index); return false; } });
這樣也可以,最后,將這些內容封裝成方法,就采用forEach的方式吧!
//查找當前dom元素在父盒子中的位置 function getIndex(dom){ var index=-1; var domArr=Array.prototype.slice.call(dom.parentElement.children); domArr.forEach(function(obj,i){ if(obj==dom){ index=i; return false; } }); return index; };
我學習js的路線就是如此,先想盡辦法把功能實現了,然后才開始封裝成方法。封裝的好處不言而喻,沒有人喜歡每次用到這個功能的時候,就去把實現代碼拷貝一份吧。
3.如何獲取parent下面指定class的元素列表?
parent盒子下面有9個孩子節點,我們能否通過一個什么辦法獲取到這9個孩子節點呢?顯然,這些孩子節點都有一個共同的className,那么我們可以通過這個className來獲取。
IE9 + 已經可以通過下面的方式來實現了:
var children=parent.getElementsByClassName('child');
效果:
IE678還是不支持的,那么,如果讓我們自己來封裝一個方法,又該如何呢?
這里提供一種思路:
1.用getElementsByTagName獲取parent元素下所有的節點。
2.遍歷這些節點,比較className,如果相同,就用一個數組裝起來。
3.返回這個數組。
上代碼:
/*通過className獲取dom元素進行過濾*/ function getClass(pid,sClass){ var aEle=dom(pid).getElementsByTagName('*'); var arrs=[]; for(var i=0;i<aEle.length;i++){ if(aEle[i].className.indexOf(sClass)!=-1){ arrs.push(aEle[i]); } } return arrs; }
最后,附上最開始小例子的源碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
*{margin: 0;padding: 0;}
body {
background: url(https://ss1.bdstatic.com/lvoZeXSm1A5BphGlnYG/skin/12.jpg?2) no-repeat;
background-size: 100% 128%;
overflow: hidden;
}
.content {
height: 600px;
width: 305px;
margin: 100px auto;
position: relative;
border-top:8px solid #ccc;
border-right:10px solid #ccc;
}
.content .screen {
height: 298px;
width: 305px;
background: #333;
position: absolute;
}
.content .screen .icon {
width: 78px;
height: 78px;
display: inline-block;
background: url(android.png) no-repeat;
background-size: 100% 100%;
position: absolute;
top: 50%;
left: 50%;
margin-top: -39px;
margin-left: -39px;
}
.parent {
width: 305px;
height: 302px;
background: #d7e6ea;
position: absolute;
bottom: 0px;
}
.parent .child {
width: 80px;
height: 80px;
background: #eee;
float: left;
margin-top: 10px;
margin-left: 9px;
margin-right: 12px;
margin-bottom: 12px;
box-shadow: 3px -3px 2px #9898c7;
text-align: center;
line-height: 80px;
font-family: "微軟雅黑";
font-size: 28px;
text-shadow: 2px 2px 2px yellowgreen;
}
.parent .child:hover {
cursor: pointer;
background: linear-gradient(#ccc,#666);
}
.putIn {
position: absolute;
width:100%;
height:60px;
line-height: 60px;
color: #fff;
bottom:0;
right: 0;/*為了讓padding起作用*/
text-align:right;
font-size: 40px;
overflow: hidden;
padding-right: 8px;
padding-bottom: 8px;
}
</style>
</head>
<body>
<div class="content">
<div class="screen">
<i class="icon"></i>
<span id="putIn" class="putIn"></span>
</div>
<div class='parent'>
<div class='child'>1</div>
<div class='child'>2</div>
<div id='targetBox' class='child'>3</div>
<div class='child'>4</div>
<div class='child'>5</div>
<div class='child'>6</div>
<div class='child'>7</div>
<div class='child'>8</div>
<div class='child'>9</div>
</div>
</div>
</body>
<script>
//獲取JavaScript的dom對象
function dom(id){
if(id.toString().indexOf('#') !=-1) {
id=id.replace('#','');
}
return document.getElementById(id);
};
var buttons=document.getElementsByClassName('child');
var putIn=dom('#putIn');
for(var i=0,len=buttons.length;i < len;i++){
buttons[i].onclick=function(){
var num=this.innerHTML;
if(putIn.innerText.length < 13 )
putIn.innerText=putIn.innerText + num;
}
}
</script>
</html>
包是JavaScript這門語言中一個非常強大的特性,它允許函數訪問并操作函數外部的變量。在深入理解閉包之前,我們先來看看什么是作用域和詞法作用域。
在JavaScript中,每個函數都有自己的作用域。作用域可以被視為一個變量存儲的環境,只有在這個環境中聲明的變量和函數才可以被訪問。詞法作用域是指在代碼編寫時函數和變量的作用域就已經確定下來,不會改變。
閉包是指那些能夠訪問自由變量的函數。所謂自由變量,是指在函數中使用的,但既不是函數參數也不是函數局部變量的變量。閉包可以記憶并訪問所在的詞法作用域,即使該函數在其詞法作用域之外執行。
閉包有多種用途,包括但不限于:
下面通過幾個實際的例子來演示閉包的概念。
這個例子展示了如何使用閉包來創建一個私有變量count,這個變量只能通過特定的函數來訪問和修改。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>閉包示例:計數器</title>
</head>
<body>
<button id="counterBtn">點擊我</button>
<p>點擊次數:<span id="count">0</span></p>
<script>
function createCounter() {
let count=0; // 私有變量
return function() {
count +=1;
document.getElementById('count').textContent=count;
};
}
const counter=createCounter();
document.getElementById('counterBtn').addEventListener('click', counter);
</script>
</body>
</html>
在這個例子中,createCounter函數返回了一個匿名函數,這個匿名函數能夠訪問createCounter函數作用域中的count變量。即使createCounter函數執行完成后,這個匿名函數依然能夠訪問到count變量,這就是閉包的作用。
閉包允許我們創建模塊化的代碼,我們可以將相關的功能封裝在一個函數中,只暴露必要的接口。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>閉包示例:模塊化</title>
</head>
<body>
<button id="helloBtn">問好</button>
<button id="byeBtn">告別</button>
<script>
const greetingModule=(function() {
const name='小明'; // 私有變量
function sayHello() {
alert('你好, ' + name + '!');
}
function sayGoodbye() {
alert('再見, ' + name + '!');
}
return {
hello: sayHello,
bye: sayGoodbye
};
})();
document.getElementById('helloBtn').addEventListener('click', greetingModule.hello);
document.getElementById('byeBtn').addEventListener('click', greetingModule.bye);
</script>
</body>
</html>
在這個例子中,我們創建了一個立即執行的函數表達式(IIFE),它返回了一個對象,這個對象包含兩個方法:sayHello和sayGoodbye。這兩個方法都可以訪問到私有變量name,但是外部代碼卻無法直接訪問name變量。這樣我們就創建了一個簡單的模塊,它封裝了私有數據和公共接口。
經典的面試題之一是在循環中使用閉包。下面的例子演示了如何正確地在循環中創建閉包。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>閉包示例:循環中的閉包</title>
</head>
<body>
<script>
function createButtons() {
for (var i=1; i <=5; i++) {
let button=document.createElement('button');
button.textContent='按鈕 ' + i;
button.addEventListener('click', (function(number) {
return function() {
alert('這是按鈕 ' + number);
};
})(i));
document.body.appendChild(button);
}
}
createButtons();
</script>
</body>
</html>
在這個例子中,我們在循環中創建了五個按鈕,并為每個按鈕添加了點擊事件監聽器。注意我們是如何使用立即執行的函數表達式來創建閉包的,它捕獲了當前的i值,并使每個按鈕都能彈出正確的編號。
閉包是JavaScript中一個非常強大的特性,它允許我們以優雅的方式封裝和管理數據和功能。理解閉包對于成為一名高效的前端工程師至關重要。以上例子僅僅是閉包用途的冰山一角,但它們展示了閉包的基本概念和一些常見的應用場景。掌握閉包,你將能夠編寫出更加模塊化、高效和可維護的代碼。
件是 Web 開發的方向,現在的熱點是 JavaScript 組件,但是 HTML 組件未來可能更有希望。 本文就介紹 HTML 組件的基礎知識:自定義元素(custom elements)。
一、瀏覽器處理
我們一般都使用標準的 HTML 元素。
<p>Hello World</p>
上面代碼中,<p>就是標準的 HTML 元素。
如果使用非標準的自定義元素,會有什么結果?
<greeting>Hello World</greeting>
上面代碼中,<greeting>就是非標準元素,瀏覽器不認識它。這段代碼的運行結果是,瀏覽器照常顯示Hello World,這說明瀏覽器并沒有過濾這個元素。
現在,為自定義元素加上樣式。
greeting { display: block; font-size: 36px; color: red; }
運行結果如下。
接著,使用腳本操作這個元素。
function customTag(tagName, fn){ Array .from(document.getElementsByTagName(tagName)) .forEach(fn); } function greetingHandler(element) { element.innerHTML='你好,世界'; } customTag('greeting', greetingHandler);
運行結果如下。
這說明,瀏覽器對待自定義元素,就像對待標準元素一樣,只是沒有默認的樣式和行為。這種處理方式是寫入 HTML5 標準的。
“User agents must treat elements and attributes that they do not understand as semantically neutral; leaving them in the DOM (for DOM processors), and styling them according to CSS (for CSS processors), but not inferring any meaning from them.”
上面這段話的意思是,瀏覽器必須將自定義元素保留在 DOM 之中,但不會任何語義。除此之外,自定義元素與標準元素都一致。
事實上,瀏覽器提供了一個HTMLUnknownElement對象,所有自定義元素都是該對象的實例。
var tabs=document.createElement('tabs'); tabs instanceof HTMLUnknownElement // true tabs instanceof HTMLElement // true
上面代碼中,tabs是一個自定義元素,同時繼承了HTMLUnknownElement和HTMLElement接口。
獲取方式:
1.在你手機的右上角有【關注】選項,或點擊我的頭像,點擊關注!(關注我)
2.關注后,手機客戶端點擊我的主頁面,右上角有私信,請私信發我:編程
電腦已經設置好了關鍵詞自動回復,自動領取就好了!這幾天上萬個消息,真的回復不過來,所以回復的時候請注意關鍵詞!
其實做為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要這里請私信我“編程”不管你是小白還是大牛歡迎入住大家一起交流成長。小編會在里面不定期分享干貨源碼,包括我精心整理的一份零基礎教程。歡迎各位感興趣的的小伙伴。
學習思路:
二、HTML import
有了自定義元素,就可以寫出語義性非常好的 HTML 代碼。
<share-buttons> <social-button type="weibo"> <a href="...">微博</a> </social-button> <social-button type="weixin"> <a href="...">微信</a> </social-button> </share-buttons>
上面的代碼,一眼就能看出語義。
如果將<share-buttons>元素的樣式與腳本,封裝在一個 HTML 文件share-buttons.html之中,這個元素就可以復用了。
使用的時候,先引入share-buttons.html。
<link rel="import" href="share-buttons.html">
然后,就可以在網頁中使用<share-buttons>了。
<article> <h1>Title</h1> <share-buttons/> ... ... </article>
HTML imports 的更多用法可以參考教程(1,2)。目前只有 Chrome 瀏覽器支持這個語法。
三、Custom Elements 標準
HTML5 標準規定了自定義元素是合法的。然后,W3C 就為自定義元素制定了一個單獨的 Custom Elements 標準。
它與其他三個標準放在一起—- HTML Imports,HTML Template、Shadow DOM—-統稱為 Web Components 規范。目前,這個規范只有 Chrome 瀏覽器支持。
Custom Elements 標準對自定義元素的名字做了限制。
“自定義元素的名字必須包含一個破折號(-)所以<x-tags>、<my-element>和<my-awesome-app>都是正確的名字,而<tabs>和<foo_bar>是不正確的。這樣的限制使得 HTML 解析器可以分辨那些是標準元素,哪些是自定義元素。”
注意,一旦名字之中使用了破折號,自定義元素就不是HTMLUnknownElement的實例了。
var xTabs=document.createElement('x-tabs'); xTabs instanceof HTMLUnknownElement // false xTabs instanceof HTMLElement // true
Custom Elements 標準規定了,自定義元素的定義可以使用 ES6 的class語法。
// 定義一個 <my-element></my-element> class MyElement extends HTMLElement {...} window.customElements.define('my-element', MyElement);
上面代碼中,原生的window.customElements對象的define方法用來定義 Custom Element。該方法接受兩個參數,第一個參數是自定義元素的名字,第二個參數是一個 ES6 的class。
這個class使用get和set方法定義 Custom Element 的某個屬性。
class MyElement extends HTMLElement { get content() { return this.getAttribute('content'); } set content(val) { this.setAttribute('content', val); } }
有了這個定義,網頁之中就可以插入<my-element>了。
<my-element content="Custom Element"> Hello </my-element>
處理腳本如下。
function customTag(tagName, fn){ Array .from(document.getElementsByTagName(tagName)) .forEach(fn); } function myElementHandler(element) { element.textConent=element.content; } customTag('my-element', myElementHandler);
運行結果如下。
ES6 Class 的一個好處是,可以很容易地寫出繼承類。
class MyNewElement extends MyElement { // ... } customElements.define('my-new-element', MyNewElement);
今天的教程就到這里,更多用法請參考谷歌的官方教程。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。