2017年1月2日 星期一

asp.net Web開發框架 (4) - 使用Vue.js進行前端資料繫結顯示(Template Rendering)

弱水三千,為何只取Vue.js?

一直以來,我覺得大部分的開發技術其實也是一種工具,也有生命週期。既然是一種工具,那開發技術當然不能只是拿來學習,而應該是拿來使用的。最近幾年,隨著開發技術的生命週期越來越短,不免讓人開始猶豫該如何選擇。如果你慢慢發現,學習某一門技術的時間並沒有遠低於使用它的時間,那就得回頭重新評估這個工具了…

但,千萬別誤會,我不是叫大家不要花時間去進修,或是減少學習的時間。這年頭,我們比過去以前任何一個時代都需要時時刻刻學習。但,正因為我們的時間越來越珍貴,越來越難以過去的大量快速學習來面對技術的變遷,因為現在不管學得再快,也無法趕上變化的腳步…

莫名其妙講了一堆,好像跟這個主題無關?

非也,我想說的是,最近幾年我在專案中選擇的工具(開發技術)時,都盡可能以不用花太多學習時間的為主。因為工具(技術或框架)最終的目的是幫你節省時間用的,倘若學習成本太高,可能會本末倒置。而這個理由,也恰巧是我們選擇Vue.js作為前端開發框架的原因。

當過去幾年我們在.net環境嘗試建構一個適當的開發架構時,三層式的SPA對我們來說是個能同時滿足行動裝置、Web、以及桌面應用的理想選擇,而要採用何者搭配SPA作為Web前端開發套件呢? 最終,我們選擇了Vue.js。

理由?

  1. 它的程式碼很簡潔,非常輕量級,執行速度也算快,一點都不讓人覺得累贅。
  2. 它很好學,還有中文的文件(唯一的遺憾是簡體),對於已經有前後端程式碼分離、SPA基本概念的人,用起來跟喝水差不多。
  3. 它在資料繫結這個部份的做法非常直覺,MVVM概念的實現很接近以前XAML的作法,同時,它採用的標記語法很簡單,也極不容易破壞HTML版面,和設計師(designer)很好合作。

以上是最主要的這幾點。

Demo的前置準備

我們前面說過Vue.js學起來很簡單,因此我們也不用談什麼初階進階的東西。待會的Demo就直接從伺服器端把一組資料傳到前端,然後透過Vue.js做一個Binding(Template Rendering),以表格的方式把從伺服器端傳來的JSON資料呈現出來。
(若需要完整的CRUD請參考本文最後)

如果你想跟我一起 hands-on 一下,請依照底下的操作步驟做好前置準備,別忘了,我們用的是SPA架構,把以前你熟悉的asp.net WebForms或asp.net MVC都先給擱在一邊吧。

補充: 底下的範例是透過WebForms PageMethod來寫SPA,如果你想看WebAPI的SPA版本,請參考Source code,UI的部分請看index.html,同時原本PageMethod相對應的改成了透過WebAPI呼叫BO,請參考ControllerHealth.cs,而程式碼的說明則建議您先看完這篇之後,再接著看下一篇(WebAPI版)。

  1. 請先建立一個最基本的asp.net 應用程式(請用Empty範本,並勾選WebAPI與WebForms),然後只需直接引入一個Nuget套件isRock.Framework.Web.AllPackages,它會幫你引入其他所有需要的Nuget套件:
  2. 接著,請在頁面上建立一個default.aspx (如果你偏好WebAPI版本的SPA,可參考這邊自行傳換成建立WebApi,或待會看下一篇):
  3. 準備工作先到這邊,接著我們來看如何進行Vue資料繫結。
基本概念

開工前我們扼要說一下基本概念,我們接下來要透過Vue.js做一個最基本的資料繫結,整個動作發生於前端,也就是瀏覽器上(這和Silverlight類似),但和過去asp.net WebForms發生在後端的資料繫結有所不同。

所以你必須先知道一件事情,這裡所謂的資料繫結,指的是瀏覽器內的HTML與Object的繫結。也就是,將『從伺服器端透過AJAX呼叫,被以JSON格式傳遞到瀏覽器之後的JavaScript Object』,與『HTML UI』Template之間的資料繫結。

而非像是過去的asp.net webforms或MVC一樣,在伺服器端進行的資料庫與UI Rendering之間的繫結。

大部分的SPA架構,前端顯示的資料都是從伺服器端以JSON的方式傳到前端,所以我們這裡的資料繫結大多談的都是資料被以JSON格式傳到前端瀏覽器上『之後』的資料繫結。

因此,你必須有幾個概念:

  1. UI上的資料不會『直接』與後端資料庫互動,而是在前端瀏覽器的記憶體內與HTML UI互動。
  2. 資料在繫結前,得先從伺服器端(以JSON格式)傳過來。
  3. 倘若是表單繫結,UI上的資料被用戶修改而有所異動,也只是反應回前端瀏覽器內(記憶體中)的Object,並非直接回寫資料庫。

暫時先知道這些就可以了。

要Demo什麼?

我們先來看,如何從伺服器端取得JSON資料,然後透過Vue.js的template動態Render到HTML上的範例(後面會再介紹表單中的資料雙向繫結)。好的,我們待會要做的事情是這樣,畫面上有一個類似底下這樣的UI:

當按下左上角Get Data按鈕的時候,會從伺服器端撈一堆資料,以JSON的格式傳到前端瀏覽器上,透過Vue.js進行DataBinding,呈現出底下的結果:

如果用戶按下上圖中的清空鈕,則表格資料會清空,就這樣。

如何使用Vue.js的template syntax做HTML動態rendering

好,知道要做什麼之後,我們實際來嘗試一下,請在剛才建立好的aspx頁面的CodeBehind程式碼中,建立底下這個Method :

上面這段後端C#程式碼的主要目的,是建立可以往前端傳送資料、可以被前端JavaScript呼叫的PageMethod,角色如同WebAPI或WebServices一般,但.aspx開發人員很幸運,用上面這樣的寫法就行了。

細看程式碼其實很簡單,28-33行就是準備假資料,如果是正式環境,我會從資料庫抓資料,但因為這只是一個範例,我們不要弄得太複雜。注意我們可以直接在同一個頁面上定義ViewData Class,當然也可以獨立做成一個專案或寫在同一個專案的BO(Business Logic Object)資料夾底下,但對於WebForms開發人員我們很包容,暫時先寫在同一個頁面上就好。

35行的迴圈是計算BMI值,最後在46行回傳給前端JavaScript,就這樣。別問我為何那麼簡單,因為 1.它本來就很簡單 2.上面範例用了我們開發的框架,大部分前端AJAX程式碼以及後端資料回傳的類別都包裝過了。

寫好後端C#,待會接著我們來看前端。

後端的PageMethod負責提供資料,留意上面程式碼25行該PageMethod的宣告以及回傳型別,是public static PageMethodDefaultResult<List<StudentInfo>> GetData() {…},由於框架提供的功能,你可以在前端透過底下這樣的JavaScript直接呼叫後端的GetData()這個PageMethod,作法像是底下這樣:
          CallPageMethod('GetData', null,
              //when success
              function (result) {
                 vm_StudentInfo.items = result.Data;;
              }
           );
透過呼叫CallPageMethod這個function,即可執行伺服器端這個名為GetData的PageMethod(由於該Method不需要任何參數,因此上面第二個參數我們給null),並且在成功呼叫之後,透過callback function取得回傳值result,這個result就是剛才PageMethod的回傳物件PageMethodDefaultResult<List<StudentInfo>>,而result.Data則是PageMethod回傳物件中的List<StudentInfo>,也就是實際上我們在前端需要的ViewModel資料,也就是五筆學生的身高體重與BMI值。

那…這個…

vm_StudentInfo.items = result.Data;

這行程式碼什麼意思呢?別急,我們來看前端頁面上完整的程式碼:

請注意UI的部分只有50行之後,UI進行Template Rendering的部分只有64-94行中間的表格部分,而8-11行則是引用我們會用到的js與css。整段程式碼看過之後,我們來看關鍵的幾個部分。

  1. 首先,該頁面一被載入完畢,41行的Document Ready會先被執行,請留意43行的SetBinding設定。後面45,46只是Hook Button的Click事件而已。
  2. 43行呼叫的SetBinding做了什麼呢? 我們看16-23行。整段內容非常簡單,就是透過Vue做一個資料繫結,繫結什麼? 誰跟誰繫結? 就是頁面上的HTML Template與瀏覽器記憶體中的物件vd_StudentInfo。其中20行的el與21行的data,告訴Vue.js的Rendering/Binding engine,當指向vd_StudentInfo這個記憶體物件的items有所異動時,要自動更新(Rendering)頁面上TableBody這一塊的內容。

     
  3. 我們看TableBody,也就是第64行到94行這一塊div :
     
  4. 由於上面的TableBody區塊,是透過{{…}}這樣的語法所設置了的HTML樣板(Template),因此,每當vm_StudentInfo中,指向vd_StudentInfo的這個data(也就是items)有所異動時,el區塊(也就是TableBody)就會被更新。你可能會疑惑兩件事情,(1) items什麼時候會被異動? 以及 (2) el區塊會被怎麼更新?
  5. 首先,請看45行的Button,他被按下時會觸發26行的GetData,透過CallPageMethod呼叫是伺服器端的GetData方法回傳學生資料JSON到前端,透過result.Data傳回,然後我們丟給binding_StudentInfo.items,對,就是這個動作,更新了items,這解答了上面的(1)這個問題。
  6. el區塊會被怎麼更新呢? 因為我們透過了Vue.js設定的Template語法(也就是那些{{…}}),因此,Vue.js Render Engine發現了items有所異動,就會去拿vd_StudentInfo中的值,更新指定的el區塊(tableBody),也就是64-94行的HTML樣板(Template)。
  7. 更新時,會把vd_StudentInfo帶入items,然後請特別注意76行的<tr v-for="item in items">,這一段Vue的v-for語法,意思是接下來的tr區塊(76-92行),會被重複顯示(Render),重複的次數看items這個array的個數決定…別忘了,items就是vd_StudentInfo,而vd_StudentInfo是從伺服器端傳來的List<StudentInfo>…
  8. 由於伺服器端傳來的資料有五筆,因此這個v-for跑了五次,每一次帶入一個StudentInfo item(留意78,81,84…這幾行的繫結語法{{item.屬性名稱}}),資料被帶入表格,呈現出底下的結果:

沒了,就這樣。

這個Template Rendering與過去XAML當中的Binding Engine作法幾乎完全相同。也就是,透過設定Template語法,上面js程式碼中的new Vue(…),把UI Element與記憶體中的Data Object做一個關聯(繫結),一旦繫結綁定了之後,一端有任何變化,另一端也會跟著變化(在表單中使用的話,可透過v-model設為雙向繫結,容後介紹),而搭配上{{…}}這樣的Template顯示語法,在HTML中可以輕易的帶入要呈現的集合資料或變數。

不僅僅語法非常簡潔,HTML Tag的破壞也極少,這是我喜歡Vue.js的原因,他讓SPA可以輕易實現前端的Template Rendering或Data Binding,並且讓設計師(Designer)與程式設計師(Developer)可以開心的合作。

所以…

目前Vue.js幾乎是我們現在開發SPA時,在前端的首選甚至是唯一選擇。上面這整段程式碼是非常常見的應用,只要稍微熟悉Template Rendering或Data Binding概念,可以很快的pick up整個Vue.js的語法與使用,建議沒有使用過的開發人員可以試試看…

後面,我會抽空繼續介紹更進一步的Binding方式,例如在表格中加上Button按鈕之類的…

source code : https://github.com/isdaviddong/AspNetWebFormsSpaVueBinding

Again: 上面是透過PageMethod來寫,如果你想看WebAPI的版本,請參考上面的程式碼,UI的部分請看index.html,PageMethod則改成了透過WebAPI呼叫BO,請參考ControllerHealth.cs ,並接著看下一篇

更完整的WebAPI版本CRUD Source Code:
  https://github.com/isdaviddong/AspNetWithVueBinding
--------------------------------------------
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

2 則留言:

王鵬僑 提到...

謝謝 大大的分享

讓我受益良多

isDavid 提到...

@王鵬僑,

hope helps. :)