SlideShare a Scribd company logo
從改寫後台 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>零件名: </label>
<input id="form-name">
</div>
<div>
<input type="submit" value="查詢">
</div>
</form>
<table>
<tbody>
</tbody>
</table>
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);
});
}
問題在哪?
畫面不能一目了然
<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);
事件處理也有一樣的問題
onclick="" 等必須佔用全域變數,原則上不考慮
某個handler 從哪掛上來的?
非得要實際跑再用開發者工具看嗎?囧rz
版型一改,選擇器重寫!!
把值從DOM 撈出來
把串接好的字串塞回去DOM
全部都是滿滿的選擇器!
業務邏輯跟細節操作混淆
隨著程式規模變大,很難看出實際的業務邏輯
寫和讀的時間全浪費在差不多但又得重寫的細節
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);
為了解決上述問題
如果可以...
讓 <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) {
讓事件綁定集中在 HTML
- <form onsubmit="return search()" action="#">
+ <form 呼叫這個元件的="某個函數">
- $('form').on('submit', search);
另外還要能避免汙染全域變數
自動依 JS 物件產生畫面
<table>
<tbody>
+ <tr 自動依這個產生一連串元素="JS的查詢結果陣列">
+ <td>陣列元素.編號</td>
+ <td>陣列元素.零件名</td>
+ <td>陣列元素.數量</td>
+ </tr>
</tbody>
</table>
- // 前略 for 迴圈
- html += '</tr>';
- });
- $('tbody').html(html);
讓 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/articles/vue-2-progressive-front-end-solution )
從 <script> 開始的 Vue.js
「漸進式」就是不用從一開始就被鎖死在
Node.js、webpack、....等完整建置環境
跟開始用jQuery 一樣簡單!
介绍- vue.js
用JSFiddle 或JSBin 等環境即時練習
開始使用:把官方文件給的script tag 複製貼上!
<script src="https://unpkg.com/vue/dist/vue.js"></script>
宣告式渲染起手式: {{ }} 樣板
<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);
加上 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>,發生了什麼事情?
怎麼理解?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.js
正式環境用縮小過的.min.js
https://unpkg.com/vue/dist/vue.min.js
一樣可以先刻畫面
- <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>
在 JS 裡面用 Vue 把資料接好
- // 先把原本的 code 全部刪掉
var app = new Vue({
el: '#app', // 讓這個 Vue 實例管理 #app 這個 DOM 節點
data: { // data 裏面的屬性可以在 v- 或 {{ }} 等地方取用
form: {
id: '',
name: ''
}
}
});
案例中的需求:
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()">
<div>
<label>編號: </label>
<input v-model="form.id">
</div>
v-on: 可直接縮寫成「@」
可加上.prevent 達到event.preventDefault(); 的效果
在 methods 寫入對應的處理器
var app = new Vue({
el: '#app',
data: {
form: {
id: '',
name: ''
}
},
+ // 使用 methods 定義事件處理器之類的 function
+ methods: {
+ search: function () {
+ // 一樣處理 AJAX 等等
+ }
+ }
});
案例中的需求:
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 = this; // 因 callback 內 this 指向不同
+ $.post('http://api/', vm.form, function (res) {
+ vm.results = JSON.parse(res);
+ });
}
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>
案例中的需求:
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:class="{
+ invalid: !isFormValid
+ }"
+ >
</div>
當!isFormValid 為true 時,class 添加"invalid" 一項
為false 時則自動移除
v-bind: 可直接縮寫成「:」
其他屬性如 disabled 也可以
<div>
- <input type="submit" value="查詢">
+ <input
+ type="submit"
+ value="查詢"
+ :disabled="!isFormValid"
+ >
</div>
當!isFormValid 為true 時,
自動新增disabled 屬性,反之自動移除
另外v-bind 也可以用在綁定一般屬性的字串值,
例如name、id、value ...等
依賴 data 的寫在 computed
data: {
form: {
id: '',
name: ''
},
results: []
},
+ computed: {
+ isFormValid: function () {
+ return this.form.name !== '';
+ }
+ }
computed 在依賴的data 或computed 屬性更新時,
會自動重新計算
上面這串的運作邏輯是?
使用者在<input> 內打字時,
自動更新data 中的name
name 被更新時自動重新計算isFormValid
!isFormValid 為true 時
<input> 自動加上"invalid" class
<button> 自動加上"disabled" 屬性
!isFormValid 為false 時
<input> 自動移除"invalid" class
<button> 自動移除"disabled" 屬性
完成的範例:
h ps://goo.gl/x67m4Z
一趟範例下來你學會了:
把jQuery 命令式編程改寫成Vue.js 宣告式渲染
初始化Vue 實例new Vue() 和存取data
從Vue 實例中取值的樣板{{ }}
數據綁定v-model
事件綁定v-on: 和它的縮寫@
用computed 處理有相依性的屬性
元素屬性綁定v-bind: 和它的縮寫:
以及:class="" 專用的語法
以資料驅動畫面
避免在 JS 操作 DOM
讓業務邏輯跟畫面定義乾淨切割
更多好玩的都在官方文件
h ps://cn.vuejs.org/v2/guide
下次講什麼?
Vue.js 組件(Component)系統

More Related Content

PDF
第4回 データフレームの基本操作 その2(解答付き)
PDF
第一次用 Vue.js 就愛上 [改]
PDF
給 iOS 工程師的 Vue.js 開發
PPTX
jQuery Mobile
PDF
CRUD 綜合運用
PDF
Rails talk-5
PPTX
只需要懂Jquery也能學react js
PDF
JavaScript 快速複習 2017Q1
第4回 データフレームの基本操作 その2(解答付き)
第一次用 Vue.js 就愛上 [改]
給 iOS 工程師的 Vue.js 開發
jQuery Mobile
CRUD 綜合運用
Rails talk-5
只需要懂Jquery也能學react js
JavaScript 快速複習 2017Q1
Ad

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