Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
從改寫後台 jQuery 開始的
Vue.js 宣告式渲染
by Aysh Su @ 2017/2/22
PM 跟你說要加新頁面:
寫 jQuery 時會先想到什麼?
1. 從<form> 撈輸入值回來
2. AJAX 請求
3. 串接HTML 字串,塞進<table>
HTML 先刻一刻:
<form onsubmit="return search()" action="#">
<div>
<label>編號: </label>
<input id="form-id">
</div>
<div>
<label...
JS 部份可能長這樣:
function search() {
var params = {
id: $('#form-id').val(),
name: $('#form-name').val()
}; // 或 new FormData($...
問題在哪?
畫面不能一目了然
<tbody>
<!-- 這裡到底在幹嘛!?!?!?-->
</tbody>
必須跨越HTML 和JS 才能找出對應部份
// 跋山涉水過後發現....
response.forEach(function (item) {
h...
事件處理也有一樣的問題
onclick="" 等必須佔用全域變數,原則上不考慮
某個handler 從哪掛上來的?
非得要實際跑再用開發者工具看嗎?囧rz
版型一改,選擇器重寫!!
把值從DOM 撈出來
把串接好的字串塞回去DOM
全部都是滿滿的選擇器!
業務邏輯跟細節操作混淆
隨著程式規模變大,很難看出實際的業務邏輯
寫和讀的時間全浪費在差不多但又得重寫的細節
response.forEach(function (item) {
html += '<tr>';
html += '<td>' +...
為了解決上述問題
如果可以...
讓 <input> 值同步到 JS 物件
<label>編號: </label>
- <input id="form-id">
+ <input 把值同步到="JS物件的編號">
<label>零件名: </label>
- <input id...
讓事件綁定集中在 HTML
- <form onsubmit="return search()" action="#">
+ <form 呼叫這個元件的="某個函數">
- $('form').on('submit', search);
另外還...
自動依 JS 物件產生畫面
<table>
<tbody>
+ <tr 自動依這個產生一連串元素="JS的查詢結果陣列">
+ <td>陣列元素.編號</td>
+ <td>陣列元素.零件名</td>
+ <td>陣列元素.數量</td>
+ ...
讓 HTML 的畫面一目瞭然
單看 HTML 就知道這裡在幹嘛
讓 JS 裡面只剩業務邏輯
跟凌亂的 DOM 操作說拜拜
用 Vue.js 實現
宣告式渲染
宣告式渲染的優勢:乾淨
將「畫面呈現的定義」和「業務邏輯」兩者分離
JS 內的業務邏輯專注操作資料(JS物件)
讓「資料(JS物件)」
自動依「定義(HTML樣板)」
變成「畫面(實際呈現的DOM)」
「宣告」的就是樣板的定義
相對名詞:命令式...
天啊!又要學一個框架?
想到 "Javascript Fa gue"...
「漸進式」 前端框架 Vue.js
入門門檻低,學習曲線平順
官方文件好懂不複雜
能屈能伸彈性大
不怕被"JavaScript fatigue" 打倒
圖: Vue 2.0——渐进式前端解决方案 ( www.infoq.com/cn/artic...
從 <script> 開始的 Vue.js
「漸進式」就是不用從一開始就被鎖死在
Node.js、webpack、....等完整建置環境
跟開始用jQuery 一樣簡單!
介绍- vue.js
用JSFiddle 或JSBin 等環境即時練習
...
宣告式渲染起手式: {{ }} 樣板
<div id="app">
<div>Hello {{ name }}!</div>
</div>
var app = new Vue({ // 產生一個新的 Vue 實例
el: '#app', // ...
加上 v‐model 數據綁定試試!
<div id="app">
<input type="text" v-model="name">
<div>Hello {{ name }}!</div>
</div>
var app = new Vue...
怎麼理解?MVVM 架構
圖: Overview - vue.js ( https://v1.vuejs.org/guide/overview.html )
來改寫開場那個案例
h ps://goo.gl/NwKA5b
案例中的需求:
1. 從<form> 撈輸入值回來
2. 用<form> 的輸入值執行AJAX 請求
3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
引入 Vue.js
+<script src="https://unpkg.com/vue/dist/vue.js"></script>
</body>
開發階段用有完整錯誤訊息的
https://unpkg.com/vue/dist/vue....
一樣可以先刻畫面
- <div>
+ <div id="app">
<form onsubmit="return search()" action="#">
<div>
<label>編號: </label>
- <input id="form...
在 JS 裡面用 Vue 把資料接好
- // 先把原本的 code 全部刪掉
var app = new Vue({
el: '#app', // 讓這個 Vue 實例管理 #app 這個 DOM 節點
data: { // data 裏面的...
案例中的需求:
1. 從<form> 撈輸入值回來
2. 用<form> 的輸入值執行AJAX 請求
3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
v‐on: 掛上 submit 事件處理器
<div id="app">
- <form onsubmit="return search()" action="#">
+ <form v-on:submit.prevent="search()"...
在 methods 寫入對應的處理器
var app = new Vue({
el: '#app',
data: {
form: {
id: '',
name: ''
}
},
+ // 使用 methods 定義事件處理器之類的 functi...
案例中的需求:
1. 從<form> 撈輸入值回來
2. 用<form> 的輸入值執行AJAX 請求
3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
$.ajax() 不是罪
但 $('table').html(html) 是
用 this 存取 Vue 實例 data
data: {
form: {
id: '',
name: ''
},
+ results: []
},
methods: {
search: function () {
+ var vm = thi...
v‐for 自動依陣列產生 <tr>
<input type="submit" value="查詢">
</div>
</form>
<table>
<tbody>
+ <tr v-for="item in results">
+ <td> {...
案例中的需求:
1. 從<form> 撈輸入值回來
2. 用<form> 的輸入值執行AJAX 請求
3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
基本的功能完成了!!
h ps://goo.gl/juKbew
怎麼加上其他花樣?
舉例來說...簡單的表單驗證?
需求如下:
零件名不得為空值
驗證失敗時
將查詢按鈕設置disabled 屬性
將零件名的輸入框加上class「invalid」
驗證成功時自動解除上述設定
讓 class 按照 true/false 開關
<div>
<label>零件名: </label>
- <input v-model="form.name">
+ <input
+ v-model="form.name"
+ v-bind:...
其他屬性如 disabled 也可以
<div>
- <input type="submit" value="查詢">
+ <input
+ type="submit"
+ value="查詢"
+ :disabled="!isFormVali...
依賴 data 的寫在 computed
data: {
form: {
id: '',
name: ''
},
results: []
},
+ computed: {
+ isFormValid: function () {
+ retur...
上面這串的運作邏輯是?
使用者在<input> 內打字時,
自動更新data 中的name
name 被更新時自動重新計算isFormValid
!isFormValid 為true 時
<input> 自動加上"invalid" class
...
完成的範例:
h ps://goo.gl/x67m4Z
一趟範例下來你學會了:
把jQuery 命令式編程改寫成Vue.js 宣告式渲染
初始化Vue 實例new Vue() 和存取data
從Vue 實例中取值的樣板{{ }}
數據綁定v-model
事件綁定v-on: 和它的縮寫@
用compu...
以資料驅動畫面
避免在 JS 操作 DOM
讓業務邏輯跟畫面定義乾淨切割
更多好玩的都在官方文件
h ps://cn.vuejs.org/v2/guide
下次講什麼?
Vue.js 組件(Component)系統
Upcoming SlideShare
Loading in …5
×

從改寫後台 jQuery 開始的 Vue.js 宣告式渲染

8,315 views

Published on

簡介:
還記得你上次用 AJAX 撈資料生表格時,是怎麼寫的嗎?
如果你花了 80% 的時間在 JS 裡面寫 for 迴圈串接 HTML 字串,
再把這一坨 tr 字串塞進去 tbody。
三個月發現每次回來維護這份程式時,
又要再花一堆時間把分散在 HTML 和 JS 的頁面用腦袋整合起來、把業務邏輯分離。
你已經受夠這種凌亂的程式碼了嗎?相信你一定會喜歡 Vue.js!
讓我們一起從改寫後台網頁的 jQuery 範例開始,
學習怎麼讓他變身成更容易維護的 Vue.js 網頁!

1. 傳統 jQuery 後台頁面程式碼問題分析
2. Vue.js 與 MVVM 宣告式渲染簡介
3. 將前述案例逐步改寫成 Vue.js 宣告式渲染 & Vue.js 常用語法介紹

Published in: Software
  • Hello! Get Your Professional Job-Winning Resume Here - Check our website! https://vk.cc/818RFv
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

從改寫後台 jQuery 開始的 Vue.js 宣告式渲染

  1. 1. 從改寫後台 jQuery 開始的 Vue.js 宣告式渲染 by Aysh Su @ 2017/2/22
  2. 2. PM 跟你說要加新頁面:
  3. 3. 寫 jQuery 時會先想到什麼? 1. 從<form> 撈輸入值回來 2. AJAX 請求 3. 串接HTML 字串,塞進<table>
  4. 4. HTML 先刻一刻: <form onsubmit="return search()" action="#"> <div> <label>編號: </label> <input id="form-id"> </div> <div> <label>零件名: </label> <input id="form-name"> </div> <div> <input type="submit" value="查詢"> </div> </form> <table> <tbody> </tbody> </table>
  5. 5. JS 部份可能長這樣: function search() { var params = { id: $('#form-id').val(), name: $('#form-name').val() }; // 或 new FormData($('form')[0]); $.post(url, params, function (response) { var html = ''; response.forEach(function (item) { html += '<tr>'; html += '<td>' + item.id + '</td>'; html += '<td>' + item.name + '</td>'; html += '<td>' + item.quantity + '</td>'; html += '</tr>'; }); $('tbody').html(html); }); }
  6. 6. 問題在哪?
  7. 7. 畫面不能一目了然 <tbody> <!-- 這裡到底在幹嘛!?!?!?--> </tbody> 必須跨越HTML 和JS 才能找出對應部份 // 跋山涉水過後發現.... response.forEach(function (item) { html += '<tr>'; html += '<td>' + item.id + '</td>'; html += '<td>' + item.name + '</td>'; html += '<td>' + item.quantity + '</td>'; html += '</tr>'; }); $('tbody').html(html);
  8. 8. 事件處理也有一樣的問題 onclick="" 等必須佔用全域變數,原則上不考慮 某個handler 從哪掛上來的? 非得要實際跑再用開發者工具看嗎?囧rz
  9. 9. 版型一改,選擇器重寫!! 把值從DOM 撈出來 把串接好的字串塞回去DOM 全部都是滿滿的選擇器!
  10. 10. 業務邏輯跟細節操作混淆 隨著程式規模變大,很難看出實際的業務邏輯 寫和讀的時間全浪費在差不多但又得重寫的細節 response.forEach(function (item) { html += '<tr>'; html += '<td>' + item.id + '</td>'; html += '<td>' + item.name + '</td>'; html += '<td>' + item.quantity + '</td>'; html += '</tr>'; }); $('tbody').html(html);
  11. 11. 為了解決上述問題 如果可以...
  12. 12. 讓 <input> 值同步到 JS 物件 <label>編號: </label> - <input id="form-id"> + <input 把值同步到="JS物件的編號"> <label>零件名: </label> - <input id="form-name"> + <input 把值同步到="JS物件的零件名"> - var params = { - id: $('#form-id').val(), - name: $('#form-name').val() - } - $.post(url, params, function (res) { + $.post(url, JS物件, function (res) {
  13. 13. 讓事件綁定集中在 HTML - <form onsubmit="return search()" action="#"> + <form 呼叫這個元件的="某個函數"> - $('form').on('submit', search); 另外還要能避免汙染全域變數
  14. 14. 自動依 JS 物件產生畫面 <table> <tbody> + <tr 自動依這個產生一連串元素="JS的查詢結果陣列"> + <td>陣列元素.編號</td> + <td>陣列元素.零件名</td> + <td>陣列元素.數量</td> + </tr> </tbody> </table> - // 前略 for 迴圈 - html += '</tr>'; - }); - $('tbody').html(html);
  15. 15. 讓 HTML 的畫面一目瞭然 單看 HTML 就知道這裡在幹嘛
  16. 16. 讓 JS 裡面只剩業務邏輯 跟凌亂的 DOM 操作說拜拜
  17. 17. 用 Vue.js 實現 宣告式渲染
  18. 18. 宣告式渲染的優勢:乾淨 將「畫面呈現的定義」和「業務邏輯」兩者分離 JS 內的業務邏輯專注操作資料(JS物件) 讓「資料(JS物件)」 自動依「定義(HTML樣板)」 變成「畫面(實際呈現的DOM)」 「宣告」的就是樣板的定義 相對名詞:命令式編程 程式碼中充滿冗贅又難以追溯的畫面細節操作
  19. 19. 天啊!又要學一個框架? 想到 "Javascript Fa gue"...
  20. 20. 「漸進式」 前端框架 Vue.js 入門門檻低,學習曲線平順 官方文件好懂不複雜 能屈能伸彈性大 不怕被"JavaScript fatigue" 打倒 圖: Vue 2.0——渐进式前端解决方案 ( www.infoq.com/cn/articles/vue-2-progressive-front-end-solution )
  21. 21. 從 <script> 開始的 Vue.js 「漸進式」就是不用從一開始就被鎖死在 Node.js、webpack、....等完整建置環境 跟開始用jQuery 一樣簡單! 介绍- vue.js 用JSFiddle 或JSBin 等環境即時練習 開始使用:把官方文件給的script tag 複製貼上! <script src="https://unpkg.com/vue/dist/vue.js"></script>
  22. 22. 宣告式渲染起手式: {{ }} 樣板 <div id="app"> <div>Hello {{ name }}!</div> </div> var app = new Vue({ // 產生一個新的 Vue 實例 el: '#app', // 讓這個實例管控哪個 DOM 節點 data: { // JS 中對應到畫面上的狀態物件 name: 'world' } }); // 試試看改動 name 會發生什麼事情... setTimeout(function () { app.name = 'John'; // 畫面上顯示的 name 也跟著自動被改變了!! }, 2000);
  23. 23. 加上 v‐model 數據綁定試試! <div id="app"> <input type="text" v-model="name"> <div>Hello {{ name }}!</div> </div> var app = new Vue({ el: '#app', data: { name: 'world' } }); 操作看看 <input>,發生了什麼事情?
  24. 24. 怎麼理解?MVVM 架構 圖: Overview - vue.js ( https://v1.vuejs.org/guide/overview.html )
  25. 25. 來改寫開場那個案例 h ps://goo.gl/NwKA5b
  26. 26. 案例中的需求: 1. 從<form> 撈輸入值回來 2. 用<form> 的輸入值執行AJAX 請求 3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
  27. 27. 引入 Vue.js +<script src="https://unpkg.com/vue/dist/vue.js"></script> </body> 開發階段用有完整錯誤訊息的 https://unpkg.com/vue/dist/vue.js 正式環境用縮小過的.min.js https://unpkg.com/vue/dist/vue.min.js
  28. 28. 一樣可以先刻畫面 - <div> + <div id="app"> <form onsubmit="return search()" action="#"> <div> <label>編號: </label> - <input id="form-id"> + <input v-model="form.id"> + <!-- 跟 Vue 實例中的 data + 的 form.id 做雙向同步 --> </div> <div> <label>零件名: </label> - <input id="form-name"> + <input v-model="form.name"> </div>
  29. 29. 在 JS 裡面用 Vue 把資料接好 - // 先把原本的 code 全部刪掉 var app = new Vue({ el: '#app', // 讓這個 Vue 實例管理 #app 這個 DOM 節點 data: { // data 裏面的屬性可以在 v- 或 {{ }} 等地方取用 form: { id: '', name: '' } } });
  30. 30. 案例中的需求: 1. 從<form> 撈輸入值回來 2. 用<form> 的輸入值執行AJAX 請求 3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
  31. 31. v‐on: 掛上 submit 事件處理器 <div id="app"> - <form onsubmit="return search()" action="#"> + <form v-on:submit.prevent="search()"> <div> <label>編號: </label> <input v-model="form.id"> </div> v-on: 可直接縮寫成「@」 可加上.prevent 達到event.preventDefault(); 的效果
  32. 32. 在 methods 寫入對應的處理器 var app = new Vue({ el: '#app', data: { form: { id: '', name: '' } }, + // 使用 methods 定義事件處理器之類的 function + methods: { + search: function () { + // 一樣處理 AJAX 等等 + } + } });
  33. 33. 案例中的需求: 1. 從<form> 撈輸入值回來 2. 用<form> 的輸入值執行AJAX 請求 3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
  34. 34. $.ajax() 不是罪 但 $('table').html(html) 是
  35. 35. 用 this 存取 Vue 實例 data data: { form: { id: '', name: '' }, + results: [] }, methods: { search: function () { + var vm = this; // 因 callback 內 this 指向不同 + $.post('http://api/', vm.form, function (res) { + vm.results = JSON.parse(res); + }); }
  36. 36. v‐for 自動依陣列產生 <tr> <input type="submit" value="查詢"> </div> </form> <table> <tbody> + <tr v-for="item in results"> + <td> {{ item.id }} </td> + <td> {{ item.name }} </td> + <td> {{ item.quantity }} </td> + </tr> </tbody> </table>
  37. 37. 案例中的需求: 1. 從<form> 撈輸入值回來 2. 用<form> 的輸入值執行AJAX 請求 3. 把AJAX 請求的結果陣列轉成<tr> 塞進<table>
  38. 38. 基本的功能完成了!! h ps://goo.gl/juKbew 怎麼加上其他花樣?
  39. 39. 舉例來說...簡單的表單驗證? 需求如下: 零件名不得為空值 驗證失敗時 將查詢按鈕設置disabled 屬性 將零件名的輸入框加上class「invalid」 驗證成功時自動解除上述設定
  40. 40. 讓 class 按照 true/false 開關 <div> <label>零件名: </label> - <input v-model="form.name"> + <input + v-model="form.name" + v-bind:class="{ + invalid: !isFormValid + }" + > </div> 當!isFormValid 為true 時,class 添加"invalid" 一項 為false 時則自動移除 v-bind: 可直接縮寫成「:」
  41. 41. 其他屬性如 disabled 也可以 <div> - <input type="submit" value="查詢"> + <input + type="submit" + value="查詢" + :disabled="!isFormValid" + > </div> 當!isFormValid 為true 時, 自動新增disabled 屬性,反之自動移除 另外v-bind 也可以用在綁定一般屬性的字串值, 例如name、id、value ...等
  42. 42. 依賴 data 的寫在 computed data: { form: { id: '', name: '' }, results: [] }, + computed: { + isFormValid: function () { + return this.form.name !== ''; + } + } computed 在依賴的data 或computed 屬性更新時, 會自動重新計算
  43. 43. 上面這串的運作邏輯是? 使用者在<input> 內打字時, 自動更新data 中的name name 被更新時自動重新計算isFormValid !isFormValid 為true 時 <input> 自動加上"invalid" class <button> 自動加上"disabled" 屬性 !isFormValid 為false 時 <input> 自動移除"invalid" class <button> 自動移除"disabled" 屬性
  44. 44. 完成的範例: h ps://goo.gl/x67m4Z
  45. 45. 一趟範例下來你學會了: 把jQuery 命令式編程改寫成Vue.js 宣告式渲染 初始化Vue 實例new Vue() 和存取data 從Vue 實例中取值的樣板{{ }} 數據綁定v-model 事件綁定v-on: 和它的縮寫@ 用computed 處理有相依性的屬性 元素屬性綁定v-bind: 和它的縮寫: 以及:class="" 專用的語法
  46. 46. 以資料驅動畫面 避免在 JS 操作 DOM 讓業務邏輯跟畫面定義乾淨切割
  47. 47. 更多好玩的都在官方文件 h ps://cn.vuejs.org/v2/guide
  48. 48. 下次講什麼? Vue.js 組件(Component)系統

×