[重構倒數第30天] — 使用 Vue3 Composition API 重構 JS 選單
Tags: Vuejs, Vue3, Vue, Front End Development

[重構倒數第30天] — 使用 Vue3 Composition API 重構 JS 選單 Mike Follow Sep 1 · 8 min read

前言

該系列是為了讓看過Vue官方文件或學過Vue但是卻不知道怎麼下手去重構現在有的網站而去規畫的系列文章，在這邊整理了許多我自己使用Vue重構很多網站的經驗分享給讀者們。

用 Vue 跟用原生 JS 或是 JQuery 開發差在哪裡?

網路上面已經有很多在介紹這些差異的文章了，我在這邊我不會去重複太多論述，不過我要在這邊講一個在開發上面最重要的差異就是『以前我們是對DOM直接操作，而Vue我們是對資料去操作』，如果你對這句話不是很能理解，那接下來我們重構的細節，你可要看仔細了 !

接下來我們會使用 Vue3 的 Composition API 來進行 web 的重構

首先我們先來看一般我們不使用 Vue 的話會如何做

html

<div id="app">

<nav></nav>

</div>

javascript

const NavItemArr = [

{ name: "home", href: "javascript:;" },

{ name: "about", href: "javascript:;" },

{ name: "address", href: "javascript:;" },

{ name: "blog", href: "javascript:;" },

{ name: "works", href: "javascript:;" },

];

let html = "";

for (const nav of NavItemArr) {

html += `<a href="${nav.href}">${nav.name}</a>`;

}

document.querySelector("nav").innerHTML = html;

const linkAll = document.querySelectorAll("nav > a");

linkAll[0].classList.add("active");

for (const link of linkAll) {

link.addEventListener("click", (e) => {

for (const item of linkAll) {

item.classList.remove("active");

}

e.target.classList.add("active");

});

}

​

首先會有選單內容的資料，裡面包含有選單的名字以及連結 然後透過迴圈把選單的html 給組起來，然後丟到指定的DOM裡面 先針對預設第一個選單加入active class 等選單的DOM 渲染完成後，對每個選單監聽一個click事件 點擊選單後清除所有選單的active狀態，然後對點擊的選單加入active class

在這邊你會發現我一下子要處理DOM的渲染，一下子也要處理DOM的監聽事件，以及選單的切換狀態。

再來我們看一下 Vue的版本

<div id="app">

<nav>

<a

v-for="(item, idx) in NavItemArr"

:key="item.name"

:href="item.href"

:class="{ active: activeIdx === idx }"

@click="handleMenuFn(idx)"

>

{{ item.name }}

</a>

</nav>

</div> <script>

import { ref } from "Vue";

// const { ref } = Vue; 用cdn可以在全域底下取的Vue

const App = {

setup() {

const activeIdx = ref(0);



const NavItemArr = ref([

{ name: "home", href: "javascript:;" },

{ name: "about", href: "javascript:;" },

{ name: "address", href: "javascript:;" },

{ name: "blog", href: "javascript:;" },

{ name: "works", href: "javascript:;" },

]);



const handleMenuFn = (idx) => {

activeIdx.value = idx;

};



return { activeIdx, NavItemArr, handleMenuFn };

},

};



Vue.createApp(App).mount("#app");

</script>

我們在Vue的部分我們使用了 ref來定義選單的內容資料(NavItemArr)及目前選取的選單的索引(activeIdx)，還有我點擊選單的時候要執行function (handleMenuFn)，然後把我們要在 template 中所使用的資料以及function都放入return 中，讓我們可以在 template 中調用。

關於ref 請參考官方文件 https://v3.vuejs.org/api/refs-api.html#refs

然後我們可以透過 Vue 的模板語法 v-for 來讓我們的 <a> 依照我們的 NavItemArr 這個陣列裡面的資料來渲染相對應的DOM，將選單給產生出來。

我們使用v-for的時候會需要一個key的屬性，這個key是需要一個唯一值來讓Vue去對應你產生出來的DOM，以方便在你做資料更改的時候去辨識那些DOM是需要被更改，那些不要更改，進而透過最小幅度的消耗來修改畫面。 關於key 請參考官方文件 https://v3.cn.vuejs.org/api/special-attributes.html#key

然後我們在 <a> 上面綁定 @click 事件，當點擊的時候傳入 v-for 回傳的索引，透過 handleMenuFn 去改變我們的activeIdx 這個索引。

然後你會發現透過 <a> 面的 class 的判斷，我去判斷 v-for 回傳的索引是否有等於我點擊選單所傳入的值，如果有，代表 activeIdx === idx 這個判斷式是成立的，那這時候 active 就會被加入到該 <a> 身上，以達到我在點擊其他選單的時候，active 也會被正確的加入到其他 <a> 身上。

到這邊你會發現一件事，那就是從頭到尾我並沒有去針對DOM 去做任何的操作，我一直在操作的都是資料，渲染或修改DOM元素的一直都是Vue，不管是我們使用的v-for 以及 class上面的判斷，又或是去修改索引的function，這些通通都是在操作資料，這就是用Vue跟用原生JS或JQ開發網站上面最大的不同，這樣我們工程師在開發網站功能的時候就可以只專心處理資料的部分，就不用把資料的處理跟DOM的操作綁再一起，就呼應了我一開始說的『以前我們是對DOM直接操作，而Vue我們是對資料去操作』。

這個範例我有放在codepen上，有興趣的朋友可以看看

​

轉換技術的過程是辛苦的

我們在轉換主要開發的技術的時候都會有過渡期，基本上每個人在剛開始的時候都會遇到撞牆期，又或是想太多不敢往前踏出第一步，這種感覺我懂。

舉例來說，我最常被問到的問題是上完Vue課程的時候，要如何開始第一步的去用Vue在實際的案子上面去使用，其實可以不用一開始就一定要整個網站全部打掉全部用Vue開始重作，可以先從網站的小區塊一步步地慢慢練習，把原本用純JS或是jQ的地方慢慢地改成Vue，這樣子的話一開始的負擔才不會太大，慢慢建立熟悉度還有信心，日後再慢慢挑戰大規模的使用就好，當你跨過那個過渡期，代表你又更往前了一步。

還有，技術是為了解決問題而存在的，不是說學習了Vue就不需要學習JQ或是原生的JS了，我們在開發或是維護舊專案上面也是會需要看到JQ的code或是在使用Vue的時候都會需要了解許多JS的語法來進行開發，尤其是在寫Vue3的時候，像是定義 let 或是 const 的時候你總要知道差別在哪裡，在使用Array的時候總要會處理Array的幾個函式吧，所以總歸一句，都學啦XD