1. Vue.js
1.1. Vue.js是什麼?
1). 作用: 動态建構使用者界面
2). 特點:
* 遵循MVVM模式
* 編碼簡潔, 體積小, 運作效率高, 移動/PC端開發
* 它本身隻關注UI, 可以輕松引入vue插件和其它第三庫開發項目
3). 與其它架構的關聯:
* 借鑒angular的模闆和資料綁定技術
* 借鑒react的元件化和虛拟DOM技術
4). vue包含一系列的擴充插件(庫):
* vue-cli: vue腳手架
* vue-resource(axios): ajax請求
* vue-router: 路由
* vuex: 狀态管理
* vue-lazyload: 圖檔懶加載
* vue-scroller: 頁面滑動相關
* element-ui: 基于vue的元件庫(PC端)
* mint-ui: 基于vue的元件庫(移動端)
1.2. 基本使用
1). 引入vue.js
2). 建立Vue執行個體對象(vm), 指定選項(配置)對象
el : 指定dom标簽容器的選擇器
data : 指定初始化狀态資料的對象/函數(傳回一個對象)
3). 在頁面模闆中使用{{}}或vue指令
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 測試執行個體 - 菜鳥教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
</html>
cdn
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
1.3. 安裝-NPM 方法
由于 npm 安裝速度慢,本教程使用了淘寶的鏡像及其指令 cnpm
1.3.1. 使用淘寶 NPM 鏡像
大家都知道國内直接使用 npm 的官方鏡像是非常慢的,這裡推薦使用淘寶 NPM 鏡像。
淘寶 NPM 鏡像是一個完整 npmjs.org 鏡像,你可以用此代替官方版本(隻讀),同步頻率目前為 10分鐘 一次以保證盡量與官方服務同步。
添加倉庫位址
npm install --registry=https://registry.npm.taobao.org
你可以使用淘寶定制的 cnpm (gzip 壓縮支援) 指令行工具代替預設的 npm:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
這樣就可以使用 cnpm 指令來安裝子產品了:
$ cnpm install [name]
npm 版本需要大于 3.0,如果低于此版本需要更新它:
# 檢視版本
$ npm -v
2.3.0
#更新 npm
cnpm install npm -g
# 更新或安裝 cnpm
npm install cnpm -g
在用 Vue.js 建構大型應用時推薦使用 NPM 安裝:
# 最新穩定版
$ npm install vue
如果你遇到了使用 npm 安 裝node_modules 總是提示報錯:報錯: npm resource busy or locked.....。
可以先删除以前安裝的 node_modules :
npm cache clean
npm install
1.3.2. 指令行工具
Vue.js 提供一個官方指令行工具,可用于快速搭建大型單頁應用。
# 全局安裝 vue-cli
$ cnpm install --global vue-cli
# 建立一個基于 webpack 模闆的新項目
$ vue init webpack my-project
# 這裡需要進行一些配置,預設回車即可
This will install Vue 2.x version of the template.
For Vue 1.x use: vue init webpack#1.0 my-project
? Project name my-project
? Project description A Vue.js project
? Author runoob <[email protected]>
? Vue build standalone
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Setup unit tests with Karma + Mocha? Yes
? Setup e2e tests with Nightwatch? Yes
vue-cli · Generated "my-project".
To get started:
cd my-project
npm install
npm run dev
Documentation can be found at https://vuejs-templates.github.io/webpack
進入項目,安裝并運作:
$ cd my-project
$ cnpm install
$ cnpm run dev
DONE Compiled successfully in 4388ms
> Listening at http://localhost:8080
成功執行以上指令後通路 http://localhost:8080/,輸出結果如下所示:

**注意:**Vue.js 不支援 IE8 及其以下 IE 版本。
1.4. Vue對象的選項
上一章節中我們使用了 npm 安裝項目,我們在 IDE(Eclipse、Atom等) 中打開該目錄,結構如下所示:
1.4.1. 目錄解析
目錄/檔案 | 說明 |
---|---|
build | 項目建構(webpack)相關代碼 |
config | 配置目錄,包括端口号等。我們初學可以使用預設的。 |
node_modules | npm 加載的項目依賴子產品 |
src | 這裡是我們要開發的目錄,基本上要做的事情都在這個目錄裡。裡面包含了幾個目錄及檔案:assets: 放置一些圖檔,如logo等。components: 目錄裡面放了一個元件檔案,可以不用。App.vue: 項目入口檔案,我們也可以直接将元件寫這裡,而不使用 components 目錄。main.js: 項目的核心檔案。 |
static | 靜态資源目錄,如圖檔、字型等。 |
test | 初始測試目錄,可删除 |
.xxxx檔案 | 這些是一些配置檔案,包括文法配置,git配置等。 |
index.html | 首頁入口檔案,你可以添加一些 meta 資訊或統計代碼啥的。 |
package.json | 項目配置檔案。 |
README.md | 項目的說明文檔,markdown 格式 |
1.4.2. 起步
每個 Vue 應用都需要通過執行個體化 Vue 來實作。
文法格式如下:
var vm = new Vue({
// 選項
})
接下來讓我們通過執行個體來看下 Vue 構造器中需要哪些内容:
執行個體
<div id="vue_det">
<h1>site : {{site}}</h1>
<h1>url : {{url}}</h1>
<h1>{{details()}}</h1>
</div>
<script type="text/javascript">
var vm = new Vue({
el: '#vue_det',
data: {
site: "菜鳥教程",
url: "www.runoob.com",
alexa: "10000"
},
methods: {
details: function() {
return this.site + " - 學的不僅是技術,更是夢想!";
}
}
})
</script>
可以看到在 Vue 構造器中有一個el 參數,它是 DOM 元素中的 id。在上面執行個體中 id 為 vue_det,在 div 元素中:
<div id = "vue_det"></div>
這意味着我們接下來的改動全部在以上指定的 div 内,div 外部不受影響。
接下來我們看看如何定義資料對象。
data 用于定義屬性,執行個體中有三個屬性分别為:site、url、alexa。
methods 用于定義的函數,可以通過 return 來傳回函數值。
{{ }} 用于輸出對象屬性和函數傳回值。
<div id="vue_det">
<h1>site : {{site}}</h1>
<h1>url : {{url}}</h1>
<h1>{{details()}}</h1>
</div>
當一個 Vue 執行個體被建立時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的所有的屬性。當這些屬性的值發生改變時,html 視圖将也會産生相應的變化。
<div id="vue_det">
<h1>site : {{site}}</h1>
<h1>url : {{url}}</h1>
<h1>Alexa : {{alexa}}</h1>
</div>
<script type="text/javascript">
// 我們的資料對象
var data = { site: "菜鳥教程", url: "www.runoob.com", alexa: 10000}
var vm = new Vue({
el: '#vue_det',
data: data
})
// 它們引用相同的對象!
document.write(vm.site === data.site) // true
document.write("<br>")
// 設定屬性也會影響到原始資料
vm.site = "Runoob"
document.write(data.site + "<br>") // Runoob
// ……反之亦然
data.alexa = 1234
document.write(vm.alexa) // 1234
</script>
1.4.3. 模闆文法
使用 v-html 指令用于輸出 html 代碼:
<div id="app">
<div v-html="message"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
message: '<h1>菜鳥教程</h1>'
}
})
</script>
屬性
HTML 屬性中的值應使用 v-bind 指令。
以下執行個體判斷 class1 的值,如果為 true 使用 class1 類的樣式,否則不使用該類:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 測試執行個體 - 菜鳥教程(runoob.com)</title>
</head>
<style>
.class1{
background: #444;
color: #eee;
}
</style>
<body>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
<div id="app">
<label for="r1">修改顔色</label><input type="checkbox" v-model="use" id="r1">
<br><br>
<div v-bind:class="{'class1': use}">
v-bind:class 指令
</div>
</div>
<script>
new Vue({
el: '#app',
data:{
use: false
}
});
</script>
</body>
指令
指令是帶有 v- 字首的特殊屬性。
指令用于在表達式的值改變時,将某些行為應用到 DOM 上。如下例子:
<div id="app">
<p v-if="seen">現在你看到我了</p>
</div>
1.4.4. 參數
參數在指令後以冒号指明。例如, v-bind 指令被用來響應地更新 HTML 屬性:
<div id="app">
<pre><a v-bind:href="url" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" >菜鳥教程</a></pre>
</div>
在這裡 href 是參數,告知 v-bind 指令将該元素的 href 屬性與表達式 url 的值綁定。
另一個例子是 v-on 指令,它用于監聽 DOM 事件:
<a v-on:click="doSomething">
在這裡參數是監聽的事件名。
修飾符
修飾符是以半角句号 . 指明的特殊字尾,用于指出一個指令應該以特殊方式綁定。例如,.prevent 修飾符告訴 v-on 指令對于觸發的事件調用 event.preventDefault():
<form v-on:submit.prevent="onSubmit"></form>
1.4.5. ==使用者輸入==
在 input 輸入框中我們可以使用 v-model 指令來實作雙向資料綁定:
<div id="app">
<p>{{ message }}</p>
<input v-model="message">
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Runoob!'
}
})
</script>
==v-model== 指令用來在 input、select、textarea、checkbox、radio 等表單控件元素上建立雙向資料綁定,根據表單上的值,自動更新綁定的元素的值。
按鈕的事件我們可以使用 v-on 監聽事件,并對使用者的輸入進行響應。
過濾器
Vue.js 允許你自定義過濾器,被用作一些常見的文本格式化。由"管道符"訓示, 格式如下:
<!-- 在兩個大括号中 -->
{{ message | capitalize }}
<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>
過濾器函數接受表達式的值作為第一個參數。
以下執行個體對輸入的字元串第一個字母轉為大寫:
<div id="app">
{{ message | capitalize }}
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'runoob'
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
</script>
過濾器可以串聯:
{{ message | filterA | filterB }}
過濾器是 JavaScript 函數,是以可以接受參數:
{{ message | filterA('arg1', arg2) }}
這裡,message 是第一個參數,字元串 'arg1' 将傳給過濾器作為第二個參數, arg2 表達式的值将被求值然後傳給過濾器作為第三個參數。
縮寫
v-bind 縮寫
Vue.js 為兩個最為常用的指令提供了特别的縮寫:
<!-- 完整文法 -->
<a v-bind:href="url" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ></a>
<!-- 縮寫 -->
<a :href="url" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" ></a>
v-on 縮寫
<!-- 完整文法 -->
<a v-on:click="doSomething"></a>
<!-- 縮寫 -->
<a @click="doSomething"></a>
1.4.6. 條件
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
type: 'C'
}
})
</script>
v-show
我們也可以使用 v-show 指令來根據條件展示元素:
v-show 指令
<h1 v-show="ok">Hello!</h1>
1.4.7. 循環語句
循環使用 v-for 指令。
v-for 指令需要以 site in sites 形式的特殊文法, sites 是源資料數組并且 site 是數組元素疊代的别名。
v-for 可以綁定資料到數組來渲染一個清單:
<div id="app">
<ol>
<li v-for="site in sites">
{{ site.name }}
</li>
</ol>
</div>
<script>
new Vue({
el: '#app',
data: {
sites: [
{ name: 'Runoob' },
{ name: 'Google' },
{ name: 'Taobao' }
]
}
})
</script>
v-for 疊代對象
v-for 可以通過一個對象的屬性來疊代資料:
<div id="app">
<ul>
<li v-for="value in object">
{{ value }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
object: {
name: '菜鳥教程',
url: 'http://www.runoob.com',
slogan: '學的不僅是技術,更是夢想!'
}
}
})
</script>
你也可以提供第二個的參數為鍵名:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 測試執行個體 - 菜鳥教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="(value, key) in object">
{{ key }} : {{ value }}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
object: {
name: '菜鳥教程',
url: 'http://www.runoob.com',
slogan: '學的不僅是技術,更是夢想!'
}
}
})
</script>
</body>
</html>
第三個參數為索引:
<div id="app">
<ul>
<li v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</li>
</ul>
</div>
1.4.8. 計算屬性
computer 屬性“依賴緩存”的概念以及與 method 的差别。如下面代碼,cnt 是獨立于 vm 對象的變量。在使用 reversedMessage 這個計算屬性的時候,第一次會執行代碼,得到一個值,以後再使用 reversedMessage 這個計算屬性,因為 vm 對象沒有發生改變,于是界面渲染就直接用這個值,不再重複執行代碼。而 reversedMessage2 沒有這個緩存,隻要用一次,函數代碼就執行一次,于是每次傳回值都不一樣。
當你沒有使用到計算屬性的依賴緩存的時候,可以使用定義方法來代替計算屬性,在 methods 裡定義一個方法可以實作相同的效果,甚至該方法還可以接受參數,使用起來更靈活。
1.4.9. Vue.js 監聽屬性
<div id = "app">
<p style = "font-size:25px;">計數器: {{ counter }}</p>
<button @click = "counter++" style = "font-size:25px;">點我</button>
</div>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
counter: 1
}
});
vm.$watch('counter', function(nval, oval) {
alert('計數器值的變化 :' + oval + ' 變為 ' + nval + '!');
});
</script>
1.4.10. 樣式綁定
Vue.js class
class 與 style 是 HTML 元素的屬性,用于設定元素的樣式,我們可以用 v-bind 來設定樣式屬性。
Vue.js v-bind 在處理 class 和 style 時, 專門增強了它。表達式的結果類型除了字元串之外,還可以是對象或數組。
<div class="active"></div>
1.4.11. Vue.js 事件處理器
通常情況下,我們需要使用一個方法來調用 JavaScript 方法。
v-on 可以接收一個定義的方法來調用。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 測試執行個體 - 菜鳥教程(runoob.com)</title>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- `greet` 是在下面定義的方法名 -->
<button v-on:click="greet">Greet</button>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
name: 'Vue.js'
},
// 在 `methods` 對象中定義方法
methods: {
greet: function (event) {
// `this` 在方法裡指目前 Vue 執行個體
alert('Hello ' + this.name + '!')
// `event` 是原生 DOM 事件
if (event) {
alert(event.target.tagName)
}
}
}
})
// 也可以用 JavaScript 直接調用方法
app.greet() // -> 'Hello Vue.js!'
</script>
</body>
</html>
1.4.12. 事件修飾符
Vue.js 為 v-on 提供了事件修飾符來處理 DOM 事件細節,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js通過由點(.)表示的指令字尾來調用修飾符。
-
.stop
-
.prevent
-
.capture
-
.self
-
.once
<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 送出事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 隻有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件偵聽器時使用事件捕獲模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 隻當事件在該元素本身(而不是子元素)觸發時觸發回調 -->
<div v-on:click.self="doThat">...</div>
<!-- click 事件隻能點選一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>
1.4.13. 按鍵修飾符
Vue 允許為 v-on 在監聽鍵盤事件時添加按鍵修飾符:
<!-- 隻有在 keyCode 是 13 時調用 vm.submit() -->
<input v-on:keyup.13="submit">
記住所有的 keyCode 比較困難,是以 Vue 為最常用的按鍵提供了别名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 縮寫文法 -->
<input @keyup.enter="submit">
全部的按鍵别名:
-
.enter
-
.tab
-
(捕獲 "删除" 和 "倒退" 鍵).delete
-
.esc
-
.space
-
.up
-
.down
-
.left
-
.right
-
.ctrl
-
.alt
-
.shift
-
.meta
執行個體
<p><!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
1.4.14. ==Vue.js 表單==
這節我們為大家介紹 Vue.js 表單上的應用。
你可以用 v-model 指令在表單控件元素上建立雙向資料綁定。g](vue_res/
v-model 會根據控件類型自動選取正确的方法來更新元素。
1.5. 輸入框
執行個體中示範了 input 和 textarea 元素中使用 v-model 實作雙向資料綁定:
<div id="app">
<p>input 元素:</p>
<input v-model="message" placeholder="編輯我……">
<p>消息是: {{ message }}</p>
<p>textarea 元素:</p>
<p style="white-space: pre">{{ message2 }}</p>
<textarea v-model="message2" placeholder="多行文本輸入……"></textarea>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Runoob',
message2: '菜鳥教程\r\nhttp://www.runoob.com'
}
})
</script>
1.5.1. 複選框
複選框如果是一個為邏輯值,如果是多個則綁定到同一個數組:
1.6. 複選框
<div id="app">
<p>單個複選框:</p>
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
<p>多個複選框:</p>
<input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
<label for="runoob">Runoob</label>
<input type="checkbox" id="google" value="Google" v-model="checkedNames">
<label for="google">Google</label>
<input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
<label for="taobao">taobao</label>
<br>
<span>選擇的值為: {{ checkedNames }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
checked : false,
checkedNames: []
}
})
</script>
1.6.1. 單選按鈕
以下執行個體中示範了單選按鈕的雙向資料綁定:
<div id="app">
<input type="radio" id="runoob" value="Runoob" v-model="picked">
<label for="runoob">Runoob</label>
<br>
<input type="radio" id="google" value="Google" v-model="picked">
<label for="google">Google</label>
<br>
<span>選中值為: {{ picked }}</span>
</div>
<script>
new Vue({
el: '#app',
data: {
picked : 'Runoob'
}
})
</script>
選中後,效果如下圖所示g](vue_res/vue_res/
1.6.2. select 清單
以下執行個體中示範了下拉清單的雙向資料綁定:
<div id="app">
<select v-model="selected" name="fruit">
<option value="">選擇一個網站</option>
<option value="www.runoob.com">Runoob</option>
<option value="www.google.com">Google</option>
</select>
<div id="output">
選擇的網站是: {{selected}}
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
selected: ''
}
})
</script>
選取 Runoob,g](vue_res/(vue_res/如下所示:
1.6.3. 修飾符
1.6.3.1. .lazy
在預設情況下, v-model 在 input 事件中同步輸入框的值與資料,但你可以添加一個修飾符 lazy ,進而轉變為在 change 事件中同步:
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >
1.6.3.2. .number
如果想自動将使用者的輸入值轉為 Number 類型(如果原值的轉換結果為 NaN 則傳回原值),可以添加一個修飾符 number 給 v-model 來處理輸入值:
<input v-model.number="age" type="number">
這通常很有用,因為在 type="number" 時 HTML 中輸入的值也總是會傳回字元串類型。
1.6.3.3. .trim
如果要自動過濾使用者輸入的首尾空格,可以添加 trim 修飾符到 v-model 上過濾輸入:
<input v-model.trim="msg">
1.6.4. ==Vue.js 元件==
元件(Component)是 Vue.js 最強大的功能之一。
元件可以擴充 HTML 元素,封裝可重用的代碼。
元件系統讓我們可以用獨立可複用的小元件來建構大型應用,幾乎任意類型的g](vue_res/(vue_res/面都可以抽象為一個元件樹:
注冊一個全局元件文法格式如下:
Vue.component(tagName, options)
tagName 為元件名,options 為配置選項。注冊後,我們可以使用以下方式來調用元件:
<tagName></tagName>
1.6.4.1. 全局元件
所有執行個體都能用全局元件。
<div id="app">
<runoob></runoob>
</div>
<script>
// 注冊
Vue.component('runoob', {
template: '<h1>自定義元件!</h1>'
})
// 建立根執行個體
new Vue({
el: '#app'
})
</script>
1.6.4.2. 局部元件
我們也可以在執行個體選項中注冊局部元件,這樣元件隻能在這個執行個體中使用:
<div id="app">
<runoob></runoob>
</div>
<script>
var Child = {
template: '<h1>自定義元件!</h1>'
}
// 建立根執行個體
new Vue({
el: '#app',
components: {
// <runoob> 将隻在父模闆可用
'runoob': Child
}
})
</script>
1.6.4.3. Prop
prop 是父元件用來傳遞資料的一個自定義屬性。
父元件的資料需要通過 props 把資料傳給子元件,子元件需要顯式地用 props 選項聲明 "prop":
<div id="app">
<child message="hello!"></child>
</div>
<script>
// 注冊
Vue.component('child', {
// 聲明 props
props: ['message'],
// 同樣也可以在 vm 執行個體中像 "this.message" 這樣使用
template: '<span>{{ message }}</span>'
})
// 建立根執行個體
new Vue({
el: '#app'
})
</script>
1.6.4.4. 動态 Prop
類似于用 v-bind 綁定 HTML 特性到一個表達式,也可以用 v-bind 動态綁定 props 的值到父元件的資料中。每當父元件的資料變化時,該變化也會傳導給子元件:
<div id="app">
<div>
<input v-model="parentMsg">
<br>
<child v-bind:message="parentMsg"></child>
</div>
</div>
<script>
// 注冊
Vue.component('child', {
// 聲明 props
props: ['message'],
// 同樣也可以在 vm 執行個體中像 "this.message" 這樣使用
template: '<span>{{ message }}</span>'
})
// 建立根執行個體
new Vue({
el: '#app',
data: {
parentMsg: '父元件内容'
}
})
</script>
以下執行個體中将 v-bind 指令将 todo 傳到每一個重複的元件中:
<div id="app">
<ol>
<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
</ol>
</div>
<script>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
new Vue({
el: '#app',
data: {
sites: [
{ text: 'Runoob' },
{ text: 'Google' },
{ text: 'Taobao' }
]
}
})
</script>
注意: prop 是單向綁定的:當父元件的屬性變化時,将傳導給子元件,但是不會反過來。
1.6.4.5. Prop 驗證
元件可以為 props 指定驗證要求。
為了定制 prop 的驗證方式,你可以為 props 中的值提供一個帶有驗證需求的對象,而不是一個字元串數組。例如:
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字元串
propC: {
type: String,
required: true
},
// 帶有預設值的數字
propD: {
type: Number,
default: 100
},
// 帶有預設值的對象
propE: {
type: Object,
// 對象或數組預設值必須從一個工廠函數擷取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須比對下列字元串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
當 prop 驗證失敗的時候,(開發環境建構版本的) Vue 将會産生一個控制台的警告。
type 可以是下面原生構造器:
-
String
-
Number
-
Boolean
-
Array
-
Object
-
Date
-
Function
-
Symbol
type 也可以是一個自定義構造器,使用 instanceof 檢測。
1.6.4.6. 自定義事件
父元件是使用 props 傳遞資料給子元件,但如果子元件要把資料傳遞回去,就需要使用自定義事件!
我們可以使用 v-on 綁定自定義事件, 每個 Vue 執行個體都實作了事件接口(Events interface),即:
- 使用
監聽事件$on(eventName)
- 使用
觸發事件$emit(eventName)
另外,父元件可以在使用子元件的地方直接用 v-on 來監聽子元件觸發的事件。
以下執行個體中子元件已經和它外部完全解耦了。它所做的隻是觸發一個父元件關心的内部事件。
<div id="app">
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
</div>
<script>
Vue.component('button-counter', {
template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
incrementHandler: function () {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal: function () {
this.total += 1
}
}
})
</script>
如果你想在某個元件的根元素上監聽一個原生事件。可以使用 .native 修飾 v-on 。例如:
<my-component v-on:click.native="doTheThing"></my-component>
data 必須是一個函數
上面例子中,可以看到 button-counter 元件中的 data 不是一個對象,而是一個函數:
data: function () {
return {
count: 0
}
}
這樣的好處就是每個執行個體可以維護一份被傳回對象的獨立的拷貝,如果 data 是一個對象則會影響到其他執行個體,如下所示:
<div id="components-demo3" class="demo">
<button-counter2></button-counter2>
<button-counter2></button-counter2>
<button-counter2></button-counter2>
</div>
<script>
var buttonCounter2Data = {
count: 0
}
Vue.component('button-counter2', {
/*
data: function () {
// data 選項是一個函數,元件不互相影響
return {
count: 0
}
},
*/
data: function () {
// data 選項是一個對象,會影響到其他執行個體
return buttonCounter2Data
},
template: '<button v-on:click="count++">點選了 {{ count }} 次。</button>'
})
new Vue({ el: '#components-demo3' })
</script>
1.6.5. Vue.js 自定義指令
除了預設設定的核心指令( v-model 和 v-show ), Vue 也允許注冊自定義指令。
下面我們注冊一個全局指令 v-focus, 該指令的功能是在頁面加載時,元素獲得焦點:
<div id="app">
<p>頁面載入時,input 元素自動擷取焦點:</p>
<input v-focus>
</div>
<script>
// 注冊一個全局自定義指令 v-focus
Vue.directive('focus', {
// 當綁定元素插入到 DOM 中。
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
// 建立根執行個體
new Vue({
el: '#app'
})
</script>
我們也可以在執行個體使用 directives 選項來注冊局部指令,這樣指令隻能在這個執行個體中使用:
<div id="app">
<p>頁面載入時,input 元素自動擷取焦點:</p>
<input v-focus>
</div>
<script>
// 建立根執行個體
new Vue({
el: '#app',
directives: {
// 注冊一個局部的自定義指令 v-focus
focus: {
// 指令的定義
inserted: function (el) {
// 聚焦元素
el.focus()
}
}
}
})
</script>
1.6.6. 鈎子
1.6.6.1. 鈎子函數
指令定義函數提供了幾個鈎子函數(可選):
-
: 隻調用一次,指令第一次綁定到元素時調用,用這個鈎子函數可以定義一個在綁定時執行一次的初始化動作。bind
-
: 被綁定元素插入父節點時調用(父節點存在即可調用,不必存在于 document 中)。inserted
-
: 被綁定元素所在的模闆更新時調用,而不論綁定值是否變化。通過比較更新前後的綁定值,可以忽略不必要的模闆更新(詳細的鈎子函數參數見下)。update
-
: 被綁定元素所在模闆完成一次更新周期時調用。componentUpdated
-
: 隻調用一次, 指令與元素解綁時調用。unbind
1.6.6.2. 鈎子函數參數
鈎子函數的參數有:
- el: 指令所綁定的元素,可以用來直接操作 DOM 。
-
binding
: 一個對象,包含以下屬性:
- name: 指令名,不包括
字首。v-
- value: 指令的綁定值, 例如:
, value 的值是v-my-directive="1 + 1"
。2
- oldValue: 指令綁定的前一個值,僅在
和update
鈎子中可用。無論值是否改變都可用。componentUpdated
- expression: 綁定值的表達式或變量名。 例如
, expression 的值是v-my-directive="1 + 1"
。"1 + 1"
- arg: 傳給指令的參數。例如
, arg 的值是v-my-directive:foo
。"foo"
- modifiers: 一個包含修飾符的對象。 例如:
, 修飾符對象 modifiers 的值是v-my-directive.foo.bar
。{ foo: true, bar: true }
- name: 指令名,不包括
- vnode: Vue 編譯生成的虛拟節點。
- oldVnode: 上一個虛拟節點,僅在
和update
鈎子中可用。componentUpdated
<div id="app" v-runoob:hello.a.b="message">
</div>
<script>
Vue.directive('runoob', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
})
new Vue({
el: '#app',
data: {
message: '菜鳥教程!'
}
})
</script>
有時候我們不需要其他鈎子函數,我們可以簡寫函數,如下格式:
Vue.directive('runoob', function (el, binding) {
// 設定指令的背景顔色
el.style.backgroundColor = binding.value.color
})
指令函數可接受所有合法的 JavaScript 表達式,以下執行個體傳入了 JavaScript 對象:
<div id="app">
<div v-runoob="{ color: 'green', text: '菜鳥教程!' }"></div>
</div>
<script>
Vue.directive('runoob', function (el, binding) {
// 簡寫方式設定文本及背景顔色
el.innerHTML = binding.value.text
el.style.backgroundColor = binding.value.color
})
new Vue({
el: '#app'
})
</script>
1.6.7. Vue.js 路由
Vue.js 路由允許我們通過不同的 URL 通路不同的内容。
通過 Vue.js 可以實作多視圖的單頁Web應用(single page web application,SPA)。
Vue.js 路由需要載入 vue-router 庫
中文文檔位址:vue-router文檔。
1.6.7.1. 安裝
1.6.7.1.1. 1、直接下載下傳 / CDN
https://unpkg.com/vue-router/dist/vue-router.js
1.6.7.1.2. NPM
推薦使用淘寶鏡像:
cnpm install vue-router
1.6.7.2. 簡單執行個體
Vue.js + vue-router 可以很簡單的實作單頁應用。
是一個元件,該元件用于設定一個導航連結,切換不同 HTML 内容。 to 屬性為目标位址, 即要顯示的内容。
以下執行個體中我們将 vue-router 加進來,然後配置元件和路由映射,再告訴 vue-router 在哪裡渲染它們。代碼如下所示:
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 元件來導航. -->
<!-- 通過傳入 `to` 屬性指定連結. -->
<!-- <router-link> 預設會被渲染成一個 `<a>` 标簽 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由比對到的元件将渲染在這裡 -->
<router-view></router-view>
</div>
// 0. 如果使用子產品化機制程式設計,導入 Vue 和 VueRouter,要調用 Vue.use(VueRouter)
// 1. 定義(路由)元件。
// 可以從其他檔案 import 進來
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定義路由
// 每個路由應該映射一個元件。 其中"component" 可以是
// 通過 Vue.extend() 建立的元件構造器,
// 或者,隻是一個元件配置對象。
// 我們晚點再讨論嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 建立 router 執行個體,然後傳 `routes` 配置
// 你還可以傳别的配置參數, 不過先這麼簡單着吧。
const router = new VueRouter({
routes // (縮寫)相當于 routes: routes
})
// 4. 建立和挂載根執行個體。
// 記得要通過 router 配置參數注入路由,
// 進而讓整個應用都有路由功能
const app = new Vue({
router
}).$mount('#app')
// 現在,應用已經啟動了!
點選過的導航連結都會加上樣式 class ="router-link-exact-active router-link-active"。
1.6.7.3. 相關屬性
接下來我們可以了解下更多關于 的屬性。
1.6.7.3.1. to
表示目标路由的連結。 當被點選後,内部會立刻把 to 的值傳到 router.push(),是以這個值可以是一個字元串或者是描述目标位置的對象。
<!-- 字元串 -->
<router-link to="home">Home</router-link>
<!-- 渲染結果 -->
<a href="home" target="_blank" rel="external nofollow" >Home</a>
<!-- 使用 v-bind 的 JS 表達式 -->
<router-link v-bind:to="'home'">Home</router-link>
<!-- 不寫 v-bind 也可以,就像綁定别的屬性一樣 -->
<router-link :to="'home'">Home</router-link>
<!-- 同上 -->
<router-link :to="{ path: 'home' }">Home</router-link>
<!-- 命名的路由 -->
<router-link :to="{ name: 'user', params: { userId: 123 }}">User</router-link>
<!-- 帶查詢參數,下面的結果為 /register?plan=private -->
<router-link :to="{ path: 'register', query: { plan: 'private' }}">Register</router-link>
1.6.7.3.2. replace
設定 replace 屬性的話,當點選時,會調用 router.replace() 而不是 router.push(),導航後不會留下 history 記錄。
<router-link :to="{ path: '/abc'}" replace></router-link>
1.6.7.3.3. append
設定 append 屬性後,則在目前 (相對) 路徑前添加基路徑。例如,我們從 /a 導航到一個相對路徑 b,如果沒有配置 append,則路徑為 /b,如果配了,則為 /a/b
<router-link :to="{ path: 'relative/path'}" append></router-link>
1.6.7.3.4. tag
有時候想要
<router-link>
渲染成某種标簽,例如
<li>
。 于是我們使用
tag
prop 類指定何種标簽,同樣它還是會監聽點選,觸發導航。
<router-link to="/foo" tag="li">foo</router-link>
<!-- 渲染結果 -->
<li>foo</li>
1.6.7.3.5. active-class
設定 連結激活時使用的 CSS 類名。可以通過以下代碼來替代。
<style>
._active{
background-color : red;
}
</style>
<p>
<router-link v-bind:to = "{ path: '/route1'}" active-class = "_active">Router Link 1</router-link>
<router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>
注意這裡 class 使用 active_class="_active"。
1.6.7.3.6. exact-active-class
配置當連結被精确比對的時候應該激活的 class。可以通過以下代碼來替代。
<p>
<router-link v-bind:to = "{ path: '/route1'}" exact-active-class = "_active">Router Link 1</router-link>
<router-link v-bind:to = "{ path: '/route2'}" tag = "span">Router Link 2</router-link>
</p>
1.6.7.3.7. event
聲明可以用來觸發導航的事件。可以是一個字元串或是一個包含字元串的數組。
<router-link v-bind:to = "{ path: '/route1'}" event = "mouseover">Router Link 1</router-link>
以上代碼設定了 event 為 mouseover ,及在滑鼠移動到 Router Link 1 上時導航的 HTML 内容會發生改變。
1.6.7.4. NPM 路由執行個體
接下來我們示範了一個使用 npm 簡單的路由執行個體,開始前,請先下載下傳該執行個體源代碼:
路由執行個體
你也可以在 Github 上下載下傳:https://github.com/chrisvfritz/vue-2.0-simple-routing-example
下載下傳完後,解壓該目錄,重命名目錄為 vue-demo,vu 并進入該目錄,執行以下指令:
# 安裝依賴,使用淘寶資源指令 cnpm
cnpm install
# 啟動應用,位址為 localhost:8080
cnpm run dev
如果你需要釋出到正式環境可以執行以下指令:
cnpm run build
執行成功後,訪g](vue_res/ttp://localhost:8080 即可看到如下界面:
1.6.8. Vue.js Ajax(axios)
1.6.8.1. test
Vue.js 2.0 版本推薦使用 axios 來完成 ajax 請求。
Axios 是一個基于 Promise 的 HTTP 庫,可以用在浏覽器和 node.js 中。
Github開源位址: https://github.com/axios/axios
1.6.8.1.1. 安裝方法
使用 cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
或
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
使用 npm:
$ npm install axios
使用 bower:
$ bower install axios
使用 yarn:
$ yarn add axios
1.6.8.1.2. GET 方法
我們可以簡單的讀取 JSON 資料:
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('https://www.runoob.com/try/ajax/json_demo.json')
.then(response => (this.info = response))
.catch(function (error) { // 請求失敗處理
console.log(error);
});
}
})
使用 response.data 讀取 JSON 資料:
<div id="app">
<h1>網站清單</h1>
<div
v-for="site in info"
>
{{ site.name }}
</div>
</div>
<script type = "text/javascript">
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.get('https://www.runoob.com/try/ajax/json_demo.json')
.then(response => (this.info = response.data.sites))
.catch(function (error) { // 請求失敗處理
console.log(error);
});
}
})
</script>
GET 方法傳遞參數格式如下:
// 直接在 URL 上添加參數 ID=12345
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 也可以通過 parmas 設定參數:
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1.6.8.1.3. POST 方法
new Vue({
el: '#app',
data () {
return {
info: null
}
},
mounted () {
axios
.post('https://www.runoob.com/try/ajax/json_demo.json')
.then(response => (this.info = response))
.catch(function (error) { // 請求失敗處理
console.log(error);
});
}
})
POST 方法傳遞參數格式如下:
axios.post('/user', {
firstName: 'Fred', // 參數 firstName
lastName: 'Flintstone' // 參數 lastName
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
1.6.8.1.4. 執行多個并發請求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 兩個請求現在都執行完成
}));
1.6.8.1.5. axios API
可以通過向 axios 傳遞相關配置來建立請求。
axios(config)
// 發送 POST 請求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
// GET 請求遠端圖檔
axios({
method:'get',
url:'http://bit.ly/2mTM3nY',
responseType:'stream'
})
.then(function(response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
axios(url[, config])
// 發送 GET 請求(預設的方法)
axios('/user/12345');
1.6.8.1.6. 請求方法的别名
為友善使用,官方為所有支援的請求方法提供了别名,可以直接使用别名來發起請求:
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.patch(url[, data[, config]])
**注意:**在使用别名方法時, url、method、data 這些屬性都不必在配置中指定。
1.6.8.1.7. 并發
處理并發請求的助手函數:
axios.all(iterable)
axios.spread(callback)
1.6.8.1.8. 建立執行個體
可以使用自定義配置建立一個 axios 執行個體:
axios.create([config])
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
1.6.8.1.9. 執行個體方法
以下是可用的執行個體方法。指定的配置将與執行個體的配置合并:
axios#request(config)
axios#get(url[, config])
axios#delete(url[, config])
axios#head(url[, config])
axios#post(url[, data[, config]])
axios#put(url[, data[, config]])
axios#patch(url[, data[, config]])
1.6.8.1.10. 請求配置項
下面是建立請求時可用的配置選項,注意隻有 url 是必需的。如果沒有指定 method,請求将預設使用 get 方法。
{
// `url` 是用于請求的伺服器 URL
url: "/user",
// `method` 是建立請求時使用的方法
method: "get", // 預設是 get
// `baseURL` 将自動加在 `url` 前面,除非 `url` 是一個絕對 URL。
// 它可以通過設定一個 `baseURL` 便于為 axios 執行個體的方法傳遞相對 URL
baseURL: "https://some-domain.com/api/",
// `transformRequest` 允許在向伺服器發送前,修改請求資料
// 隻能用在 "PUT", "POST" 和 "PATCH" 這幾個請求方法
// 後面數組中的函數必須傳回一個字元串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 對 data 進行任意轉換處理
return data;
}],
// `transformResponse` 在傳遞給 then/catch 前,允許修改響應資料
transformResponse: [function (data) {
// 對 data 進行任意轉換處理
return data;
}],
// `headers` 是即将被發送的自定義請求頭
headers: {"X-Requested-With": "XMLHttpRequest"},
// `params` 是即将與請求一起發送的 URL 參數
// 必須是一個無格式對象(plain object)或 URLSearchParams 對象
params: {
ID: 12345
},
// `paramsSerializer` 是一個負責 `params` 序列化的函數
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: "brackets"})
},
// `data` 是作為請求主體被發送的資料
// 隻适用于這些請求方法 "PUT", "POST", 和 "PATCH"
// 在沒有設定 `transformRequest` 時,必須是以下類型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏覽器專屬:FormData, File, Blob
// - Node 專屬: Stream
data: {
firstName: "Fred"
},
// `timeout` 指定請求逾時的毫秒數(0 表示無逾時時間)
// 如果請求話費了超過 `timeout` 的時間,請求将被中斷
timeout: 1000,
// `withCredentials` 表示跨域請求時是否需要使用憑證
withCredentials: false, // 預設的
// `adapter` 允許自定義處理請求,以使測試更輕松
// 傳回一個 promise 并應用一個有效的響應 (查閱 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示應該使用 HTTP 基礎驗證,并提供憑據
// 這将設定一個 `Authorization` 頭,覆寫掉現有的任意使用 `headers` 設定的自定義 `Authorization`頭
auth: {
username: "janedoe",
password: "s00pers3cret"
},
// `responseType` 表示伺服器響應的資料類型,可以是 "arraybuffer", "blob", "document", "json", "text", "stream"
responseType: "json", // 預設的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名稱
xsrfCookieName: "XSRF-TOKEN", // default
// `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱
xsrfHeaderName: "X-XSRF-TOKEN", // 預設的
// `onUploadProgress` 允許為上傳處理進度事件
onUploadProgress: function (progressEvent) {
// 對原生進度事件的處理
},
// `onDownloadProgress` 允許為下載下傳處理進度事件
onDownloadProgress: function (progressEvent) {
// 對原生進度事件的處理
},
// `maxContentLength` 定義允許的響應内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定義對于給定的HTTP 響應狀态碼是 resolve 或 reject promise 。如果 `validateStatus` 傳回 `true` (或者設定為 `null` 或 `undefined`),promise 将被 resolve; 否則,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 預設的
},
// `maxRedirects` 定義在 node.js 中 follow 的最大重定向數目
// 如果設定為0,将不會 follow 任何重定向
maxRedirects: 5, // 預設的
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定義在執行 http 和 https 時使用的自定義代理。允許像這樣配置選項:
// `keepAlive` 預設沒有啟用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// "proxy" 定義代理伺服器的主機名稱和端口
// `auth` 表示 HTTP 基礎驗證應當用于連接配接代理,并提供憑據
// 這将會設定一個 `Proxy-Authorization` 頭,覆寫掉已有的通過使用 `header` 設定的自定義 `Proxy-Authorization` 頭。
proxy: {
host: "127.0.0.1",
port: 9000,
auth: : {
username: "mikeymike",
password: "rapunz3l"
}
},
// `cancelToken` 指定用于取消請求的 cancel token
// (檢視後面的 Cancellation 這節了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
1.6.8.1.11. 響應結構
axios請求的響應包含以下資訊:
{
// `data` 由伺服器提供的響應
data: {},
// `status` HTTP 狀态碼
status: 200,
// `statusText` 來自伺服器響應的 HTTP 狀态資訊
statusText: "OK",
// `headers` 伺服器響應的頭
headers: {},
// `config` 是為請求提供的配置資訊
config: {}
}
使用 then 時,會接收下面這樣的響應:
axios.get("/user/12345")
.then(function(response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
});
在使用
catch
時,或傳遞 rejection callback 作為
then
的第二個參數時,響應可以通過
error
對象可被使用。
1.6.8.1.12. 配置的預設值
你可以指定将被用在各個請求的配置預設值。
全局的 axios 預設值:
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
自定義執行個體預設值:
// 建立執行個體時設定配置的預設值
var instance = axios.create({
baseURL: 'https://api.example.com'
});
// 在執行個體已建立後修改預設值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
1.6.8.1.13. 配置的優先順序
配置會以一個優先順序進行合并。這個順序是:在 lib/defaults.js 找到的庫的預設值,然後是執行個體的 defaults 屬性,最後是請求的 config 參數。後者将優先于前者。這裡是一個例子:
// 使用由庫提供的配置的預設值來建立執行個體
// 此時逾時配置的預設值是 `0`
var instance = axios.create();
// 覆寫庫的逾時預設值
// 現在,在逾時前,所有請求都會等待 2.5 秒
instance.defaults.timeout = 2500;
// 為已知需要花費很長時間的請求覆寫逾時設定
instance.get('/longRequest', {
timeout: 5000
});
1.6.8.1.14. 攔截器
在請求或響應被 then 或 catch 處理前攔截它們。
// 添加請求攔截器
axios.interceptors.request.use(function (config) {
// 在發送請求之前做些什麼
return config;
}, function (error) {
// 對請求錯誤做些什麼
return Promise.reject(error);
});
// 添加響應攔截器
axios.interceptors.response.use(function (response) {
// 對響應資料做點什麼
return response;
}, function (error) {
// 對響應錯誤做點什麼
return Promise.reject(error);
});
如果你想在稍後移除攔截器,可以這樣:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以為自定義 axios 執行個體添加攔截器。
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
錯誤處理:
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 請求已發出,但伺服器響應的狀态碼不在 2xx 範圍内
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
可以使用 validateStatus 配置選項定義一個自定義 HTTP 狀态碼的錯誤範圍。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 狀态碼在大于或等于500時才會 reject
}
})
1.6.8.1.15. 取消
使用 cancel token 取消請求。
Axios 的 cancel token API 基于cancelable promises proposal
可以使用 CancelToken.source 工廠方法建立 cancel token,像這樣:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 處理錯誤
}
});
// 取消請求(message 參數是可選的)
source.cancel('Operation canceled by the user.');
還可以通過傳遞一個 executor 函數到 CancelToken 的構造函數來建立 cancel token:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函數接收一個 cancel 函數作為參數
cancel = c;
})
});
// 取消請求
cancel();
注意:可以使用同一個 cancel token 取消多個請求。
1.6.8.1.16. 請求時使用 application/x-www-form-urlencoded
axios 會預設序列化 JavaScript 對象為 JSON。 如果想使用 application/x-www-form-urlencoded 格式,你可以使用下面的配置。
浏覽器
在浏覽器環境,你可以使用 URLSearchParams API:
const params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
URLSearchParams 不是所有的浏覽器均支援。
除此之外,你可以使用 qs 庫來編碼資料:
const qs = require('qs');
axios.post('/foo', qs.stringify({ 'bar': 123 }));
// Or in another way (ES6),
import qs from 'qs';
const data = { 'bar': 123 };
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
1.6.8.1.17. Node.js 環境
在 node.js裡, 可以使用 querystring 子產品:
const querystring = require('querystring');
axios.post('http://something.com/', querystring.stringify({ foo: 'bar' }));
當然,同浏覽器一樣,你還可以使用 qs 庫。
1.6.8.1.17.1. Promises
axios 依賴原生的 ES6 Promise 實作而被支援。
如果你的環境不支援 ES6 Promise,你可以使用 polyfill。
1.6.8.1.17.2. TypeScript支援
axios 包含 TypeScript 的定義。
import axios from "axios";
axios.get("/user?ID=12345");
1.6.9. Vue.js Ajax(vue-resource)
Vue 要實作異步加載需要使用到 vue-resource 庫。
Vue.js 2.0 版本推薦使用 axios 來完成 ajax 請求。
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
1.6.9.1. Get 請求
以下是一個簡單的 Get 請求執行個體,請求位址是一個簡單的 txt 文本:
1.6.9.1.1. 執行個體
window.onload = function(){ var vm = new Vue({ el:'#box', data:{ msg:'Hello World!', }, methods:{ get:function(){ //發送get請求 this.$http.get('/try/ajax/ajax_info.txt').then(function(res){ document.write(res.body); },function(){ console.log('請求失敗處理'); }); } } }); }
嘗試一下 »
如果需要傳遞資料,可以使用 this.$http.get('get.php',{params : jsonData}) 格式,第二個參數 jsonData 就是傳到後端的資料。
this.$http.get('get.php',{params : {a:1,b:2}}).then(function(res){
document.write(res.body);
},function(res){
console.log(res.status);
});
1.6.9.2. post 請求
post 發送資料到後端,需要第三個參數 {emulateJSON:true}。
emulateJSON 的作用: 如果Web伺服器無法處理編碼為 application/json 的請求,你可以啟用 emulateJSON 選項。
1.6.9.2.1. 執行個體
window.onload = function(){ var vm = new Vue({ el:'#box', data:{ msg:'Hello World!', }, methods:{ post:function(){ //發送 post 請求 this.$http.post('/try/ajax/demo_test_post.php',{name:"菜鳥教程",url:"http://www.runoob.com"},{emulateJSON:true}).then(function(res){ document.write(res.body); },function(res){ console.log(res.status); }); } } }); }
嘗試一下 »
demo_test_post.php 代碼如下:
<?php
$name = isset($_POST['name']) ? htmlspecialchars($_POST['name']) : '';
$city = isset($_POST['url']) ? htmlspecialchars($_POST['url']) : '';
echo '網站名: ' . $name;
echo "\n";
echo 'URL 位址: ' .$city;
?>
1.6.9.3. 文法 & API
你可以使用全局對象方式 Vue.http 或者在一個 Vue 執行個體的内部使用 this.$http來發起 HTTP 請求。
// 基于全局Vue對象使用http
Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
// 在一個Vue執行個體内使用$http
this.$http.get('/someUrl', [options]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
vue-resource 提供了 7 種請求 API(REST 風格):
get(url, [options])
head(url, [options])
delete(url, [options])
jsonp(url, [options])
post(url, [body], [options])
put(url, [body], [options])
patch(url, [body], [options])
除了 jsonp 以外,另外 6 種的 API 名稱是标準的 HTTP 方法。
options 參數說明:
參數 | 類型 | 描述 |
---|---|---|
url | | 請求的目标URL |
body | , , | 作為請求體發送的資料 |
headers | | 作為請求頭部發送的頭部對象 |
params | | 作為URL參數的參數對象 |
method | | HTTP方法 (例如GET,POST,...) |
timeout | | 請求逾時(機關:毫秒) ( 表示永不逾時) |
before | | 在請求發送之前修改請求的回調函數 |
progress | | 用于處理上傳進度的回調函數 ProgressEvent |
credentials | | 是否需要出示用于跨站點請求的憑據 |
emulateHTTP | | 是否需要通過設定 頭部并且以傳統POST方式發送PUT,PATCH和DELETE請求。 |
emulateJSON | | 設定請求體的類型為 |
通過如下屬性和方法處理一個請求擷取到的響應對象:
屬性 | 類型 | 描述 |
---|---|---|
url | | 響應的 URL 源 |
body | , , | 響應體資料 |
headers | | 請求頭部對象 |
ok | | 當 HTTP 響應碼為 200 到 299 之間的數值時該值為 true |
status | | HTTP 響應碼 |
statusText | | HTTP 響應狀态 |
方法 | 類型 | 描述 |
text() | | 以字元串方式傳回響應體 |
json() | | 以格式化後的 json 對象方式傳回響應體 |
blob() | | 以二進制 Blob 對象方式傳回響應體 |
1.6.10. Vue.js 響應接口
Vue 可以添加資料動态響應接口。
例如以下執行個體,我們通過使用 $watch 屬性來實作資料的監聽,$watch 必須添加在 Vue 執行個體之外才能實作正确的響應。
執行個體中通過點選按鈕計數器會加 1。setTimeout 設定 10 秒後電腦的值加上 20 。
1.6.10.1. 執行個體
<div id = "app">
<p style = "font-size:25px;">計數器: {{ counter }}</p>
<button @click = "counter++" style = "font-size:25px;">點我</button>
</div>
<script type = "text/javascript">
var vm = new Vue({
el: '#app',
data: {
counter: 1
}
});
vm.$watch('counter', function(nval, oval) {
alert('計數器值的變化 :' + oval + ' 變為 ' + nval + '!');
});
setTimeout(
function(){
vm.counter += 20;
},10000
);
</script>
嘗試一下 »
Vue 不允許在已經建立的執行個體上動态添加新的根級響應式屬性。
Vue 不能檢測到對象屬性的添加或删除,最好的方式就是在初始化執行個體前聲明根級響應式屬性,哪怕隻是一個空值。
如果我們需要在運作過程中實作屬性的添加或删除,則可以使用全局 Vue,Vue.set 和 Vue.delete 方法。
1.6.10.2. Vue.set
Vue.set 方法用于設定對象的屬性,它可以解決 Vue 無法檢測添加屬性的限制,文法格式如下:
Vue.set( target, key, value )
參數說明:
- target: 可以是對象或數組
- key : 可以是字元串或數字
- value: 可以是任何類型
1.6.10.3. 執行個體
<div id = "app">
<p style = "font-size:25px;">計數器: {{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">點我</button>
</div>
<script type = "text/javascript">
var myproduct = {"id":1, name:"book", "price":"20.00"};
var vm = new Vue({
el: '#app',
data: {
counter: 1,
products: myproduct
}
});
vm.products.qty = "1";
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('計數器值的變化 :' + oval + ' 變為 ' + nval + '!');
});
</script>
在以上執行個體中,使用以下代碼在開始時建立了一個變量 myproduct:
var myproduct = {"id":1, name:"book", "price":"20.00"};
該變量在指派給了 Vue 執行個體的 data 對象:
var vm = new Vue({ el: '#app', data: { counter: 1, products: myproduct } });
如果我們想給 myproduct 數組添加一個或多個屬性,我們可以在 Vue 執行個體建立後使用以下代碼:
檢視控制台輸出:
如上圖看到的,在産品中添加了數量屬性 qty,但是 get/set 方法隻可用于 id,name 和 price 屬性,卻不能在 qty 屬性中使用。
我們不能通過添加 Vue 對象來實作響應。 Vue 主要在開始時建立所有屬性。 如果我們要實作這個功能,可以通過 Vue.set 來實作:
1.6.10.4. 執行個體
<div id = "app">
<p style = "font-size:25px;">計數器: {{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">點我</button>
</div>
<script type = "text/javascript">
var myproduct = {"id":1, name:"book", "price":"20.00"};
var vm = new Vue({
el: '#app',
data: {
counter: 1,
products: myproduct
}
});
Vue.set(myproduct, 'qty', 1);
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('計數器值的變化 :' + ovg](vue_res/+ ' 變為 ' + nval + '!');
});
</script>
從控制台輸出的結果可以看出 get/set 方法可用于qty 屬性。
1.6.10.5. Vue.delete
Vue.delete 用于删除動态添加的屬性 文法格式:
Vue.delete( target, key )
參數說明:
- target: 可以是對象或數組
- key : 可以是字元串或數字
1.6.10.6. 執行個體
<div id = "app">
<p style = "font-size:25px;">計數器: {{ products.id }}</p>
<button @click = "products.id++" style = "font-size:25px;">點我</button>
</div>
<script type = "text/javascript">
var myproduct = {"id":1, name:"book", "price":"20.00"};
var vm = new Vue({
el: '#app',
data: {
counter: 1,
products: myproduct
}
});
Vue.delete(myproduct, 'price');
console.log(vm);
vm.$watch('counter', function(nval, oval) {
alert('計數器值的變化 :' + oval + ' 變為 ' + nval + '!');
});
</scriptg](vue_res/```
以上執行個體中我們使用 Vue.delete 來删除 price 屬性。以下是控制台輸出結果:

從上圖輸出結果中,我們可以看到 price 屬性已删除,隻剩下了 id 和 name 屬性,price 屬性的 get/set 方法也已删除。
### Vue.js 執行個體
本章節為大家介紹幾個 Vue.js 執行個體,通過執行個體練習來鞏固學到的知識點。
#### 導航菜單執行個體
##### 導航菜單
建立一個簡單的導航菜單:
<!-- 激活的菜單樣式為 active 類 -->
<!-- 為了阻止連結在點選時跳轉,我們使用了 "prevent" 修飾符 (preventDefault 的簡稱)。 -->
<nav v-bind:class="active" v-on:click.prevent>
<!-- 當菜單上的連結被點選時,我們調用了 makeActive 方法, 該方法在 Vue 執行個體中建立。 -->
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" class="home" v-on:click="makeActive('home')">Home</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" class="projects" v-on:click="makeActive('projects')">Projects</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" class="services" v-on:click="makeActive('services')">Services</a>
<a href="#" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" class="contact" v-on:click="makeActive('contact')">Contact</a>
</nav>
<!-- 以下 "active" 變量會根據目前選中的值來自動變換 -->
<p>您選擇了 <b>{{active}} 菜單</b></p>
<script> // 建立一個新的 Vue 執行個體 var demo = new Vue({ // DOM 元素,挂載視圖模型 el: '#main', // 定義屬性,并設定初始值 data: { active: 'home' }, // 點選菜單使用的函數 methods: { makeActive: function(item){ // 模型改變,視圖會自動更新 this.active = item; } } }); </script>
#### 編輯文本執行個體
##### 文本編輯
點選指定文本編輯内容:
<!-- 這是一個提示框
v-on:click.stop 是一個點選事件處理器,stop 修飾符用于阻止事件傳遞
v-if 用來判斷 show_tooltip 為 true 時才顯示 -->
<div class="tooltip" v-on:click.stop v-if="show_tooltip">
<!-- v-model 綁定了文本域的内容
在文本域内容改變時,對應的變量也會實時改變 -->
<input type="text" v-model="text_content" />
</div>
<!-- 點選後調用 "toggleTooltip" 方法并阻止事件傳遞 -->
<!-- "text_content" 變量根據文本域内容的變化而變化 -->
<p v-on:click.stop="toggleTooltip">{{text_content}}</p>
<script> var demo = new Vue({ el: '#main', data: { show_tooltip: false, text_content: '點我,并編輯内容。' }, methods: { hideTooltip: function(){ // 在模型改變時,視圖也會自動更新 this.show_tooltip = false; }, toggleTooltip: function(){ this.show_tooltip = !this.show_tooltip; } } }) </script>
#### 訂單清單執行個體
##### 訂單清單
建立一個訂單清單,并計算總價:
<h1>Services</h1>
<ul>
<!-- 循環輸出 services 數組, 設定選項點選後的樣式 -->
<li v-for="service in services" v-on:click="toggleActive(service)" v-bind:class="{ 'active': service.active}">
<!-- 顯示訂單中的服務名,價格
Vue.js 定義了貨币過濾器,用于格式化價格 -->
{{service.name}} <span>{{service.price | currency}}</span>
</li>
</ul>
<div class="total">
<!-- 計算所有服務的價格,并格式化貨币 -->
Total: <span>{{total() | currency}}</span>
</div>
<script>
// 自定義過濾器 "currency". Vue.filter('currency', function (value) { return '$' + value.toFixed(2); });
var demo = new Vue({ el: '#main', data: { // 定義模型屬性 the model properties. The view will loop // 視圖将循環輸出數組的資料 services: [ { name: 'Web Development', price: 300, active:true },{ name: 'Design', price: 400, active:false },{ name: 'Integration', price: 250, active:false },{ name: 'Training', price: 220, active:false } ] }, methods: { toggleActive: function(s){ s.active = !s.active; }, total: function(){
var total = 0;
this.services.forEach(function(s){
if (s.active){
total+= s.price;
}
});
return total;
}
}
}); </script>
#### 搜尋頁面執行個體
##### 搜尋頁面
在輸入框輸入搜尋内容,清單顯示配置的清單:
<div class="bar">
<!-- searchString 模型與文本域建立綁定 -->
<input type="text" v-model="searchString" placeholder="輸入搜尋内容" />
<ul>
<!-- 循環輸出資料 -->
<li v-for="article in filteredArticles">
<a v-bind:href="article.url" target="_blank" rel="external nofollow" ><img v-bind:src="article.image" /></a>
<p>{{article.title}}</p>
</li>
<script>
var demo = new Vue({ el: '#main', data: { searchString: "",
// 資料模型,實際環境你可以根據 Ajax 來擷取
articles: [
{
"title": "What You Need To Know About CSS Variables",
"url": "https://www.runoob.com/css/css-tutorial.html",
"image": "https://static.runoob.com/images/icon/css.png"
},
{
"title": "Freebie: 4 Great Looking Pricing Tables",
"url": "https://www.runoob.com/html/html-tutorial.html",
"image": "https://static.runoob.com/images/icon/html.png"
},
{
"title": "20 Interesting JavaScript and CSS Libraries for February 2016",
"url": "https://www.runoob.com/css3/css3-tutorial.html",
"image": "https://static.runoob.com/images/icon/css3.png"
},
{
"title": "Quick Tip: The Easiest Way To Make Responsive Headers",
"url": "https://www.runoob.com/css3/css3-tutorial.html",
"image": "https://static.runoob.com/images/icon/css3.png"
},
{
"title": "Learn SQL In 20 Minutes",
"url": "https://www.runoob.com/sql/sql-tutorial.html",
"image": "https://static.runoob.com/images/icon/sql.png"
},
{
"title": "Creating Your First Desktop App With HTML, JS and Electron",
"url": "https://www.runoob.com/js/js-tutorial.html",
"image": "https://static.runoob.com/images/icon/html.png"
}
]
},
computed: {
// 計算數學,比對搜尋
filteredArticles: function () {
var articles_array = this.articles,
searchString = this.searchString;
if(!searchString){
return articles_array;
}
searchString = searchString.trim().toLowerCase();
articles_array = articles_array.filter(function(item){
if(item.title.toLowerCase().indexOf(searchString) !== -1){
return item;
}
})
// 傳回過來後的數組
return articles_array;;
}
}
});
</script>
#### 切換不同布局執行個體
##### 切換不同布局
點選右上角的按鈕來切換不同頁面布局:
<div class="bar">
<!-- 兩個按鈕用于切換不同的清單布局 -->
<a class="list-icon" v-bind:class="{ 'active': layout == 'list'}" v-on:click="layout = 'list'"></a>
<a class="grid-icon" v-bind:class="{ 'active': layout == 'grid'}" v-on:click="layout = 'grid'"></a>
</div>
<!-- 我們設定了兩套布局頁面。使用哪套依賴于 "layout" 綁定 -->
<ul v-if="layout == 'grid'" class="grid">
<!-- 使用大圖,沒有文本 -->
<li v-for="a in articles">
<a v-bind:href="a.url" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank"><img v-bind:src="a.image.large" /></a>
</li>
</ul>
<ul v-if="layout == 'list'" class="list">
<!-- 使用小圖及标題 -->
<li v-for="a in articles">
<a v-bind:href="a.url" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank"><img v-bind:src="a.image.small" /></a>
<p>{{a.title}}</p>
</li>
</ul>
</form>
<script> <script> var demo = new Vue({ el: '#main', data: { // 視圖模型,可能的值是 "grid" 或 "list"。 layout: 'grid', articles: [{ "title": "HTML 教程", "url": " https://www.runoob.com/html/html-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/htmlbig.png", "small": " https://static.runoob.com/images/icon/html.png" } }, { "title": "CSS 教程", "url": " https://www.runoob.com/css/css-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/cssbig.png", "small": " https://static.runoob.com/images/icon/css.png" } }, { "title": "JS 教程", "url": " https://www.runoob.com/js/js-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/jsbig.jpeg", "small": " https://static.runoob.com/images/icon/js.png" } }, { "title": "SQL 教程", "url": " https://www.runoob.com/sql/sql-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/sqlbig.png", "small": " https://static.runoob.com/images/icon/sql.png" } }, { "title": "Ajax 教程", "url": " https://www.runoob.com/ajax/ajax-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/ajaxbig.png", "small": " https://static.runoob.com/images/icon/ajax.png" } }, { "title": "Python 教程", "url": " https://www.runoob.com/pyhton/pyhton-tutorial.html", "image": { "large": " https://static.runoob.com/images/mix/pythonbig.png", "small": " https://static.runoob.com/images/icon/python.png" } }] } }); </script>
### 1). el
指定dom标簽容器的選擇器 Vue就會管理對應的标簽及其子标簽
### 2). data
對象或函數類型 指定初始化狀态屬性資料的對象 vm也會自動擁有data中所有屬性 頁面中可以直接通路使用 資料代理: 由vm對象來代理對data中所有屬性的操作(讀/寫)
### 3). methods
包含多個方法的對象 供頁面中的事件指令來綁定回調 回調函數預設有event參數, 但也可以指定自己的參數 所有的方法由vue對象來調用, 通路data中的屬性直接使用this.xxx
### 4). computed
包含多個方法的對象 對狀态屬性進行計算傳回一個新的資料, 供頁面擷取顯示 一般情況下是相當于是一個隻讀的屬性 利用set/get方法來實作屬性資料的計算讀取, 同時監視屬性資料的變化 如何給對象定義get/set屬性 在建立對象時指定: get name () {return xxx} / set name (value) {} 對象建立之後指定: Object.defineProperty(obj, age, {get(){}, set(value){}})
### 5). watch
包含多個屬性監視的對象 分為一般監視和深度監視 xxx: function(value){} xxx : { deep : true, handler : fun(value) } 另一種添加監視方式: vm.$watch('xxx', function(value){})
## 4. 過渡動畫
```vue
<div id = "databinding">
<button v-on:click = "show = !show">點我</button>
<transition name = "fade">
<p v-show = "show" v-bind:style = "styleobj">動畫執行個體</p>
</transition>
</div>
<script type = "text/javascript">
var vm = new Vue({
el: '#databinding',
data: {
show:true,
styleobj :{
fontSize:'30px',
color:'red'
}
},
methods : {
}
});
</script>
利用vue去操控css的transition/animation動畫
模闆: 使用<transition name='xxx'>包含帶動畫的标簽
css樣式
.fade-enter-active: 進入過程, 指定進入的transition
.fade-leave-active: 離開過程, 指定離開的transition
.xxx-enter, .xxx-leave-to: 指定隐藏的樣式
編碼例子
.xxx-enter-active, .xxx-leave-active {
transition: opacity .5s
}
.xxx-enter, .xxx-leave-to {
opacity: 0
}
<transition name="xxx">
<p v-if="show">hello</p>
</transition>
1.7. 生命周期
vm/元件對象
生命周期圖
主要的生命周期函數(鈎子)
created() / mounted(): 啟動異步任務(啟動定時器,發送ajax請求, 綁定監聽)
beforeDestroy(): 做一些收尾的工作
1.8. 自定義過濾器
1.8.1. 了解
對需要顯示的資料進行格式化後再顯示
1.8.2. 編碼
1). 定義過濾器
Vue.filter(filterName, function(value[,arg1,arg2,...]){
// 進行一定的資料處理
return newValue
})
2). 使用過濾器
<div>{{myData | filterName}}</div>
<div>{{myData | filterName(arg)}}</div>
1.9. vue内置指令
v-text/v-html: 指定标簽體
* v-text : 當作純文字
* v-html : 将value作為html标簽來解析
v-if v-else v-show: 顯示/隐藏元素
* v-if : 如果vlaue為true, 目前标簽會輸出在頁面中
* v-else : 與v-if一起使用, 如果value為false, 将目前标簽輸出到頁面中
* v-show: 就會在标簽中添加display樣式, 如果vlaue為true, display=block, 否則是none
v-for : 周遊
* 周遊數組 : v-for="(person, index) in persons"
* 周遊對象 : v-for="value in person" $key
v-on : 綁定事件監聽
* v-on:事件名, 可以縮寫為: @事件名
* 監視具體的按鍵: @keyup.keyCode @keyup.enter
* 停止事件的冒泡和阻止事件預設行為: @click.stop @click.prevent
* 隐含對象: $event
v-bind : 強制綁定解析表達式
* html标簽屬性是不支援表達式的, 就可以使用v-bind
* 可以縮寫為: :id='name'
* :class
* :class="a"
* :class="{classA : isA, classB : isB}"
* :class="[classA, classB]"
* :style
:style="{color : color}"
v-model
* 雙向資料綁定
* 自動收集使用者輸入資料
ref : 辨別某個标簽
* ref='xxx'
* 讀取得到标簽對象: this.$refs.xxx
1.10. 自定義指令
1.10.1. 1). 注冊全局指令
Vue.directive('my-directive', function(el, binding){
el.innerHTML = binding.value.toUpperCase()
})
1.10.2. 2). 注冊局部指令
directives : {
'my-directive' : function(el, binding) {
el.innerHTML = binding.value.toUpperCase()
}
}
1.10.3. 3). 使用指令
<div v-my-directive='xxx'>
1.11. 9.實作一個腳手架(vue-cli)建立的一個簡單 to do list 執行個體。
完整項目下載下傳:
Download
下載下傳後進入項目目錄執行 npm install 指令導入依賴子產品。
g](vue_res/下指令啟動項目:
npm run dev
此項目端口号設為 6060。
項目目錄結構:
src/App.vue 檔案代碼:
<template>
<div id="app">
<h1 v-html = "title"></h1>
<input v-model="newItem" v-on:keyup.enter="addNew" ></input>
<ul>
<li v-for="item in items" v-bind:class="{finished:item.isFinished}" v-on:click="toggleFinish(item)">{{item.label}}</li>
</ul>
</div>
</template>
<script>
import Store from './store'
export default {
data:function(){
return {
title:"This is a Todolist",
items:Store.fetch(),
newItem:""
}
},
watch:{
items:{
handler:function(items){
Store.save(items)
},
deep:true
}
},
methods:{
toggleFinish:function(item){
item.isFinished = !item.isFinished
},
addNew:function(){
this.items.push({
label:this.newItem,
"isFinished":false
})
this.newItem=""
}
}
}
</script>
<style>
.finished{
text-decoration:line-through;
}
li{
list-style:none;
font-size:1.6em;
margin-top:10px;
}
#app {
background-image:url(./576df1167c887_1024.jpg);
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
input{
width:230px;
height:40px;
border-radius:20px;
padding: 0.4em 0.35em;
border:3px solid #CFCFCF;
font-size: 1.55em;
}
</style>
src/store.js 實作存儲,即重新整理資料不消失:
const STORAGE_KEY='todos-vuejs'
export default {
fetch:function(){
return JSON.parse(window.localStorage.getItem(STORAGE_KEY)||'[]');
},
save:function(items){
window.localStorage.setItem(STORAGE_KEY,JSON.stringify(items))
}
}
2. vuex是什麼
2.1. 1.vuex
github站點: https://github.com/vuejs/vuex
線上文檔: https://vuex.vuejs.org/zh-cn/
簡單來說: 對應用中元件的狀态進行集中式的管理(讀/寫)
2.2. 狀态自管理應用
state: 驅動應用的資料源
view: 以聲明方式将state映射到視圖
actions: 響應在view上的使用者輸入導緻的狀态變化(包含n個更新狀态的方法)
2.3. 多元件共享狀态的問題
多個視圖依賴于同一狀态
來自不同視圖的行為需要變更同一狀态
以前的解決辦法
* 将資料以及操作資料的行為都定義在父元件
* 将資料以及操作資料的行為傳遞給需要的各個子元件(有可能需要多級傳遞)
vuex就是用來解決這個問題的
2.4. vuex的核心概念
2.4.1. state
vuex管理的狀态對象
它應該是唯一的
const state = {
xxx: initValue
}
2.4.2. mutations
包含多個直接更新state的方法(回調函數)的對象
誰來觸發: action中的commit('mutation名稱')
隻能包含同步的代碼, 不能寫異步代碼
const mutations = {
yyy (state, data) {
// 更新state的某個屬性
}
}
2.4.3. actions
包含多個事件回調函數的對象
通過執行: commit()來觸發mutation的調用, 間接更新state
誰來觸發: 元件中: $store.dispatch('action名稱') // 'zzz'
可以包含異步代碼(定時器, ajax)
const actions = {
zzz ({commit, state}, data1) {
commit('yyy', data2)
}
}
2.4.4. getters
包含多個計算屬性(get)的對象
誰來讀取: 元件中: $store.getters.xxx
const getters = {
mmm (state) {
return ...
}
}
2.4.5. modules
包含多個module
一個module是一個store的配置對象
與一個元件(包含有共享資料)對應
2.4.6. 向外暴露store對象
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
2.4.7. 元件中:
import {mapGetters, mapActions} from 'vuex'
export default {
computed: mapGetters(['mmm'])
methods: mapActions(['zzz'])
}
{{mmm}} @click="zzz(data)"
2.4.8. 映射store
import store from './store'
new Vue({
store
})
2.4.9. store對象
1.所有用vuex管理的元件中都多了一個屬性$store, 它就是一個store對象
2.屬性:
state: 注冊的state對象
getters: 注冊的getters對象
3.方法:
dispatch(actionName, data): 分發action
2.5. 将vuex引到項目中
2.5.1. 下載下傳: npm install vuex --save
2.5.2. 使用vuex
1.store.js
import Vuex from 'vuex'
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules
})
2.main.js
import store from './store.js'
new Vue({
store
})
3. VueSource準備
3.1. vueSource
1.[].slice.call(lis): 将僞數組轉換為真數組
2.node.nodeType: 得到節點類型
3.Object.defineProperty(obj, propertyName, {}): 給對象添加/修改屬性(指定描述符)
configurable: true/false 是否可以重新define
enumerable: true/false 是否可以枚舉(for..in / keys())
value: 指定初始值
writable: true/false value是否可以修改存取(通路)描述符
get: 函數, 用來得到目前屬性值
set: 函數, 用來監視目前屬性值的變化
4.Object.keys(obj): 得到對象自身可枚舉的屬性名的數組
5.DocumentFragment: 文檔碎片(高效批量更新多個節點)
6.obj.hasOwnProperty(prop): 判斷prop是否是obj自身的屬性
3.2. 資料代理(MVVM.js)
1.通過一個對象代理對另一個對象中屬性的操作(讀/寫)
2.通過vm對象來代理data對象中所有屬性的操作
3.好處: 更友善的操作data中的資料
4.基本實作流程
1). 通過Object.defineProperty()給vm添加與data對象的屬性對應的屬性描述符
2). 所有添加的屬性都包含getter/setter
3). 在getter/setter内部去操作data中對應的屬性資料
3.3. 模闆解析(compile.js)
1.模闆解析的關鍵對象: compile對象
2.模闆解析的基本流程:
1). 将el的所有子節點取出, 添加到一個建立的文檔fragment對象中
2). 對fragment中的所有層次子節點遞歸進行編譯解析處理
* 對表達式文本節點進行解析
* 對元素節點的指令屬性進行解析
* 事件指令解析
* 一般指令解析
3). 将解析後的fragment添加到el中顯示
3.解析表達式文本節點: textNode.textContent = value
1). 根據正則對象得到比對出的表達式字元串: 子比對/RegExp.$1
2). 從data中取出表達式對應的屬性值
3). 将屬性值設定為文本節點的textContent
4.事件指令解析: elementNode.addEventListener(事件名, 回調函數.bind(vm))
v-on:click="test"
1). 從指令名中取出事件名
2). 根據指令的值(表達式)從methods中得到對應的事件處理函數對象
3). 給目前元素節點綁定指定事件名和回調函數的dom事件監聽
4). 指令解析完後, 移除此指令屬性
5.一般指令解析: elementNode.xxx = value
1). 得到指令名和指令值(表達式)
2). 從data中根據表達式得到對應的值
3). 根據指令名确定需要操作元素節點的什麼屬性
* v-text---textContent屬性
* v-html---innerHTML屬性
* v-class--className屬性
4). 将得到的表達式的值設定到對應的屬性上
5). 移除元素的指令屬性
3.4. 資料劫持-->資料綁定
<div id="app">
<ul v-for="value in object">
<label>
{{ value[0] }}
</label>
<input type="text" :placeholder="value[1]">
</ul>
</div>
<script>
new Vue({
el: '#app',
data: {
object: {
"HeartBeatTime": [
"心跳周期時長",
"11",
"分鐘"
],
"RetransmissionCounts": [
"重傳次數",
"22",
"次"
],
"SearchNetTime": [
"搜網周期時長",
"33",
"分鐘"
]
}
}
})
</script>
</body>
</html>
1.資料綁定(model==>View):
1). 一旦更新了data中的某個屬性資料, 所有界面上直接使用或間接使用了此屬性的節點都會更新(更新)
2.資料劫持
1). 資料劫持是vue中用來實作資料綁定的一種技術
2). 基本思想: 通過defineProperty()來監視data中所有屬性(任意層次)資料的變化, 一旦變化就去更新界面
3.四個重要對象
1). Observer
* 用來對data所有屬性資料進行劫持的構造函數
* 給data中所有屬性重新定義屬性描述(get/set)
* 為data中的每個屬性建立對應的dep對象
2). Dep(Depend)
* data中的每個屬性(所有層次)都對應一個dep對象
* 建立的時機:
* 在初始化define data中各個屬性時建立對應的dep對象
* 在data中的某個屬性值被設定為新的對象時
* 對象的結構
{
id, // 每個dep都有一個唯一的id
subs //包含n個對應watcher的數組(subscribes的簡寫)
}
* subs屬性說明
* 當一個watcher被建立時, 内部會将目前watcher對象添加到對應的dep對象的subs中
* 當此data屬性的值發生改變時, 所有subs中的watcher都會收到更新的通知, 進而最終更新對應的界面
3). Compile
* 用來解析模闆頁面的對象的構造函數(一個執行個體)
* 利用compile對象解析模闆頁面
* 每解析一個表達式(非事件指令)都會建立一個對應的watcher對象, 并建立watcher與dep的關系
* complie與watcher關系: 一對多的關系
4). Watcher
* 模闆中每個非事件指令或表達式都對應一個watcher對象
* 監視目前表達式資料的變化
* 建立的時機: 在初始化編譯模闆時
* 對象的組成
{
vm, //vm對象
exp, //對應指令的表達式
cb, //當表達式所對應的資料發生改變的回調函數
value, //表達式目前的值
depIds //表達式中各級屬性所對應的dep對象的集合對象
//屬性名為dep的id, 屬性值為dep
}
5). 總結: dep與watcher的關系: 多對多
* 一個data中的屬性對應對應一個dep, 一個dep中可能包含多個watcher(模闆中有幾個表達式使用到了屬性)
* 模闆中一個非事件表達式對應一個watcher, 一個watcher中可能包含多個dep(表達式中包含了幾個data屬性)
* 資料綁定使用到2個核心技術
* defineProperty()
* 消息訂閱與釋出
4.雙向資料綁定
1). 雙向資料綁定是建立在單向資料綁定(model==>View)的基礎之上的
2). 雙向資料綁定的實作流程:
* 在解析v-model指令時, 給目前元素添加input監聽
* 當input的value發生改變時, 将最新的值指派給目前表達式所對應的data屬性
4. vue腳手架
4.1. vue-cli
用來建立vue項目的工具包
建立項目:
npm install -g vue-cli
vue init webpack VueDemo
開發環境運作:
cd VueDemo
npm install
npm run dev
生産環境打包釋出
npm run build
npm install -g serve
serve dist
http://localhost:5000
4.2. eslint
用來做項目編碼規範檢查的工具
基本原理: 定義了很多規則, 檢查項目的代碼一旦發現違背了某個規則就輸出相應的提示資訊
有相應的配置, 可定制檢查
4.3. 元件化程式設計
vue檔案包含3個部分
<template>
<div></div>
</template>
<script>
export default {
props: []/{}
data(){},
computed: {}
methods: {},
watch: {}
filters: {}
directives: {}
components: {}
}
</script>
<style>
</style>
元件化編碼的基本流程
1). 拆分界面, 抽取元件
2). 編寫靜态元件
3). 編寫動态元件
初始化資料, 動态顯示初始化界面
實作與使用者互動功能
元件通信的5種方式
props
vue的自定義事件
pubsub第三方庫
slot
vuex(後面單獨講)
props:
父子元件間通信的基本方式
屬性值的2大類型:
一般: 父元件-->子元件
函數: 子元件-->父元件
隔層元件間傳遞: 必須逐層傳遞(麻煩)
兄弟元件間: 必須借助父元件(麻煩)
vue自定義事件
子元件與父元件的通信方式
用來取代function props
不适合隔層元件和兄弟元件間的通信
pubsub第三方庫(消息訂閱與釋出)
适合于任何關系的元件間通信
slot
通信是帶資料的标簽
注意: 标簽是在父元件中解析
vuex
多元件共享狀态(資料的管理)
元件間的關系也沒有限制
功能比pubsub強大, 更适用于vue項目
4.4. ajax
相關庫:
vue-resource: vue插件, 多用于vue1.x
axios: 第三方庫, 多用于vue2.x
vue-resource使用
// 引入子產品
import VueResource from 'vue-resource'
// 使用插件
Vue.use(VueResource)
// 通過vue/元件對象發送ajax請求
this.$http.get('/someUrl').then((response) => {
// success callback
console.log(response.data) //傳回結果資料
}, (response) => {
// error callback
console.log(response.statusText) //錯誤資訊
})
axios使用
// 引入子產品
import axios from 'axios'
// 發送ajax請求
axios.get(url)
.then(response => {
console.log(response.data) // 得到傳回結果資料
})
.catch(error => {
console.log(error.message)
})
4.5. vue-router
vue用來實作SPA的插件
使用vue-router
1. 建立路由器: router/index.js
new VueRouter({
routes: [
{ // 一般路由
path: '/about',
component: about
},
{ // 自動跳轉路由
path: '/',
redirect: '/about'
}
]
})
2. 注冊路由器: main.js
import router from './router'
new Vue({
router
})
3. 使用路由元件标簽:
<router-link to="/xxx">Go to XXX</router-link>
<router-view></router-view>
編寫路由的3步
1. 定義路由元件
2. 映射路由
3. 編寫路由2個标簽
嵌套路由
children: [
{
path: '/home/news',
component: news
},
{
path: 'message',
component: message
}
]
向路由元件傳遞資料
params: <router-link to="/home/news/abc/123">
props: <router-view msg='abc'>
緩存路由元件
<keep-alive>
<router-view></router-view>
</keep-alive>
路由的程式設計式導航
this.$router.push(path): 相當于點選路由連結(可以傳回到目前路由界面)
this.$router.replace(path): 用新路由替換目前路由(不可以傳回到目前路由界面)
this.$router.back(): 請求(傳回)上一個記錄路由