
學(xué)習(xí)測(cè)試環(huán)境可通過(guò) CDN 地址引入 Vue(項(xiàng)目開(kāi)發(fā)和線上環(huán)境一般使用 vue-cli、webpack 打包)
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
可使用構(gòu)造函數(shù)創(chuàng)建 Vue 實(shí)例,即應(yīng)用的入口:
<div id="app">
{{msg}}
</div>
<script>
let app = new Vue({
el: '#app', // 指定頁(yè)面中存在的 DOM 元素掛載
data: { // 聲明需要雙向綁定的數(shù)據(jù)(渲染到頁(yè)面上)
msg: 'Hello World!'
}
})
console.log(app.$el) // 訪問(wèn) Vue 實(shí)例中的屬性
console.log(app.msg) // 訪問(wèn) Vue 實(shí)例 data 域中的屬性
</script>
與 jQuery 對(duì)比
使用 jQuery 實(shí)現(xiàn) todo-list:
<div>
<ul id="ul-list"></ul>
</div>
<script type="text/javascript">
var $txtTitle = $('#txt-title')
$('#btn-submit').click(function () {
var title = $txtTitle.val()
if (!title)
return
var $li = $('<li>' + title + '</li>')
$('#ul-list').append($li)
$txtTitle.val('')
})
</script>
使用 Vue 實(shí)現(xiàn) todo-list:
<div id="app">
<div>
<input v-model="title">
<button v-on:click="add">submit</button>
</div>
<div>
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
</div>
</div>
<script type="text/javascript">
var data = {
title: '',
list: []
}
new Vue({
el: '#app',
data: data,
methods: {
add: function () {
this.list.push(this.title)
this.title = ''
}
}
})
</script>
- 區(qū)別在于:jQuery 以選擇器獲取并修改 DOM,Vue 以數(shù)據(jù)與 DOM 元素綁定、DOM 響應(yīng)數(shù)據(jù)變化;
- 即數(shù)據(jù)和視圖分離(開(kāi)放封閉原則)、以數(shù)據(jù)驅(qū)動(dòng)視圖(DOM 操作被封裝)。
生命周期
一些生命周期鉤子:
- created:實(shí)例創(chuàng)建完成后調(diào)用,完成了數(shù)據(jù)的觀測(cè)等而尚未掛載(
$el還不可用)需要初始化處理一些數(shù)據(jù)時(shí)會(huì)用到; - mounted:el掛載到實(shí)例上后調(diào)用,一般第一個(gè)業(yè)務(wù)邏輯會(huì)在這里開(kāi)始。相當(dāng)于
$(document).ready(); - beforeDestroy:實(shí)例銷(xiāo)毀之前調(diào)用。主要解綁一些使用
addEventListener監(jiān)聽(tīng)的事件等; - ...
文本插值,表達(dá)式
使用雙大括號(hào)( Mustache 語(yǔ)法){{value}}是最基本的文本插值方法,可以將雙向綁定的數(shù)據(jù)實(shí)時(shí)顯示,還可以使用單行 JS 表達(dá)式:
{{1 + 1}}
{{6 > 5? msg1: msg2}}
{{var a = 6}} // 錯(cuò)誤,這是多行表達(dá)式
{{if(6 > 3){}}}
實(shí)例:自動(dòng)刷新的計(jì)時(shí)器
<div id="dateApp">
{{date}}
</div>
<script>
let app = new Vue({
el: '#dateApp',
data: {
date: new Date()
},
mounted: function() {
let _this = this; // this 表示 Vue 實(shí)例
this.timer = setInterval(
() => {
_this.date = new Date(); // 每秒刷新1次
}, 1000
)
},
beforeDestroy: function() {
if (this.timer) {
clearInterval(this.timer) // 如定時(shí)器存在即銷(xiāo)毀
}
}
})
</script>
過(guò)濾器
在 {{}} 插值的尾部添加一或多個(gè)管道符 | 可對(duì)數(shù)據(jù)進(jìn)行過(guò)濾,常用于格式化文本(字母全部大寫(xiě)、貨幣千位使用逗號(hào)分隔等):
以剛才的計(jì)時(shí)器為例
{{date | formatDate}}
在 Vue 實(shí)例中定義過(guò)濾器函數(shù):
let plusDate = function(value) {
return value < 10? '0' + value: value
}
let app = new Vue({
el: '#dateApp',
data: {
date: new Date()
},
filters: {
formatDate: function(value) {
let date = new Date(value); // 將字符串轉(zhuǎn)換為date類(lèi)型
let year = date.getFullYear();
let month = plusDate(date.getMonth() + 1);
let day = plusDate(date.getDate());
return `{year}-{month}-{day}`
}
}
過(guò)濾器中也可以傳參數(shù),如 {{date | formatDate(66,99)}} 中 formatDate 的第一個(gè)和第二個(gè)參數(shù),分別對(duì)應(yīng)過(guò)濾器函數(shù)的第二個(gè)和
第三個(gè)參數(shù)(第一個(gè)參數(shù)為 date)
計(jì)算屬性
- 在一個(gè)計(jì)算屬性里可以完成復(fù)雜的邏輯(運(yùn)算、函數(shù)調(diào)用),最終返回一個(gè)結(jié)果;
- 計(jì)算屬性還可以依賴(lài)多個(gè) Vue 實(shí)例的數(shù)據(jù),只要其中任一數(shù)據(jù)變化,計(jì)算屬性就會(huì)重新執(zhí)行并更新視圖;
- 可以為計(jì)算屬性(默認(rèn)為 getter )定義 getter 和 setter 方法對(duì)屬性進(jìn)行讀寫(xiě);
- 緩存: 不管渲染不渲染,只要計(jì)算屬性依賴(lài)的數(shù)據(jù)未發(fā)生變化,就永遠(yuǎn)不變(使用計(jì)算屬性還是
methods取決于是否需要緩存,當(dāng)遍歷大數(shù)組和做大量計(jì)算時(shí)應(yīng)當(dāng)使用計(jì)算屬性做緩存)。
實(shí)例:計(jì)算購(gòu)物車(chē)總價(jià)
<div id='app'>
{{price}}
</div>
<script>
let app = new Vue({
el: '#app',
data: {
package1: [
{name: 'x', price: 6999, count: 2},
{name: 'y', price: 7999, count: 3}
],
package2: [
{name: 'x', price: 2999, count: 5},
{name: 'y', price: 3999, count: 6}
]
},
computed: {
price: function() {
let price = 0
for (let i = 0; i < this.package1.length; i++) {
price += this.package1[i].price * this.package1[i].count;
}
for (let j = 0; j < this.package2.length; j++) {
price += this.package2[j].price * this.package2[j].count;
}
return price
}
// 計(jì)算屬性直接跟一個(gè) function,默認(rèn)是 getter 方法,等價(jià)于
/**
price: {
get: function() {
...
}
}
*/
// 也可以定義計(jì)算屬性的 setter 方法,在外部可以調(diào)用:app.price = 'xxx'
/**
price: {
set: function() {
...
}
}
*/
}
})
</script>
監(jiān)聽(tīng)屬性變化
除了使用計(jì)算屬性 computed 以外,還可以使用 watch 監(jiān)聽(tīng)單個(gè)屬性的變化,兩者對(duì)比:
computed:
<div id="app">
firstName: <input type="text" v-model="firstName">
lastName: <input type="text" v-model="lastName">
<br>
{{ fullName }}
</div>
<script>
let app = new Vue({
el: "#app",
data: {
firstName: "",
lastName: ""
},
computed: {
fullName() {
return `${this.firstName} ${this.lastName}`
}
}
})
</script>
watch:
<div id="app">
firstName: <input type="text" v-model="firstName">
lastName: <input type="text" v-model="lastName">
<br>
{{ fullName }}
</div>
<script>
let app = new Vue({
el: "#app",
data: {
firstName: "",
lastName: "",
fullName: ""
},
watch: {
firstName(val) {
this.fullName = `${val} ${this.lastName}`
},
lastName(val) {
this.fullName = `${this.firstName} ${val}`
}
}
})
</script>
基本指令
指令是 Vue 模板中最常用的一項(xiàng)功能,在 HTML 元素中帶有前綴 v- 表示,有助于快速完成 DOM 操作,最常用的幾個(gè)指令:
-
v--text:解析文本,和{{ }}作用一樣 -
v--html:解析html元素 -
v--bind:動(dòng)態(tài)更新元素上的屬性,如 id、class 等,當(dāng)數(shù)據(jù)變化時(shí)就會(huì)重新渲染。 -
v--on:綁定事件監(jiān)聽(tīng)器
<div v-bind:class='className'></div>
<button v-on:dbclick='count'></button>
語(yǔ)法糖:指在不影響功能的情況下,添加某種簡(jiǎn)潔方法實(shí)現(xiàn)同樣的效果,從而更加方便程序開(kāi)發(fā):
-
v-bind=》 : -
v-on=》 @
v-bind
綁定值:
<div id='app'>
<a v-bind:href="url">baidu</a> <!-- 使用v-bind綁定活的屬性 -->
<img :src="imgUrl" alt="">
</div>
<script>
new Vue({
el: "#app",
data: {
url: "http://www.baidu.com"
imgUrl: "https://www.baidu.com/img/bd_logo1.png?where=super"
}
})
</script>
綁定Class(綁定Style同理):
- 給
v-bind:class設(shè)置一個(gè)對(duì)象/數(shù)組可以動(dòng)態(tài)地切換 class ,條件復(fù)雜時(shí)可以使用計(jì)算屬性 - Vue 中駝峰式命名的大寫(xiě)字母都會(huì)被轉(zhuǎn)換成中劃線分隔的小寫(xiě)字母(建議統(tǒng)一寫(xiě)駝峰);
<div :class="{divStyle: isActive, borderStyle: isBorder}"></div> <!-- isActive的值為 true 為激活,false 為不激活 -->
<div :class="[activeClass,errorClass]"></div> <!-- 數(shù)組中的元素(變量)即為 class 類(lèi)名 -->
v-cloak
解決初始化慢導(dǎo)致頁(yè)面閃動(dòng)的問(wèn)題,一般與 display: none 結(jié)合使用
<style>
[v-cloak]: {
display: none
}
</style>
v-cloak: <p v-cloak:>{{msg}}</p> <!-- Vue 實(shí)例結(jié)束編譯時(shí)移除,才會(huì)渲染msg -->
<script>
while (true) {
}
new Vue({
el: "#app",
data: {
msg: "Hello World!"
}
})
</script>
v-once
只渲染一次,后續(xù)修改不會(huì)重新渲染
條件渲染指令:v-if,v-else-if,v-else
-
v-if、v-else-if后接等號(hào)和必須返回布爾值的條件,滿足條件(結(jié)果為 True)才渲染,否則會(huì)從 DOM 中移除; -
v-if在渲染元素時(shí)出于效率考慮,會(huì)盡可能復(fù)用已有元素而非重新渲染,所以可能出錯(cuò)(只渲染變化的元素,實(shí)例:用戶名與密碼的 input 框); - 上述問(wèn)題的解決方法:為元素加上
key=keyName(使元素有差異而重新渲染)。
條件渲染指令:v-show
- 與
v-if類(lèi)似,顯現(xiàn)與否取決于布爾值; - 與
v-if的區(qū)別在于v-show值為 false 時(shí)相當(dāng)于display: none,頁(yè)面上仍然存在該元素。
列表渲染指令:v-for
數(shù)組遍歷或枚舉對(duì)象屬性時(shí)可使用 v-for:
<ul>
<!-- arr: [{name: 'ywh'}, 'name': 'hwy'] -->
<li v-for="item in arr">
{{item.name}}
</li>
<li v-for="(item, index) in arr">
{{index}}-{{i.name}}
</li>
<!-- obj: {name: 'ywh', 'age': 18, gender: 'male'} -->
<li v-for="(value, key, index) in obj">
{{value}}-{{key}}-{{index}}
<li>
<ul>