seansie's blog

#0 為甚麼要用vuejs框架? -30天學會vue系列文 | seansie blog

大概如果初入網頁設計領域的人都聽說過html、css跟javascript,分別對應 內容 **樣式 跟互動。**如此看來,網站的基本元素應該湊齊了阿,幹嘛還要加上框架,增加複雜度呢?。

那好,且聽我娓娓道來。

重複元素

舉google搜尋下面的按鈕為例,你看已經分別重複8次跟10次了,如果僅使用 javascript 的話,難道要重複8次跟10次嗎?

雖然是可以用迴圈+ Inner html 啦,但是非常難以維護,尤其是一旦專案複雜度很高的時候。

// Create a container element (you can replace this with your existing container)
const container = document.createElement('div');
document.body.appendChild(container); 

// Create and append 8 buttons with innerHTML
for (let i = 1; i <= 8; i++) {
  const button = document.createElement('button');
  button.innerHTML = `Button ${i}`; 
  container.appendChild(button);
}

如下圖所示,這還只是產生8個按鈕的時候喔,別忘了還有樣式,而且你看上圖旁邊還有一個放大鏡icon要插入,這樣搞下來恐怕是一場災難,可能還要穿梭在 html 標籤之中,大概是不會來去自如而是寫出義大利麵程式碼,就是互相呼叫,毫無邏輯,基本上無法維護,想要修改就只能重寫的程式碼。筆者已經無法想像這種慘況了。

此外, inner html 還有 XSS 的風險,例如你打算插入一個 <p>使用者輸入內容 </p> 的標籤進入,可是有心的使用者輸入了 <script> alert("you are hacked")</script> ,這樣使用者瀏覽器就會彈出 you are hacked的對話框,這只是示範,既然能讓使用者彈出對話框,當然也可以 **執行任何程式碼 (ACE),**這可是非常危險的,但是如果是手工進行安全防護,費時費力,不如讓框架代勞。

最後,有時候在渲染樹狀結構(例如資料夾)的時候,剛剛的範例還需要加上遞迴,

function renderFolderTree(folder, parentElement) {
  const li = document.createElement("li");
  li.textContent = folder.name;
  li.classList.add(folder.type); // Add class for styling

  if (folder.type === "folder") {
    li.addEventListener("click", (event) => {
      event.stopPropagation(); // Prevent event bubbling to parent folders
      li.classList.toggle("active"); // Toggle visibility of children
    });

    const ul = document.createElement("ul");
    if (folder.items) {
      folder.items.forEach((item) => {
        renderFolderTree(item, ul); // Recursive call for nested items
      });
    }
    li.appendChild(ul);
  }

  parentElement.appendChild(li);
}

const folderTreeContainer = document.getElementById("folderTree");
renderFolderTree(folderData, folderTreeContainer);

真的蠻難懂的吧

而這時元件可以自我引用的優勢就出現了,元件有點像是專為html設計的函數,只要把元件自我引用,然後加上終止條件,就可以輕鬆實現這種效果了,反觀上面的 純 js實現還要處理比較底層的 DOM(html標籤)細節。

<template>
  <ul>
    <li v-for="item in items" :key="item.name" :class="item.type">
      <span @click="toggle(item)">
        {{ item.name }}
      </span>
      <folder-tree v-if="item.type === 'folder' && item.isOpen" :items="item.items" /> 
      <! 終止條件>
    </li>
  </ul>
</template>

狀態管理

網站是事件導向的程式,有事件才會有動作。而人看不到狀態,需要被渲染到螢幕上人才能看到,如果不用框架大概長這樣

<!DOCTYPE html>
<html>
<head>
  <title>Button Click Counter</title>
</head>
<body>
  <button id="myButton">Click Me</button>
  <p>Clicked <span id="countDisplay">0</span> times</p>

  <script>
    let count = 0; // 狀態儲存在全域變數
    const button = document.getElementById('myButton');
    const countDisplay = document.getElementById('countDisplay');
    // 這邊其實都可以讓框架代勞
    button.addEventListener('click', () => {
      count++;
      countDisplay.textContent = count; // 手動更新 DOM
    });
    // 這邊其實都可以讓框架代勞

  </script>
</body>
</html>

如果是簡單的網站,手動使用 DOM API來操作可能還算是一個權宜之計,但是這個前提是你要知道何時何地如何更新阿,如果專案一大基本上常人沒辦法掌握,根本搞不清楚到底甚麼時候要更新,如此一來恐怕是BUG連環爆。

不過雖然也有一些 getter 代理物件 手動事件 訂閱模式等等比較進階的技巧可以實現等效框架功能,但是軟體界有一句話 不要重新發明輪子,既然已經有經過時間考驗的解決方案,而且又是MIT可商用授權的,幹嘛不要直接用。

而在 vuejs 的作法是如下

<template>
  <div>
    <button @click="handleClick">Click Me</button>
    <p>Clicked {{ count }} times</p> {/* Vue 會自動更新 DOM */}
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0, // 使用 data 屬性管理狀態
    };
  },
  methods: {
    handleClick() {
      this.count++; // 通過 this.count 更新狀態
    },
  },
};
</script>

有看到 <template> 標籤之下有個 {{count}} 語法嗎,那個就是表示 data() 中裡面的 count 變數的站位字元,而這裡厲害之處就是他是基於虛擬DOM來渲染的,效能比普通的DOM操作更高,此外, {{count}} 這個地方只要 count 變數有更改,他就會在畫面用新的資料同步渲染。

例如如果原本 count=1 那前端畫面就會顯示 Click 1 times,而如果 count變數突然變成2了,前端畫面也會跟著變成 click 2 times。

這個非常方便的功能就像一個秘書一樣,幫忙處理 **把資料渲染到前端畫面上 ,**這種看似無聊但是很重要、需要細心注意何時何地怎麼渲染的瑣事。

身為開發者,如果使用框架就能像老闆一樣,應該是只要專心在業務邏輯上就好,把資料送到變數上面,就會自動地被渲染出來,如一來可以大大提升開發效率。而不是專心在跟自己沒關係的東西上面,例如訂機票之類的。

為甚麼推薦vue

因為 vue 是漸進式框架,漸進式,顧名思義,僅取所需,也代表他的學習曲線低。

而且就算你可能 javascipt 語法不熟甚至根本不會, 都還蠻有機會學會 vue 的。

此外它的設計真的是新手友善的,建立一個元件有點像是填表格,把 <template> <style><script> 依樣畫葫蘆,分別對應內容、樣式跟互動,而元件的邏輯(也就是如何定義互動方式,在這裡通常會叫他邏輯),也是遵循這種風格的

<script> // 有複數個用逗點隔開
export default{
	data(){
		return {
			你的變數 : "helloVue"
			}
		}
	},
	methods:{
		你的函數(){
			函數內容
		}
	}
</script>

元件邏輯在 export default的 {} 中定義,有點像是元件的入口。

裡免有許多清楚的元件邏輯函數,列舉如下(用法如上)

  • data() 定義 資料(名詞) 可以在 <template> 透過雙大括號語法讓他同步渲染
  • method() 定義方法(函數) 就像是動詞
  • create()定義建立時的初始化操作 (有點像是前處理)

等等

反觀react光是要宣告元件資料,就用了一個 useState 這種需要許多 js 知識的機制,這個恐怕會勸退許多初學者

此外 angular 是強制使用 typescript 的,也就是開發者需要明確知道 js 物件的資料型態,並且把它標住在旁邊,提供編譯器檢查,好處是錯誤很少啦,但是壞處也是顯而易見,就是學習曲線高,畢竟新手可能連 js 都有點搞不定了,遑論 typesctipt

總結

隨著前端日益複雜,簡單的 javascript 已經無法滿足開發者對於效率的追求了,因此才會出現這麼多框架來解決問題,而 vuejs 我覺得是個對新手友善的框架,得益於他漸進式的特性而學習曲線平坦,非常推薦大家學習。

<script>
	Vue.createApp({
		data(){
			return{
				msg: "Vuejs"
			}
		},
	}).mount(".app")
</script>