作者:陳俊佑 / 臺灣大學計算機及資訊網路中心程式設計組行政組員
本文接續【網站前端開發學習手札】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副程式。
圖1. x-effect指令
圖2. x-effect指令初始畫面
圖3. x-effect指令console.log畫面
圖4.修改標題
圖5.console.log顯示修改軌跡
圖6.toggle時畫面
圖7.重新toggle出現時會觸發副程式
x-ignore:簡單來說就是掠過該標籤下面所有alpine元件功能,以下的範例中label2上層被一個有x-ignore的div元件包住所以不會觸發x-text資料填入,label13的span則是直接被x-ignore掠過所以也不會觸發x-text資料填入。
圖8. x-ignore指令
圖9. x-ignore指令結果
x-cloak:跟x-if效果相近,主要是用來解決數據加載延遲導致畫面閃爍之類的問題,用x-cloak加載完再一次顯示,其使用方法必須在前面先定義一個CSS樣式[x-cloak] { display: none; }這寫法後面會再介紹,這是為了確保點擊之前是不顯示的,再來到程式碼中加入x-cloak,我們用一個button按鈕假裝是加載完要顯示的步驟,點了之後狀態改變就顯示出來相關數據。實際相關的應用可以用於反向的消失,例如是畫面剛進入數據還沒載完先出現轉圈圈loading畫面,數據載完之後loading畫面就消失了。
圖10. x-cloak指令
圖11. x-cloak指令未觸發狀況
圖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標籤內。
圖13. x-teleport指令
圖14.顯示畫面
圖15.按下按鈕可成功執行
圖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,真的是非常方便。
圖17. $id魔法屬性
圖18. HTML觀看編碼ID
$el:這個魔法屬性是可以直接選取當前DOM節點,並直接使用,直接用範例來解釋比較快,我寫個猩八嗑咖啡的容量選單,其中共有三個radio,每個radio都用x-on:click="Message()"去讀取副程式,Message副程式中使用$el.value去讀取每個radio的value,並且用alert顯示出來。
圖19. $el魔法屬性
圖20.魔法屬性效果
$refs:這個魔術屬性上篇有提及到,主要是配合x-ref標籤使用,這邊再待大家詳細說明一下,範例裡的radio選單中加了一個x-ref標籤,一個button去控制副程式中去抓x-ref標籤並且去賦予勾選checked=true,實際效果顯如下圖。
圖21. $refs魔法屬性
圖22. 畫面
圖23. 效果演示畫面
$watch:主要是監視用途,監視的數據有變化的話就會觸發,如同下方範例一開始先用個x-init初始話啟動一個副程式去開啟監視,而我們一但再input有輸入文字,就會觸發副程式,如果說應用面的話,大概可以說去即時去後端資料庫抓最新的股票價,監控到有變化觸發副程式,漲的話就文字變紅色,跌就文字變綠色之類的。
圖24. $watch:魔法指令
圖25.初始畫面
圖26.更改文字
圖27.console.log出文字
$dispatch:是個可以快速調度瀏覽器事件的好用功能。官方網頁寫了滿多的資料,我就用一個範例來說明其運作模式。這範例比較難懂一點,分別有2個按鈕,按鈕會觸發$dispatch('notify','按鈕A')跟btncount()。$dispatch會去調度notify的監聽器,並且把文字【按鈕A/按鈕B】傳入notify去控制,而notify用$event.detail去接收值並賦予到btn裡面。我們就可以看到畫面上會出現按鈕A/B被點擊的文字。
圖28. $dispatch魔法屬性
圖29. 初始畫面
圖30. 按鈕A被點擊
圖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順序。
圖32. $nextTick魔法屬性
圖33. 起始畫面
圖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把資料塞進去。
圖35. $root魔法屬性
圖36.按下按鈕console.log的結果
$data:是可以隨意調動目前x-data範圍內的所有x-data資料,我們用上面的範例改寫一下,AlpineXdata3()上面包了AlpineXdata2()跟AlpineXdata(),因此我們在AlpineXdata3()的這一層DOM去觸發按鈕抓資料,可以抓到AlpineXdata3()本身的say跟往上抓到AlpineXdata2()裡面的name還有最上一層AlpineXdata()的follow。
圖37. $data魔法屬性
圖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中,其好處就是可以重複使用。
圖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清除。
圖40. init()及destroy()
圖41. Console.log
Alpine.bind():這語法也很好用,就是當一個HTML屬性過多又或者會重複使用時可以用x-bind去封裝起來,從下面官方範例來看一個按鈕有3個屬性<button type="button" @click="doSomething()" :disabled="shouldDisable"></button>,type、click、disabled,全部都用x-bind="SomeButton"去包裝起來,看起來就乾淨多了。
圖42. Alpine.bind()語法
Alpine.store():這是一個全域的狀態管理器,他可以跨不同alpine的組件共享狀態機制,共同取得資料跟修改資料。只要用$store的語法去控制就好,以下是非常簡單的範例,Alpine.store()定義count, click用$store.count++去把全域的count加一,x-text用$store.count取得資料狀態。
圖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