iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
JavaScript

歡迎參加我的原生JS畢業典禮系列 第 18

【Day17】Vue組合式函數&自定義指令

  • 分享至 

  • xImage
  •  

前面幾天我們重新回顧了Vue的語法結構,還有各種內建提供的指令用法。今天的重點放在 「如何把自己寫的內容」 定義成可以複用的函式,以及 「如何自訂指令」 ?讓我們把Vue更活用,Let's go!

組合式函式

組合式函式讓我們能夠複用特定代碼,聽起來跟模組好像有點像?

  • 模組:重點在於主要的建構模塊,包含htmlscriptstyle
  • 組合式函式:重點在於有狀態的邏輯,可以想成在模組間會重複使用的邏輯,獨立為組合式函式共用。

行前注意事項

  1. 透過Composition API來封裝和複用
  2. 必須在<script setup>setup()之下使用
  3. 命名規則以小寫use開頭駝峰式命名
  4. 在不同組件中呼叫組合式函式都會是一個獨立作業環境,數據不會互相影響
  5. 接收參數是否為響應式狀態:接收一般字串只會執行一次,狀態改變時更新需傳入響應式參數
  6. 回傳值以ref()取代reactive(),才不會在解構過程連同內部的響應式資料一起解構

範例說明: 我們依照官方示範製作一個滑鼠追蹤函式,再套用自訂圖樣改變滑鼠呈現

  • 建立useMouse.js作為組合式函式
  • 取得追蹤鼠標位置
  • 套用在圖檔上,並隱藏系統滑鼠樣式
//useMouse.js
import { ref, onMounted, onUnmounted } from 'vue'

export function useMouse() {
    //注意回傳值使用ref而非reactive
    const x = ref(0)
    const y = ref(0)
    
    //用來更新滑鼠位置
    function nowPosition(event) {
        x.value = event.pageX
        y.value = event.pageY
    }
    //註冊監聽滑鼠移動事件
    onMounted(() => window.addEventListener('mousemove', nowPosition))
    //註銷監聽滑鼠移動事件
    onUnmounted(() => window.removeEventListener('mousemove', nowPosition))
    
    return { x, y }
}

進入App.vue引入useMouse組合式函式,接下來就是設定我們想要的游標圖片(自己畫也可以啦):

  import { useMouse } from '@/assets/useJS/useMouse.js'
  //可以取得x,y座標了
  const { x, y } = useMouse()

只要把x,y座標套用到runStyle上面就沒問題了!

//利用computed處理動態座標
 const runStyle = computed(() => {
     return {
         'width': '28px',
         'position': 'absolute',
         'left': x.value + 2 + 'px',
         'top': y.value + 2 + 'px'
     }
 })
 <img :style="runStyle" src="/cursor.png">

https://ithelp.ithome.com.tw/upload/images/20241002/20169356NCRITia2wT.png

自定義指令

學到這裡我們對Vue的內建指令(v-onv-model...)已經不陌生了,那麼透過 自定義指令 我們可以做到什麼事情呢?它主要是讓我們能複用 「對普通元素DOM的訪問邏輯」 ,直接上範例來瞧瞧它是怎麼運作的!

  • <script setup>建構模式下使用:
  1. 命名由v小寫開頭的駝峰式命名法
  2. 會使用類生命週期的鉤子函式( 注意: 沒有加on
 const vFocus = {
     //透過參數el達成.focus()效果,指定元素處於焦點狀態
     mounted:(el) => el.focus()
 }
 <input v-focus type="text" placeholder="請輸入文字"/>

https://ithelp.ithome.com.tw/upload/images/20241002/20169356IOizxxix2d.png

  • 非建構模式下使用:透過directives註冊自訂指令
export default {
    setup() {
    },
    directives: {
        //這裡命名不需要加上v
        focus: {
            mounted: (el) => el.focus()
        }
    }
}
//引用時一樣以v-xxx呼叫
<input v-focus type="text" placeholder="請輸入文字"/>
  • 全域註冊:
app.directive('focus', (el, binding) => {
    //這會在mounted和updated時都調用
    el.focus()
})

鉤子函式

上面提到了內部可以定義掛載在不同的生命週期鉤子上,大致上分為這些:

  • created(el, binding, vnode, prevVnode):在事件監聽器應用前調用
  • beforeMount(el, binding, vnode, prevVnode):在元素綁定DOM前調用
  • mounted(el, binding, vnode, prevVnode):元素與父組件綁定和其子節點掛載完調用
  • beforeUpdate(el, binding, vnode, prevVnode):綁定元素的父組件更新前調用
  • updated(el, binding, vnode, prevVnode):綁定元素與父組件和其子節點更新完調用
  • beforeUnmount(el, binding, vnode, prevVnode):綁定元素的父組件卸載前調用
  • unmounted(el, binding, vnode, prevVnode):綁定元素的父組件卸載後調用

鉤子參數

鉤子函式內部提供相關參數讓我們可以針對元素進行狀態設定:

  • el:可以針對指令綁定元素直接操作DOM
  • binding:一個對象,包含以下屬性:
    1. value:傳遞給指令的值
    2. oldValue:之前的值,僅在beforeUpdateupdated中可用,如:v-test="2",值為2
    3. arg:傳遞給指令的參數,如:v-test:hello,參數為hello
    4. modifiers:一個包含修飾符的對象,如:v-test.hello,修飾符對象是 { hello: true }
    5. instance:使用該指令的組件實例
    6. dir:指令的定義對象
  • vnode:代表綁定元素的底層VNode
  • prevVnode:代表之前的渲染中指令所綁定元素的VNode,僅在beforeUpdateupdated鉤子中可用

官方針對上述參數的提示:

Note
除了 el 外,其他參數都是只讀的,不要修改它們。
如你需要在不同的鉤子間共享信息,建議通過元素的 dataset 屬性實現。

小結

雖然自定義指令看似方便,但如果vue內建指令已經很夠用的情況下還是先以內建指令的使用為優先,後續才不會造成過多的渲染負擔喔!


參考資料
Vue-組合式函數
Vue-自定義指令


上一篇
【Day16】Vue超簡單實現元素拖曳效果—應用To Do List
下一篇
【Day18】Vue的分組報告—實作購物車(上)
系列文
歡迎參加我的原生JS畢業典禮31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言