跳到主要內容區塊

計資中心電子報C&INC E-paper

技術論壇

【網站前端開發學習手札】Alpine-羽量級JS框架(下篇)
  • 卷期:v0069
  • 出版日期:2024-06-20

作者:陳俊佑 / 臺灣大學計算機及資訊網路中心程式設計組行政組員


本文接續【網站前端開發學習手札】Alpine-羽量級JS框架(上篇)介紹Alpine羽量級alpine基礎指令及魔法屬性...

 

前言

大家好,我是富田町47番地的社畜工程師柚子哥,Alpine-羽量級JS框架(下篇)將會介紹剩下的alpine基礎指令及魔法屬性給大家知道。

 

基礎指令()

x-effect:他主要功能是alpine的原件中的特定個生命週期會觸發副程式,一是第一次被渲染到DOM時觸發,第二個是數據更新時觸發。

以下範例內含兩個x-effect。

第一個是用input輸入去控制標題,內容進而觸發x-effect效果去呼叫LogTitle副程式,可以看到圖4輸入文字內容時圖5就會看到keyin每個數字時都呼叫一次副程式。

第二個範例則是用x-if去切換元件的開啟及關閉,由於x-if每次都會建置DOM跟刪除DOM,所以就可以看到圖7知道元件每次被渲染時都會呼叫一次setupEventListener副程式。

20240620_006908_01

圖1. x-effect指令

 

20240620_006908_02

圖2. x-effect指令初始畫面

 

20240620_006908_03

圖3. x-effect指令console.log畫面

 

20240620_006908_04

圖4.修改標題

 

20240620_006908_05

圖5.console.log顯示修改軌跡

 

20240620_006908_06

圖6.toggle時畫面

 

20240620_006908_07

圖7.重新toggle出現時會觸發副程式

 

x-ignore:簡單來說就是掠過該標籤下面所有alpine元件功能,以下的範例中label2上層被一個有x-ignore的div元件包住所以不會觸發x-text資料填入,label13的span則是直接被x-ignore掠過所以也不會觸發x-text資料填入。

 

20240620_006908_08

圖8. x-ignore指令

 

20240620_006908_09

圖9. x-ignore指令結果

 

x-cloak:跟x-if效果相近,主要是用來解決數據加載延遲導致畫面閃爍之類的問題,用x-cloak加載完再一次顯示,其使用方法必須在前面先定義一個CSS樣式[x-cloak] { display: none; }這寫法後面會再介紹,這是為了確保點擊之前是不顯示的,再來到程式碼中加入x-cloak,我們用一個button按鈕假裝是加載完要顯示的步驟,點了之後狀態改變就顯示出來相關數據。實際相關的應用可以用於反向的消失,例如是畫面剛進入數據還沒載完先出現轉圈圈loading畫面,數據載完之後loading畫面就消失了。

 

20240620_006908_10

圖10. x-cloak指令

 

20240620_006908_11

圖11. x-cloak指令未觸發狀況

 

20240620_006908_12

圖12. x-cloak指令觸發狀況

 

x-teleport:功能是將指定的元素放到指定的DOM標籤內,通常是用於管理布局之用,寫了一堆自訂的排版標籤或通用標籤,底下去維護標籤內該顯示那些DOM,還可以連同alpine邏輯一起放進去,真是十分方便,不過同樣會更動到DOM,所以指令要放在<template>標籤內,下面範例是x-teleport="customer_tag"我放一個我自製的標籤<customer _tag>,裡面放一個可以x-show的功能,如圖13,而圖15是按下按鈕就會顯示,圖16是實際的HTM,大家就會知道已經x-teleport渲染到customer_tag標籤內。

 

20240620_006908_13

圖13. x-teleport指令

 

20240620_006908_14

圖14.顯示畫面

 

20240620_006908_15

圖15.按下按鈕可成功執行

 

20240620_006908_16

圖16.實際HTML

 

x-id:是要介紹的最後一個指令,接下來就會進入到alpine魔法特性中,而x-id他其實單獨用是沒有特別的效果,他是一個定義x-id可以使用的區域,必須搭配魔法屬性($id)一起使用的,因此範例放在下面說。

 

魔法特性

Alpine有一些魔法特性是很有用的功能,便捷的語法可以簡化開發功能,增強與DOM的互動,其中使用語法是由錢字號($)開頭。

 

$id:主要功能是自動生成不會衝突的ID,你可以指定ID的名稱,而他自動生成的ID後綴會自己加編號,以確保每個ID都是唯一,用說的可能很模糊,我們直接用範例來看。

圖17中我在x-data中定義customer_tag容器內要顯示的ID是'customer-input-Username',而上面HTML中我分別用兩個獨立的<DIV>用x-id='[customer_tag]'定義他可以使用的範圍(可以邊寫邊喊領域展開!!),接著DIV內的label跟input內部的會有for跟id的標籤,使用組合技把x-bind指令跟$id(customer_tag)魔法屬性結合來綁定要產生的資料,這時打開HTML原始碼顯示出來的ID就真的幫你編號customer-input-Username-1跟customer-input-Username-2,真的是非常方便。

 

20240620_006908_17

圖17. $id魔法屬性

 

 20240620_006908_18

圖18. HTML觀看編碼ID

 

$el:這個魔法屬性是可以直接選取當前DOM節點,並直接使用,直接用範例來解釋比較快,我寫個猩八嗑咖啡的容量選單,其中共有三個radio,每個radio都用x-on:click="Message()"去讀取副程式,Message副程式中使用$el.value去讀取每個radio的value,並且用alert顯示出來。

 

20240620_006908_19

圖19. $el魔法屬性

 

20240620_006908_20

圖20.魔法屬性效果

 

$refs:這個魔術屬性上篇有提及到,主要是配合x-ref標籤使用,這邊再待大家詳細說明一下,範例裡的radio選單中加了一個x-ref標籤,一個button去控制副程式中去抓x-ref標籤並且去賦予勾選checked=true,實際效果顯如下圖。

 

20240620_006908_21

圖21. $refs魔法屬性

 

20240620_006908_22

圖22. 畫面

 

20240620_006908_23

圖23. 效果演示畫面

 

$watch:主要是監視用途,監視的數據有變化的話就會觸發,如同下方範例一開始先用個x-init初始話啟動一個副程式去開啟監視,而我們一但再input有輸入文字,就會觸發副程式,如果說應用面的話,大概可以說去即時去後端資料庫抓最新的股票價,監控到有變化觸發副程式,漲的話就文字變紅色,跌就文字變綠色之類的。

 

20240620_006908_24

圖24. $watch:魔法指令

 

20240620_006908_25

圖25.初始畫面

 

20240620_006908_26

圖26.更改文字

 

20240620_006908_27

圖27.console.log出文字

 

$dispatch:是個可以快速調度瀏覽器事件的好用功能。官方網頁寫了滿多的資料,我就用一個範例來說明其運作模式。這範例比較難懂一點,分別有2個按鈕,按鈕會觸發$dispatch('notify','按鈕A')跟btncount()。$dispatch會去調度notify的監聽器,並且把文字【按鈕A/按鈕B】傳入notify去控制,而notify用$event.detail去接收值並賦予到btn裡面。我們就可以看到畫面上會出現按鈕A/B被點擊的文字。

 

20240620_006908_28

圖28. $dispatch魔法屬性

 

20240620_006908_29

圖29. 初始畫面

 

20240620_006908_30

圖30. 按鈕A被點擊

 

20240620_006908_31

圖31. 按鈕B被點擊

 

$nextTick:這個魔法屬性功能是在使用Alpine更動數值之後,他才會執行$nextTick所綁定的函式,用說的比較模糊,我們直接看範例,範例中我依樣用一個按鈕做計數器,計數器的副程式中我加入3個console.log去看執行狀態,其中一個console.log是用$nextTick去呼叫,實際點一次計數器,從主控台那邊則會看到程式一開始跑第一個console.log會顯示【起始狀態:0】,接下來計數+1,在來跑計數器後面的console.log顯示【clicks++後的狀態:1】,最後才執行$nextTick去呼叫的console.log顯示【nextTick抓到的狀態:1】,由此大家應該可以知道$nextTick順序。

 

20240620_006908_32

圖32. $nextTick魔法屬性

 

20240620_006908_33

圖33. 起始畫面

 

20240620_006908_34

圖34. Console.log結果

 

$root:他從呼叫去去尋找DOM tree元素中最靠近有設定x-data的資料,因此下面的範例中我設定3個x-data,每個x-data是一層包一層,並每層設置按鈕,每個按鈕按一次,他就去往上抓最靠近的x-data,並且console.log出HTML 中的 data-* 属性。

※新手小補充:HTML 中的data-* 属性是一個自定義的屬性,”data-“開頭後面接想要的名稱,用於嵌入額外的資料,這資料不會渲染到畫面上,可以用JS或CSS去呼叫數據,可以用先前說過的x-bind把資料塞進去。

 

20240620_006908_35

圖35. $root魔法屬性

 

20240620_006908_36

圖36.按下按鈕console.log的結果

 

$data:是可以隨意調動目前x-data範圍內的所有x-data資料,我們用上面的範例改寫一下,AlpineXdata3()上面包了AlpineXdata2()跟AlpineXdata(),因此我們在AlpineXdata3()的這一層DOM去觸發按鈕抓資料,可以抓到AlpineXdata3()本身的say跟往上抓到AlpineXdata2()裡面的name還有最上一層AlpineXdata()的follow。

 

20240620_006908_37

圖37. $data魔法屬性

 

20240620_006908_38

圖38.console.log結果

 

$store:最後一個魔法屬性是可以使用全域變數的Alpine.store(),我們放在後面一起範例解說。

 

全域變數Globals

會重複使用的變數放在全域變數中,這邊會介紹Alpine中三個全域變數Alpine.data()、Alpine.store()、Alpine.bind()。

 

Alpine.data():在上篇中X-data中有說過如果如果資料過於攏長就可以用Alpine.data()提取到專用元件中,這寫法跟我用function呼叫方法實際作用一樣,差別在於一個是用return把alpine元件資料返回,另一個則是將函數作為alpine的元件,但如果是是要用於全域的元件部分還是建議使用Alpine.data()。

 

用法是加入JS語法的事件監聽document.addEventListener(event, function, useCapture),這邊簡單說一下語法,跟alpine無關但還是分享出來,event是觸發事件的類型(init、click、keyup等),function是事件發生要執行的函數,useCapture這參數可以略過,輸入是布林值,主要是控制target element跟ancestor element的執行順序,true是capture(由外層往內層執行)、false是bubbling(由內層往外層執行)。詳細細節可以見W3官方網站(https://www.w3.org/TR/DOM-Level-3-Events/#event-flow)

 

而監聽語法中event加入alpine初始化'alpine:init'時執行,而執行的函式內就加入Alpine.data,Alpine.data(‘alpine綁定的名稱’,()=>({  }),如此就完成了。

 

document.addEventListener('alpine:init', () => {

Alpine.data(AlpineXdata,()=>({

})

})

 

由於用途跟x-data一模一樣,所以下面範例是改寫官方的範例寫了進階的複合用法,給大家參考。HTML中建立兩個alpine的x-data,分別是dropdown跟timer。

 

dropdown是控制button按下時觸發的副程式跟x-if控制template的渲染,button的x-bind="trigger"這邊用了複合語法,之前範例中有關button的觸發語法可能會寫成<button @click.prevent="this.enabled = ! this.enabled">Start</button>,用x-on去觸發,但這邊的語法是用x-bind把alpine的指令給封裝在trigger中,其好處就是可以重複使用。

 

20240620_006908_39

圖39. x-bind把alpine的指令給封裝起來

 

Timer則是放計數器,DOM初始化要執行的程式就會放在init()、DOM被銷毀時會觸發的程式碼就放在destroy()。

 

所以整段程式碼運作起來會是,按了button觸發x-if,讓<span x-data="timer" x-text="counter"></span>渲染到畫面中,一旦渲染到畫面中時就會觸發timer的初始化程序init( ),就會開始計時並顯示到console.log上,而再按一次button觸發x-if,把<span x-data="timer" x-text="counter"></span>從DOM中銷毀,這時又會觸發銷毀程序destroy( ),把timer清除。

 

20240620_006908_40

圖40. init()及destroy()

 

20240620_006908_41

圖41. Console.log

 

Alpine.bind():這語法也很好用,就是當一個HTML屬性過多又或者會重複使用時可以用x-bind去封裝起來,從下面官方範例來看一個按鈕有3個屬性<button type="button" @click="doSomething()" :disabled="shouldDisable"></button>,type、click、disabled,全部都用x-bind="SomeButton"去包裝起來,看起來就乾淨多了。

 

20240620_006908_42

圖42. Alpine.bind()語法

 

Alpine.store():這是一個全域的狀態管理器,他可以跨不同alpine的組件共享狀態機制,共同取得資料跟修改資料。只要用$store的語法去控制就好,以下是非常簡單的範例,Alpine.store()定義count, click用$store.count++去把全域的count加一,x-text用$store.count取得資料狀態。

 

20240620_006908_43

圖43. Alpine.store()語法

 

結語

這篇就介紹到這邊,上下篇把所有的指令跟魔法屬性還有全域變數都講了一遍,相信大家已經感受到alpine的魅力,下一篇我將會介紹一些官方好用的Plugins讓大家知道。

感謝大家耐心的閱讀,如內容有誤請不吝指正,讓我知道最新最正確的資訊,也可以分享給大家少走冤枉路,謝謝。

 

參考資料

Alpine官網:https://alpinejs.dev/

Alpine GitHub:https://github.com/alpinejs/alpine

政府資料開放平台:https://data.gov.tw/

Mozilla:https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

w3:https://www.w3.org/TR/DOM-Level-3-Events/#event-flow