iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
0
Modern Web

小白的JavaScript讀書日記系列 第 14

Day14:操作HTML (五)

  • 分享至 

  • xImage
  •  

今天要聊的是使用JavaScript操作樣式表,通常我們在寫網頁時,可以用css來操作的效果,也可以透過JS來達到,以及一些進階事件的處理,我們開始吧!


透過JavaScript操作樣式表

操作行內樣式
以下範例是用JavaScript做到css裡面hover的效果,
請看程式碼:

<body>
  <!--操作範例-->
  <div id="elem">滑鼠移入時改變顏色</div>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let elem = document.getElementById('elem');

      //滑鼠移入時改變背景顏色(藍)
      elem.addEventListener('mouseover', function () {
        this.style.backgroundColor = 'blue';
      })

      //滑鼠移出時恢復背景顏色
      elem.addEventListener('mouseout', function () {
        this.style.backgroundColor = '';
      })
    })
  </script>
</body>

上述範例是透過事件監聽來操作div行內的樣式表,
語法:
elem.style.prop = value
elem:元素物件
style:樣式屬性
value:設定值

要注意的是,如果是用JS來操作,樣式屬性名稱和css裡面的是不同的,例如:
css:background-color / JS:backgroundColor
css:border-top / JS:borderTop
我們可以發現,在JavaScript操作時,需要除 - 連字符好,且第一個英文單字以後的英文單字,開頭第一個字必須為大寫。

套用外部樣式表 className
上述方法,操作行內樣式雖說可以直接在div中設定樣式,但程式碼看起來會叫雜亂,要修改時也不方便。所以通常我們會將css獨立寫成一個.css檔案,再載入html裡面。
這邊要介紹使用className屬性來存取.css檔案中的樣式。
語法:
elem.className = clazz
elem:元素物件
clazz:樣式類別

接著我們來改寫上述操作行內樣式的例子:
css檔案(all.css):

.highlight{
  background-color: yellow;
}

html檔案:

<!--載入all.css-->
  <link rel="stylesheet" href="./all.css">
  <title>My title</title>
</head>
<body>
  <!--操作範例-->
  <div id="elem">滑鼠移入時改變顏色</div>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let elem = document.getElementById('elem');

      //滑鼠移入時改變背景顏色(藍)
      elem.addEventListener('mouseover', function () {
        this.className = 'highlight';
      })

      //滑鼠移出時恢復背景顏色
      elem.addEventListener('mouseout', function () {
        this.className = '';
      })
    })
  </script>

p.s如果要載入多個樣式類別可以寫成這樣 elem.className = 'clazz','clazz'。
試看看:
在all.css檔案中,新增以下程式碼:
.textcolor{color:red;}
接著更改,html檔案中的這行程式碼:
this.className = 'highlight';
改為下列程式碼:
this.className = 'hightlight textcolor';
我們可以發現,當滑鼠移入時,不僅背景顏色改變了,連字體顏色都改變了。

更簡單的操作樣式類別 classList
我們可以透過classList屬性,更直覺的操作class屬性值。
請看以下範例(改寫上述滑鼠滑入,為點擊):

<body>
  <!--操作範例-->
  <div id="elem" class="textcolor">滑鼠點擊後改變顏色</div>
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let elem = document.getElementById('elem');

      //滑鼠移入時改變背景顏色(藍)
      elem.addEventListener('click', function () {
        this.classList.toggle('highlight');
      })
    })
  </script>
</body>

上述範例中所使用的toggle是對於樣式類別on/off的切換。
以下附上w3c提供的classList可以用的成員,可以參考參考。
https://www.w3schools.com/jsref/prop_element_classlist.asp

進階事件處理

我們在Day11中有提到事件監聽/處理,這邊將針對先前的內容作進階的介紹。

取得事件相關資訊 - 事件物件
事件監聽器/事件處理程序中可以接收一個稱為事件物件的物件,從該物件可以取得事件觸發時的各種資訊,請看例子:

<body>
  <!--操作範例-->
  <input type="button" value="點擊" id="btn">
  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let elem = document.getElementById('btn');

      elem.addEventListener('click', function (e) {
        console.log('觸發端:' + elem.nodeName + '/' + elem.id);
        console.log('種類:' + e.type)
      })
    })
    //console:
    //觸發端:INPUT/btn
    //種類:click
  </script>
</body>

從上述例子,我們從elem取得事件物件e,並透過他來接收事件觸發時的相關資訊(console的結果)。
下面附上事件物件可以用的成員列表:
HTML DOM Event Properties and Methods
https://www.w3schools.com/jsref/dom_obj_event.asp

下面我們看一些範例:
顯示某區域內滑鼠指標的所在位置

this關鍵字
我們很常在程式碼內看到this來代表程式觸發端,以下我們比較一下this的用法:

  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let data = {
        title: '神鵰俠侶',
        price: '460',
        show: function () {
          console.log(this.title + '/' + this.price + '元');
        }
      };
      document.getElementById('btn').addEventListener('click', data.show);
    })
  </script>

上述程式碼我們預期在console應該要輸出神鵰俠侶/460元,但實際上卻是/undefined元!?
這是因為data.show沒有參考到data.title和data.price,而是參考到document.getElementById('btn'),所以輸出是undefined。
而為了避免這樣的問題,我們必須用Function物件內的bind()方法。
bind()方法的語法:
func.bind(that [,arg1 [,arg2 [...]]])
func:函式物件
that:函式中表示this關鍵字的東西
arg1,arg2...:傳入函式的參數

因此我們可以改寫程式碼:document.getElementById('btn').addEventListener('click', data.show)

document.getElementById('btn').addEventListener('click', data.show(data))
就可以得到“神鵰俠侶/460元”

w3c的this參考資料:
https://www.w3schools.com/js/js_this.asp

使用箭頭函式固定this
再看一個this的例子:

<body>
  <input type="button" id="btn" value="show">

  <script>
    document.addEventListener('DOMContentLoaded', function () {
      let Counter = function (elem) {
        this.count = 0;
        this.elem = elem;
        elem.addEventListener('click', function () {
          this.count++;
          this.show();
        })
      }
      Counter.prototype.show = function () {
        console.log(this.elem.id + '被點擊' + this.count + '次')
      }
      let c = new Counter(document.getElementById('btn'))
    })
    //結果:Uncaught TypeError: this.show is not a function
  </script>
</body>

在上述例子中,我們可以用之前提到的bind()方法來解決,也可以用箭頭函式來修改:
將這段程式碼

elem.addEventListener('click', function () {
          this.count++;
          this.show();
        })

修改為

elem.addEventListener('click', () => {
          this.count++;
          this.show();
        })
//結果:btn被點擊1次...2次

便可正常執行,原因是因為在箭頭函式中,this由本身宣告的地方決定,也就是說,它會指向函式所指示的this本身,因此可以輸出結果。
p.s.:箭頭函式是ES6開始才有的,這邊附上MDN的參考資料:
https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions
以及更多箭頭函式的實力(出自六角-卡斯伯大神):
https://wcc723.github.io/javascript/2017/12/21/javascript-es6-arrow-function/




今日總結:

  • 透過JavaScript操作樣式表:套用外部樣式className,classList
  • 進階事件處理:e、this,箭頭函數(this)。

希望透過今天的例子,可以再加強一些實務上用得到的方法。


上一篇
Day13:操作HTML (四)
下一篇
Day15:瀏覽器物件的基礎
系列文
小白的JavaScript讀書日記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言