# 初探 Vue.js

# 基本原理

Vue.js 是處理 View Layer 的 Library ,使用 Vue.js 時,我們會操作 View Model (也就是 Vue.js 的實體)使其依照從商業邏輯取得的資料做改變,配合在 HTML 中 Vue.js 提供的模板語法來改變配置,重新渲染後使畫面產生變化。

下圖是一個 Vue.js 簡單的架構圖:

vue mvvm like

  • View : 透過 HTML 及模板語法渲染出來的畫面。
  • View Model : 使用 Vue.js 所建立起來的實體。
  • Model : 後端程式中的商業邏輯。

圖中的綠色文字代表範例情境:

  1. 使用者按下按鈕。
  2. 透過 HTML 中模板語法的綁定觸發 Vue 實體中註冊的事件。
  3. 事件中叫用 AJAX 向伺服器請求資料。
  4. 伺服器取得資料後傳回給 Vue 實體。
  5. Vue 實體修改綁定的 View Model 。
  6. View Model 改變後觸發模板重新渲染。
  7. 使用者看到改變後的畫面。

上述的情境是在高層次的面上做說明,實際上 Vue.js 的運作原理還要比這個深奧許多,後面有機會再來分享,現在這階段,用這樣的架構去說明就可以有比較具體的概念了。

如果以語言來分的話, View 就是 HTML , View Model 是 JS ,而 Model 就是像 Node 、 Java 這類的後端語言。

# 第一支 Vue.js

這一節會用上節的情境來開發一個簡單的 Vue.js 應用,讓我們對 Vue.js 的流程有個初步的了解。

首先要建立一個 Vue 實體,再來在 HTML 中編寫模板語法,之後將 HTML 上欲做變化的元素登錄在 Vue 實體中,接著綁定 Click 事件至後端取得資料,最後修改 Vue 實體中的資料藉以讓畫面產生變化。

# 引入 Vue.js 庫

引入 Vue 的方式有很多種,在一般的專案中通常都是使用 Webpack 來引入,但本系列文為了 Demo 方便,使用 <script> 元素來引入。





 






<!DOCTYPE html>
<html>
<head>
    ...
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    ...
</body>
</html>

這樣就引入了 Vue.js 庫了。

Vue.js 有分不同的版本: FullRuntime-only , Runtime-only 版本比 Full 少了 Compiler ,這是將模板編譯成 Render Function 的編譯器,因此如果只使用 Render Function 來渲染頁面的話可以只載入 Runtime-only 就好,在後面的章節會介紹 Render Function,那時候會做比較詳細的說明,而版本差別的詳細說明可以參考官網的介紹 (opens new window)

# 建立 Vue 實體

接下來要建立 Vue 實體,就是上圖中間圓圈的部分, Vue 實體是整個 Vue.js 應用必備的物件,要建立 Vue 實體很簡單,如下程式碼:










 







<!DOCTYPE html>
<html>
<head>
    ...
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    ...
    <script>
        var vm = new Vue({
            ...
        });
        ...
    </script>
</body>
</html>

<script> 中的 new Vue({...}) 會建立 Vue 的實體,而 vm 變數取得的就是 Vue 實例化的物件。

通常 Vue 實例化物件會以 vm 當作其變數名稱,這也呼應了上面介紹: Vue 實例化物件在架構上代表著 View Model 層。

Vue 的第一個參數是 Options (opens new window),它用來登錄 Vue 實體所需的對象。

以這個例子來說有三個部分需要設定:

  • 註冊一個 Vue 實例的掛載目標。
  • 需要一個輸出取得結果的資料。
  • 一個向後端取得資料的 Click 事件。

所以 Options 物件會像下面這樣:

var vm = new Vue({
    el: '#app',
    data: {
        message: "This is local data.",
    },
    methods: {
        getRemoteMessage() {
            Promise.resolve("Get remote data.")
                .then((res) => {
                    this.message = res;
                });
        },
    },
});
  • el : 將這個 Vue 實體掛載到這裡設置的元素上。
  • data : 登錄資料,當這些資料改變時,畫面會依照變化做改變。
  • methods : 登錄方法,這些方法可以藉由 DOM 事件觸發,也可以在 Vue 實例中被叫用。

上面的程式碼做了下面三件事:

  • 將頁面上 ID 為 app 的元素當作這個 Vue 實例的掛載目標。
  • 初始一個 message 的畫面響應資料。
  • 定義一個 getRemoteMessage 方法,該方法會以非同步的方式取得資料,然後將取得的資料設置於 message 上。

這裡直接使用 Promise.resolve 當作範例,實際上這裡可以用 AJAX 取得資料。

這樣就把 Vue 實例建立起來了。

# 編寫模板

最後要使用 Vue 提供的模板語法來綁定 Vue 實例中的物件,我們需要下面這些部分:

  • 一個 ID 為 app<div>
  • 一個顯示訊息的 <p>
  • 一顆取回非同步資料的 <button>

配置會像下面這樣:








 







<!DOCTYPE html>
<html>
<head>
    ...
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <div id="app">
        <p>{{message}}</p>
        <button v-on:click="getRemoteMessage">Click</button>
    </div>
    ...
</body>
</html>

這裡有兩個 Vue 的模板語法:

  • {{message}} : 綁定 Vue 實例中的 message 資料。
  • v-on:click : 綁定 Vue 實例中的 getRemoteMessage 方法至 Click 事件中。

如此一來我們就完成了所有的配置,當你按下按鈕後就會看到 This is local data. 變為 Get remote data. 了。

# 再進一步

上面完成了我們第一個 Vue 的應用程式,但如果現在的情境是 舊系統裡面要使用 Vue.js 來擴充功能 呢? 例如說取得資料的按鈕並不存在於 Vue 實體中,那要怎麼辦呢?

我們假設以下是我們目前的頁面配置:

<div id="app">
    <p>{{message}}</p>
    ...
</div>
<button ...>Outside Button</button>

因為按鈕在 Vue 實例(div#app)的範圍外,並不在 Vue 模板中,所以並不能使用像是 v-on:click 這樣的模板語法綁定事件。

這裡可以使用 vm 變數, vm 變數就是 Vue 實例的物件,因此修改 vm 中的 message 也可以達到同樣的效果:


















 




<div id="app">
    <p>{{message}}</p>
    ...
</div>
<button onclick="clickButton()">Outside Button</button>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            message: "This is local data.",
        },
        ...
    });

    function clickButton() {
        Promise.resolve("Get remote data by outside button.")
            .then((res) => {
                vm.message = res;
            });
    }
</script>

這樣就算系統中其他部分不是使用 Vue.js ,也可以很輕鬆的整合。

# 完整程式碼

以下是完整的程式碼,包含了 Vue 實例內及實例外的按鈕範例。

<!DOCTYPE html>
<html>
<head>
    <title>Hello Vue.js</title>
    <script src="https://unpkg.com/vue"></script>
</head>
<body>
    <!-- 7. Output View after rerender -->
    <div id="app">
        <p>{{message}}</p>  <!-- 6. Rerender View -->
        <button v-on:click="getRemoteMessage">Inside Button</button>   <!-- 1. Click Button -->
    </div>
    <button onclick="clickButton()">Outside Button</button>   <!-- 1. Click Button -->
    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                message: "This is local data.",
            },
            methods: {
                getRemoteMessage() {    // 2. trigger event in Vue instance
                    Promise.resolve("Get remote data by inside button.") // 3. Get data asynchronously
                        .then((res) => {    // 4. Return result
                            this.message = res; // 5. Change View Model
                        });
                },
            },
        });

        function clickButton() {    // 2. trigger event in Vue instance
            Promise.resolve("Get remote data by outside button.") // 3. Get data asynchronously
                .then((res) => {    // 4. Return result
                    vm.message = res; // 5. Change View Model
                });
        }
    </script>
</body>
</html>

註解可以搭配文章一開始圖片上的數字做比較具體的理解。

# Demo

# 程式碼

# 小結

Vue.js 只要單純的設置就能改變頁面的配置,在範例中我們並沒有修改 DOM 元素,而是專注在對 View Model 做改變,由於不用直接接觸頁面的配置,因此變換邏輯跟頁面沒有直接的關係,所以就算修改了頁面的配置,只要模板語法的設定正確,不需要修改邏輯就可以完成修改,這樣的特性使頁面可以更容易的被抽換。

例如我們今天想要修改 message<p><div> ,如果是 JQuery 的寫法,除了 HTML 的配置要做修改外,還必須要修改 JavaScript 的程式碼,可是在 Vue.js 中我們只要把 <p> 改為 <div> 就好,只要 View Model 依然是 message ,我們就不需要修改任何的 JavaScript 碼。

而對於舊系統的相容也可以用 vm 變數做到對 Vue 實例的修改,在整合原有專案上有很大的優勢。

# 參考資料