打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
DOM系列:樣式和類

對於任何一位Web開發者而言,處理CSS樣式很多時候還是會借助JavaScript。簡單的說,我們會碰到一些交互(或UI效果的變化)都會通過JavaScript來處理style或類。那麼今天我們將要學習的是如何通過JavaScript來控制樣式和類名,在深入討論JavaScript處理樣式和類的方法之前,我們需要知道在Web頁面中元素的樣式處理通常有兩種方式。

  • 在HTML添加類名,然後在CSS樣式文件中處理樣式
  • 通過JavaScript控制HTML元素的style屬性,改變元素樣式

雖然上面提到的方法都可以處理頁面元素的樣式,但CSS始終是最佳選擇 —— 不僅對HTML如此,在JavaScript中也是如此。因為我們一直遵守的是:分離

當然很多時候,只使用CSS的類方式並不一定能達到我們要的結果(也就是說類再也無法處理時),那麼我們就必須使用JavaScript操作HTML元素中的style屬性。 比如,如果我們要動態計算元素的坐標,並想通過JavaScript來設置,那麼我們就可以像下面這樣做:

elem.style.left = leftelem.style.top = top

這只是其中的一種情景,事實上還有很多其他的情景,比如將文本的顏色變成紅色,比如添加一個背景圖片。其實,通過JavaScript來控制CSS類名,更靈活,更容易支持。

至於為什麼要這麼做,或者要怎麼做,接下來的內容就是圍繞著這些方面來闡述,感興趣的,歡迎繼續往下閱讀。

為什麼要使用JavaScript設置樣式

文章開頭我們提到了可以通過JavaScript來控制Web的樣式。那麼為什麼要使用JavaScript設置元素樣式?在深入討論之前,我們有必要知識為什麼要使用JavaScript來設置元素樣式。在常見的情況下,咱們可以通過樣式文件(就是.css文件或style標籤)或內聯樣式(元素中調用style屬性)來控制Web元素的外觀。這也可能是大家更多時候想要的。

但在很多時候,是希望內容更具交互性,打個比方說,你希望根據用戶輸入的狀態(比如鼠標單擊或者懸浮)引入別的樣式,這些樣式代碼在後台運行。雖然像hover這樣的偽選擇器提供了一些支持,但是功能還是有很多限制。

言外之意,很多更具交互性(或者說更多的富交互性)的解決方案是需要強度依賴JavaScript。JavaScript不僅可以讓你在與之交互的元素上進行樣式變化,更重要的是,它允許你在整個頁面中使用樣式。可以說這種自由性是非常強大的,而且遠遠超出了CSS對內容樣式能力的限制。

兩種處理樣式的方式

正如文章開頭提到的,如果要控制元素的樣式變化,有兩種方法可能使用JavaScript來修改。一種方法是直接在元素上設置CSS屬性(其實就是通過元素內聯的style屬性來實現)。另一種方法是從元素中添加或刪除類名,這可能導致Web運用或Web程序忽略某些樣式規則。接下來我們會圍繞著這兩種方式進行深入的學習。

直接設置style

在學習如何直接修改元素的style(或者如標題寫的一樣,直接通過設置style)屬性來改變元素的樣式之前,需要先花點時間來瞭解CSSStyleDeclaration接口。

CSSStyleDeclaration接口可以用來操作元素的樣式。常見的方式(接口)有:

  • 元素節點的style屬性,即HTMLElement.style,也就是前面介紹的方式
  • CSSStyle實例的style屬性,即HTMLElement.style.cssText
  • window.getComputedStyle()

HTMLElement.style

通過JavaScript訪問的每個HTML元素都有一個style對象。該對象允許您指定CSS屬性並設置其值。比如你在瀏覽器控制台中輸入$0.style就可以看到類似下圖這樣的一個截圖:

從上圖可以看出來,style對象下有的CSS屬性。言外之意,上圖中的CSS屬性(還有很多沒截到,可以點擊這裡查閱讀所有的屬性)可以通過elem.style.property = 'value'的方式來設置對應屬性的值。例如,咱們想對$0設置背景顏色:

$0.style.backgroundColor = '#d93600'

$0事實上對應的就是你在瀏覽器控制台中選中的元素。

簡單地說,要直接使用JavaScript來控制元素樣式,第一步是要選中要被修改樣式的元素。上面示例使用的是$0這樣的快速選擇元素方式(在瀏覽器控制台中可以這麼使用),在JavaScript中,可以使用querySelector()方法選中元素,當然在JavaScript中還可以使用其他的方式,比如前面《getElement*querySelector*》一文中介紹選中元素的方法。第二步是找到你關心的CSS屬性(想要更換的CSS樣式屬性,比如上例中的backgroundColor,其實對應的就是CSS中的background-color),然後給該屬性賦值。需要注意的是,CSS中的許多值實際上是字符串。也要記住,很多值需要帶有像pxem這樣的度量單位才能被識別。

通過elem.style.poperty方式修改元素的樣式,實際上修改的是HTML元素的style屬性的值。比如:

總而言之,可以控制HTML元素的style屬性來修改任何你想修改的HTML元素的樣式

也就是說,style是HTML元素的一個標籤屬性,也就是說它也是元素節點。既然是DOM元素的節點,我們就可以通過getAttributesetAttributeremoveAttribute等方法來讀寫或刪除DOM元素的style屬性。就上面的示例,咱們可以使用setAttribute()實現同樣的效果,比如:

$0.setAttribute(    'style',    'background-color: orange; z-index: 9999; border-left-width: 5px;')

如果你對getAttributesetAttributeremoveAttribute從未接觸或不太瞭解,建議你花點時間閱讀前面整理的文章《AttributeProperty》一文。

上面的示例演示了HTMLElement.style屬性來給HTML元素添加樣式,其效果等同於使用HTMLElement.setAttribute('style','屬性值')。事實上,HTMLElement.style屬性返回的是一個CSSStyleDeclaration對象,表示元素的內聯style屬性,但會忽略樣式表應用的屬性。

CSSStyleDeclaration接口中的HTMLElement.style接口除了給HTML元素寫CSS樣式之外,也可以讀:

$0.style.backgroundColor    // => "orange"$0.style.zIndex             // => "9999"$0.style.borderLeftWidth    // => "5px"

上面代碼中,style屬性的值是一個CSSStyleDeclaration實例。這個對象所包含的屬性與CSS規則一一對應,但CSS屬性名需要改寫,比如background-color要改成駝峰寫法,即backgroundColor。還有一點要特別的注意,如果CSS屬性名是JavaScript保留字,則樣式名之前需要加上字符串css,比如float要寫成cssFloat

HTMLElement.style.cssText

前面的示例也看到了,除了通過setAttribute('style','styleProperty:styleValue')方式給HTML元素的style設置樣式之外,還可以通過HTMLElement.style.propery=value的方式來給style屬性添加樣式。但對於要給一個元素添加多個屬性值時,需要多次寫,對於追求極速開發體驗的碼農而言,總感覺會有點蛋疼。在CSSStyleDeclarationHTMLElement.style.cssText屬性用來讀寫當前元素style的值。

先來看讀:

$0.style.cssText

輸入的值是:

background-color: orange; z-index: 9999; border-left-width: 5px;    

同樣的,如果我們要給一個元素添加樣式,也可以使用.style.cssText方式,比如:

$0.style.cssText = 'color:#f36; font-size: 2rem;padding: 10px'

這個時候對應的元素的style值變成:

使用HTMLElement.style.cssText給元素的style添加值是要特別注意,如果元素的style屬性一開始就有值,使用上面的方式添加值的話將會覆蓋原有的屬性值。比如:

值得慶幸的是,我們可以使用下面的方式來改變:

$0.style.cssText += 'color:#f36; font-size: 2rem; padding: 10px'

其中colorfont-sizepadding屬性被追加到元素的style上,而不是直接覆蓋,比如下圖所示:

注意,使用cssText的屬性值不用改寫CSS屬性名。

另外,在使用cssText時要給一個元素刪除style中的樣式,可以給該方法設置值為空字符串,比如:

$0.style.cssText = '';

window.getComputedStyle()

眾所周知,HTML元素的行內樣式是具有最高的優先級,改變行內樣式,通常會立即反映出來。但是,HTML中DOM元素最終的樣式是綜合各種規則計算出來的。也就是說,要想得到元素實際樣式,只讀取行內樣式是不夠的,需要得到瀏覽器最終計算出來的樣式規則。

至於CSS樣式是怎麼被瀏覽器計算出來的,真正要理解就要去理解瀏覽器的工作原理相關的知識了。有關於這部分就不在這裡闡述了,如果你感興趣,可以閱讀下面幾篇文章:

如果你花時間閱讀了上面的文章或者說你對瀏覽器渲染CSS有一定的瞭解的話,那麼就知道,瀏覽器解析CSS樣式一共有五個來源,其中開發人員只能接觸其中的三個來源,HTML元素內聯 style屬性,HTML的style標籤樣式和link引用樣式;其中另外兩個是瀏覽器客戶端的樣式:瀏覽器默認樣式和瀏覽器用戶自定義樣式。用一張圖簡單的描述就如下圖所示:

其實,如果你平時細心的話,在使用瀏覽器自帶的開發者工具的時候,你就可以查看到瀏覽器對元素計算出來的屬性,比如下圖:

而在JavaScript中,咱們就可以使用window.getComputedStyle方法返回瀏覽器計算後得到的最終樣式規則(即計算出來的樣式)。這個方法接受一個節點對象作為參數,返回一個CSSStyleDeclaration實例,它包含了指定節點的最終樣式信息。比如:

上圖可以看到元素$0計算出來的最終樣式信息。如果我們把其賦值給一個變量,比如objStyle,那麼我們可以通過類似下面的方式取出元素對應的樣式屬性的值:

objStyle.color              // => rgb(64, 64, 64)objStyle.backgroundColor    // => rgba(0, 0, 0, 0)

getComputedStyle方法還可以接受第二個參數,表示當前元素的偽元素,比如:before:after:first-line:first-letter等。

window.getComputedStyle($0, ':before')

需要注意的是,節點元素的style對象無法讀寫偽元素的樣式,這個時候就需要用到window.getComputedStyle。使用JavaScript獲取偽元素可以用類似下面這樣的方法:

window.getComputedStyle($0, ':before').color

除此之外,還可以使用接下來要介紹的CSSStyleDeclaration實例的getPropertyValue方法。比如:

window.getComputedStyle($0, ':before').getPropertyValue('color')

在使用CSSStyleDeclaration實例有幾點需要注意:

  • CSSStyleDeclaration實例返回的CSS值都是絕對單位。比如,長度都是像素單位,顏色是rgb()rgba()格式
  • CSS規則的簡寫形式無效。比如,margin的值不能直接讀,需要分開來讀,比如marginLeftmarginTop
  • 如果讀取CSS原始的屬性名,要用方括號運算符,比如objStyle['z-index'],也可以換成駝峰方式objStyle.zIndex
  • 該方法返回的CSSStyleDeclaration實例的cssText屬性無效,返回undefined

CSSStyleDeclaration實例的其他方法

CSSStyleDeclaration實例除了上述的一些方法之外,還有其他的一些方法或屬性。接下來咱們要學習的就是有關於他的屬性和方法。

前面也提到過了,CSSStyleDeclaration實例返回的是一個object,那麼我們object的一些屬性和方法也可以用到這裡。比如lengthitem()之類的等。比如:

let ele = document.querySelector('#viewport')let objStyle = window.getComputedStyle(ele)objStyle.length // => 292objStyle[0]     // => animation-delay

我們也可以通過for循環把其每個屬性打印出來,比如:

for (let i = 0; i < objStyle.length; i++) {    console.log(objStyle[i])}

除此之外,還有幾個實例方法:

  • CSSStyleDeclaration.getPropertyPriority方法接受 CSS 樣式的屬性名作為參數,返回一個字符串,表示有沒有設置important優先級。如果有就返回important,否則返回空字符串。
  • CSSStyleDeclaration.getPropertyValue方法接受 CSS 樣式屬性名作為參數,返回一個字符串,表示該屬性的屬性值。
  • CSSStyleDeclaration.removeProperty方法接受一個屬性名作為參數,在 CSS 規則裡面移除這個屬性,返回這個屬性原來的值。
  • CSSStyleDeclaration.setProperty方法用來設置新的 CSS 屬性。該方法沒有返回值。

有關於getComputedStyle更詳細的介紹可以閱讀:

通過classNameclassList控制樣式

在我們Web的開發中,通過控制HTML元素的的類名(添加或刪除),從而來控制元素的樣式,這也是非常常見的方式。在JavaScript中,可以通過classNameclassList來給元素添加或刪除樣式,從而實現元素樣式的修改。

通過className添加和刪除類

通過前面的學習,我們知道className屬性允許你訪問HTML元素的class屬性。通過HTMLElement.className可以讀出HTML元素的class屬性的值。同樣的,給className賦值,可以給元素添加類名,但不同的是,新的類名將會覆蓋舊的類名。比如下面這樣的一個操作:

可以看到,新添加的new類名,覆蓋了已有的jhp類名。如果想讓新添加的類名不覆蓋已有的類名,可以通過+=的方式來添加,比如:

$0.className += ' jhp'

這個時候重新打印className,其值就是new jhp,在對應的HTML元素相比較而言就成功的添加了新的類名。

不過這樣寫,有點蛋疼,咱們可以將其封裝成一個函數,比如addClass()

function addClass(elements, myClass) {    // 如果沒有元素,我們就跳出函數    if (!elements) {        return;    }    // 如果有一個選擇器,將獲取所選擇的元素    if (typeof(elements) === 'string') {        elements = document.querySelectorAll(elements)    }    // 如果我們只有一個DOM元素,那麼將它作為一個簡化的數組件來操作    else if (elements.tagName) {        elements = [elements]    }    // 向所有選中的元素添加類    for (var i = 0; i < elements.length; i++) {        // 如果類名不存在        if ((' ' + elements[i].className + ' ').indexOf(' ' + myClass + ' ') < 0) {            // 添加類            elements[i].className += ' ' + myClass        }    }}

有了這個函數之後,咱們就可以這樣使用了:

addClass('.classdiv','highlight');addClass(document.getElementById('iddiv'),'highlight');

使用className給指定的元素刪除一個類名,相對來說比較麻煩一點。比如上例,咱們使用addClass()函數之後,通過$0.className可以讀取出當前元素$0class的值為new jhp primary。如果我們要把類名重新恢復到new jhp時,只能像下面這樣:

$0.className = 'new jhp'

為了能更好的操作,咱們也可以類似於addClass()函數一樣,寫一個removeClass()

function removeClass(elements, myClass) {    // 如果沒有這個元素,直接跳出函數    if (!elements) {        return;    }    // 如果有一個選擇器,將獲取所選擇的元素    if (typeof(elements) === 'string') {        elements = document.querySelectorAll(elements)    }    // 如果我們只有一個DOM元素,那麼將它作為一個簡化的數組件來操作    else if (elements.tagName) {        elements = [elements]    }    // 創建查找類的模式    var reg = new RegExp('(^| )' + myClass + '($| )', 'g')    // 從選中的元素中刪除類    for (var i = 0; i < elements.length; i++) {        elements[i].className = elements[i].className.replace(reg, ' ')    }}

如果要在指定的元素中刪除一個類名,就可以像下面這樣使用:

removeClass($0, 'new')

最後的結果正如我們所希望的一樣:

特別聲明,上面addClass()removeClass()兩函數的的代碼來源於@Yaphi Berhanu寫的博文

通過classList來添加和刪除類等

上面看的是className給指定元素的class中添加和刪除類。事實上,咱們還可以使用classList。在classList中主要的API有:

  • elem.classList.add(): 添加類名
  • elem.classList.remove():刪除類名
  • elem.classList.toggle():切換類名,如果改類名存在將會刪除該類名,如果不存在將會添加該類名
  • elem.classList.contains:判斷是否含有該類名,如果包含則返回true,反之返回的是false

比如我們當前元素$0,可以在瀏覽器中輸出$0.classList對應的值。從返回的結果上可以看出來,其返回的是DOMTokenList。而且從其__proto__中可以找到classList對應的API,比如addcontainsremove等。

DOMTokenList這種類型表示一組空間分隔的標記。通常由HTMLElement.classList, HTMLLinkElement.relList, HTMLAnchorElement.relListHTMLAreaElement.relList返回。從0開始的類JavaScript數組索引。DOMTokenList始終是區分大小寫的。

classList.add()

使用classList.add()添加類名,咱們可以像下面這樣:

$0.classList.add('make', 'me', 'look', 'rad')

classList.contains()

通過classList.contains()可以判斷元素是否包含指定的類名,如果包含返回的是true,如果沒包含返回的是false

$0.classList.contains('new')    // => false$0.classList.contains('make')   // => true

classList.remove()

使用classList.remove()可以刪除指定的類名。比如:

classList.toggle()

其實該API就類似一個開關。打個比方說,如果當前元素中有指定的類名,那麼執行該 API之後會將指定的類名刪除,返之將會添加。類似這樣的一個操作:

if ($0.classList.contains('rad')) {    $0.classList.remove('rad');} else {    $0.classList.add('rad');}

上面的這個功能,就可以使用classList.toggle來替代:

$0.classList.toggle('cool')

使用classList.toggle表示:如果添加類,將返回true,如果刪除類,將返回false

let a = $0.classList.toggle('cool');console.log(a); // => true 

classList.toggle可以選擇接受第二個參數,該參數是一個布爾值。可以根據第二個參數來控制是否添加還是刪除類。

let someCondition;let b = shadesEl.classList.toggle('cool', !!someCondition);console.log(b); // => false, `someCondition` 是 undefined,計算結果是false, class被刪除someCondition = 'I wear my sunglasses at night';let c = shadesEl.classList.toggle('cool', !!someCondition);console.log(c); // => true, `someCondition` 計算出來的結果是true, class被添加

有了classList之後,那麼前面寫的addClass()removeClass()就可以修改一下了。把以前的className替換成現在的classList。如此一來,代碼會變得簡單的多。比如:

function addClass(elements, myClass) {    elements = document.querySelectorAll(elements)    for (var i = 0; i < elements.length; i++) {        elements[i].classList.add(myClass)    }}function removeClass(elements, myClass) {    elements = document.querySelectorAll(elements)    for (var i = 0; i < elements.length; i++) {        elements[i].classList.remove(myClass)    }}
classList其他API

classList除了上面一些常用的API之外,還有lengthvalue屬性以及entriesforEachitemkeys等。大家可以根據實際需要的去選擇所需要的API。比如:

有關於classList更多的介紹可以閱讀:

總結

通過上面的學習,知道如何通過JavaScript來修改CSS樣式。我們平常中會使用到的方法會有:

  • 通過DOM Element對象的getAttribute()setAttribute()removeAttribute()等方法修改元素的style屬性
  • 通過對元素節點的style來讀寫行內CSS樣式
  • 通過style對象的cssText屬性來修改全部的style屬性
  • 通過style對象的setProperty()getPropertyValue()removeProperty()等方法來讀寫行內CSS樣式
  • 通過window.getComputedStyle()方法獲得瀏覽器最終計算的樣式規則
  • 通過classNameclassList給元素添加或刪除類名,配合樣式文件來修改元素樣式

其實除了上述介紹的方法之外,咱們還可以直接添加樣式。常見的方式是通過創建style標籤來添加內置的CSS樣式表或者通過link標籤來引用外部樣式表。另外還可以使用addRuleinsertRule來添加樣式規則。不過在這篇文章我們沒有介紹這些內容,我們將在後續的內容中再來學習這方面的知識。如果你對這方面的知識感興趣,歡迎持續觀注後續的更新。

由於自身是JavaScript的初學者,如果文章中有不對之處,煩請各位拍正。如果您在這方面有更多經驗,歡迎在下面的評論中與我們一起分享。如果你覺得這篇文章幫助你了,歡迎給我打賞(^_^)!!!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
JavaScript学习笔记之CSS
开发跨浏览器JavaScript---《Ajax基础教程》笔记 - java - CSDN...
如何在 JavaScript 中创建虚拟键盘
你可能不需要 jQuery!使用原生 JavaScript 进行开发
网站如何做到完全不需要使用jQuery
JS30 - 01 JavaScript Drum Kit
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服