Vue是現在最流行的前端框架之一,而且相對于其他兩個框架React和Angular來說也更加易學,而且它的作者是國人,中文文檔也很完善。當然Vue框架算是比較高級的框架,所以在使用過程中還需要JavaScript、JavaScript 2015、WebPack、NodeJS、npm、ESLint、JavaScript單元測試框架等其他知識和框架的使用方法。在學習Vue之前,最好先學習一下這些知識。由于Vue的中文文檔比較完善,所以這里只介紹Vue框架的一些核心概念,詳細的使用方法還得查看官方文檔。
Vue的中文文檔可以查看https://cn.vuejs.org/v2/guide/installation.html 。
Vue路由功能需要導入vue-router,它的中文文檔可以查看https://router.vuejs.org/zh-cn/ 。
Vue的狀態管理功能需要使用vuex,它的中文文檔可以查看https://vuex.vuejs.org/zh-cn/ 。
如果需要更多Vue資料,可以查看awesome-vue,列舉了很多Vue資源。
Vue基本概念
從單文件開始
首先,我們來拋開那些復雜的框架配置,先從單文件開始學習Vue最基本的內容。這樣做很簡單,講下面的代碼復制為一個HTML文件,在瀏覽器中打開即可。這里引用了Vue框架的CDN,所以不需要任何配置即可使用Vue。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue單文件例子</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
</body>
</html>
Vue實例
Vue框架中最重要的東西就是Vue實例了,它是Vue框架的核心對象。在創建Vue實例的時候需要傳入一些參數,el
參數是Vue實例的作用范圍;data
參數是Vue實例使用的數據。在Vue實例對應的元素中,我們可以使用模板語法{{var}}
來使用這些數據。
<h1>Vue實例</h1>
<div id="s1">
<p>{{data}}</p>
</div>
<script>
let vm1 = new Vue({
el: '#s1',
data: {
data: '一些數據'
}
})
</script>
模板語法
文本插值
上面已經展示了一個小例子。文本需要寫在兩對花括號之間。當然這里其實不止可以寫單個變量,還可以寫組合表達式,例如{{text + new Date()}}
。
所有在構造Vue實例是傳入的數據都是可響應的,也就是說只要數據發生改變,那么視圖的數據也會發生改變。如果希望數據不發生改變,需要使用v-once
指令。所有v-
開頭的都是Vue獨有的指令,這些指令將在后面介紹。
HTML插值
有時候需要操作原始HTML,Vue也提供了支持。要插入的HTML代碼需要使用v-html
指令來指定,這個指令會將它所在的HTML代碼塊整個替換為要插入的HTML塊。由于可能導致XSS攻擊,所以最好不要隨便替換HTML塊。另外要替換HTML塊的話只能使用v-html
指令,如果使用前面的文本插值的話,插入的只是一段文本。
屬性
文本插值只能插入文本,如果需要設置和修改HTML屬性的話,需要使用v-bind
指令。
下面是一個簡單的例子,將它復制到前面的HTML文件中即可看到效果。
<h1>模板語法</h1>
<div id="s2">
<button v-on:click='changeText'>修改文本</button>
<p>文本:{{text}}</p>
<p>組合表達式:</p>
<p v-once>只渲染一次的文本:{{text}}</p>
<p>HTML代碼:<span v-html="html"></span></p>
<p>屬性:
<button v-bind:disabled="disabled">禁用按鈕</button>
</p>
</div>
<script>
let vm2 = new Vue({
el: '#s2',
data: {
text: 1,
html: '<del>666</del>',
disabled: true
},
methods: {
changeText: function (event) {
this.text += 1
}
}
})
</script>
計算屬性
有時候程序邏輯比較復雜,可能需要對一個數據進行一些計算和處理。這時候就需要計算屬性了。當然由于模板語法支持表達式,所以也可以直接在{{}}
中編寫表達式,但是不管從可讀性還是可維護的角度來說,計算屬性都是更好的選擇。
計算屬性需要在構造Vue實例的時候傳入computed
屬性,然后在相應的函數中處理復雜邏輯。計算屬性可以向普通屬性那樣在視圖中使用。計算屬性有個優點就是惰性求值,下面的例子中,toUpper
計算屬性依賴于words
屬性,只要words
不發生改變,那么多次訪問toUpper
不會重新出發計算,而是會使用已有的結果。只有當words
發生變化時,toUpper
才會相應改變。
<h1>計算屬性</h1>
<div id="s3">
<p>單詞:{{words}}</p>
<p>單詞大寫:{{toUpper}}</p>
</div>
<script>
let vm3 = new Vue({
el: '#s3',
data: {
words: 'I love you'
},
computed: {
toUpper: function () {
return this.words.toUpperCase()
}
}
})
</script>
Vue指令
v-once
這個指令讓視圖只渲染一次,將來就算相應的數據發生變化,也不會重新渲染。該指令主要在希望靜態顯示不需要更新數據的時候使用。
v-html
這個指令主要在需要操作原始HTML的時候使用。
v-bind
該指令在需要綁定HTML標簽屬性的時候使用。為了方便,該指令還有一個縮寫:
,例如:class="myClass"
就相當于v-bind:class="myClass"
。
v-on
該指令主要用于綁定事件處理程序。該指令有縮寫@
,例如@click="onClick"
就相當于v-on:click="onClick"
。
v-show、v-if、v-else和v-else-if
這幾個指令主要用于條件渲染,將在后面進行介紹。
v-for
該指令用于渲染整個列表,將在后面進行介紹。
v-model
該指令可以讓頁面元素和數據進行雙向綁定。默認情況下數據和頁面元素是單向綁定的,使用該指令可以讓其變成雙向綁定。該指令主要用于處理表單等場景。
條件渲染
v-if、v-else和v-else-if這幾個指令用于條件渲染,讓我們可以按照條件在頁面上顯示和隱藏某些元素。注意v-else-if指令是Vue 2.1新增的。類似的指令還有v-show,不過v-show指令僅僅改變元素的CSS display屬性,也是說隱藏的元素還是存在于頁面上,僅僅是不顯示而已。而v-if等元素會真正創建和銷毀元素。
這些指令的使用方法很簡單,直接看例子就行了。
<h1>條件渲染</h1>
<div id="s4">
<h3>v-if渲染會實際創建和銷毀對象</h3>
<p>分數是:<input type="text" v-model="mark"/></p>
<p v-if="mark < 60">不及格</p>
<p v-else-if="mark <80">及格</p>
<p v-else="">優秀</p>
<h3>v-show僅僅調用CSS display屬性</h3>
<button @click="toggleShow">改變show狀態</button>
<p v-show="show">可以看到我</p>
</div>
<script>
let vm4 = new Vue({
el: '#s4',
data: {
mark: 80,
show: true
},
methods: {
toggleShow: function () {
this.show = !this.show
}
}
})
</script>
列表渲染
如果需要渲染一組數據,可以使用v-for指令。v-for指令需要一個item in items
塊來聲明迭代那些數據,這里in
也可以改為of
。如果需要獲取迭代的索引的話,可以把迭代塊聲明為(item, index) in items
這樣的。另外除了迭代一個列表,也可以迭代一個對象的屬性。
<h1>列表渲染</h1>
<div id="s5">
<h3>名字列表</h3>
<ul>
<li v-for="name in names">{{name}}</li>
</ul>
<h3>人物表格</h3>
<table>
<thead>
<tr>
<td>編號</td>
<td>姓名</td>
<td>年齡</td>
</tr>
</thead>
<tbody>
<tr v-for="(person, index) of people" :key="index">
<td>{{index}}</td>
<td>{{person.name}}</td>
<td>{{person.age}}</td>
</tr>
</tbody>
</table>
</div>
<script>
let vm5 = new Vue({
el: '#s5',
data: {
names: [
'zhang3',
'li4',
'yitian',
'jojo'
],
people: [
{name: 'zhang3', age: 24},
{name: 'li4', age: 25},
{name: 'yitian', age: 24},
{name: 'jojo', age: 30}
]
}
})
</script>
事件處理
v-on指令用于綁定事件處理函數,這里的函數需要在構造Vue實例的時候在methods
屬性中聲明。
針對鍵盤按鍵,Vue還定義了一組按鍵修飾別名,詳情請參考官方文檔。下面是一個簡單的例子。
<h1>事件處理</h1>
<div id="s6">
<h3>計數器</h3>
<p>
<button @click="addCount">增加計數</button>
<em>{{count}}</em>
</p>
<h3>獲取按鍵(單擊、回車和空格)</h3>
<input type="text"
@keyup.enter="alert('按下了回車')"
@keyup.space="alert('按下了空格')"
@click="alert('單擊')"/>
</div>
<script>
let vm6 = new Vue({
el: '#s6',
data: {
count: 0
},
methods: {
addCount: function () {
this.count++
}
}
})
</script>
綁定表單
如果要將數據和頁面元素進行雙向綁定,使用v-model指令。這個指令主要用于處理表單輸入中。下面是一組表單例子。
<h1>綁定表單</h1>
<div id="s7">
<p>文本框:{{text}}</p>
<p>多行文本:{{textArea}}</p>
<p>單選按鈕:{{radio}}</p>
<p>復選框:{{checkbox}}</p>
<p>多選框:{{select}}</p>
<hr>
<p>文本框:<input type="text" v-model="text"></p>
<p>多行文本:<textarea v-model="textArea"></textarea></p>
<p>單選按鈕:<input type="radio" v-model="radio" value="1" id="one"><label for="one">1</label>
<input type="radio" value="2" v-model="radio" id="two"><label for="two">2</label>
</p>
<p>復選框:<input type="checkbox" v-model="checkbox" id="checkbox"><label for="checkbox">復選框</label></p>
<p>多選框:<select id="select" v-model="select">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</p>
</div>
<script>
let vm7 = new Vue({
el: '#s7',
data: {
text: 'text',
textArea: 'textArea',
radio: '',
checkbox: '',
select: '',
}
})
</script>
在處理表單輸入的時候,還有.lazy
、.number
、.trim
幾個修飾符,它們的作用分別是在change事件中更新、將表單輸入轉換為數值以及去掉表單中的前后空格。
組件
前面介紹了Vue的各種功能,但是這些功能并不能直接在項目中使用。因為如果直接使用的話,會導致出現一個非常大的Vue實例,這和將所有代碼都寫在一個文件的道理是一樣的。所以Vue引入了組件來進行模塊化功能。
定義組件和定義一個Vue實例類似。不同的是,組件需要有自己的模板,而且組件的data
屬性必須是一個函數。原因是假如一個組件在多個地方復用,那么原本的data
屬性會導致所有組件實例共用一個屬性值。使用函數后,每個組件實例都會有自己獨立的數據。更加詳細的解釋和例子請查看官方文檔。
let component1 = {
template: '<h3>{{hello}}</h3>',
data() {
return {
hello: 'hello world'
}
}
}
定義好了組件之后,我們還需要在Vue中注冊它。第一種方法是全局注冊,這樣組件就可以在全局范圍中使用。
Vue.component('組件標簽名', {
//實際組件
})
第二種方法更常見,就是局部注冊。將組建注冊到局部Vue實例,那么組件只會在該實例的作用域內可見。局部注冊需要在創建Vue實例的時候講組件傳入到components
屬性中。
let vm8 = new Vue({
el: '#s8',
components: {
'hello-world': component1,
}
})
組件注冊完畢之后,我們就可以像使用自定義標簽一樣使用它了。
<hello-world></hello-world>
如果需要從父組件中傳遞數據,需要在子組件中聲明props
屬性制定要傳入的數據。
let component1 = {
template: '<p>{{hello}} {{name}}</p>',
data() {
return {
hello: 'hello world'
}
},
props: [
'name'
]
}
然后就可以像這樣傳遞數據了。
<hello-world name="zhang3"></hello-world>
如果需要傳遞動態數據,使用v-bind
指令即可。
<hello-world :name="name"></hello-world>
一個完整的例子見下。
<h1>組件</h1>
<div id="s8">
<h3>hello world組件</h3>
<hello-world></hello-world>
<h3>從父組件傳遞數據</h3>
<hello-world name="zhang3"></hello-world>
<h3>動態傳遞數據</h3>
<hello-world :name="name"></hello-world>
</div>
<script>
let component1 = {
template: '<p>{{hello}} {{name}}</p>',
data() {
return {
hello: 'hello world'
}
},
props: [
'name'
]
}
let vm8 = new Vue({
el: '#s8',
data: {
name: 'yitian'
},
components: {
'hello-world': component1,
}
})
</script>
過渡效果
最后來說說Vue的過渡效果,這里只說說最基本的進入離開過渡。Vue還支持更加復雜的狀態過渡,如果想了解這些更復雜的知識,請直接查看文檔。
Vue封裝了一個組件transition
,當其中的組件被插入、刪除,或者發生變化的時候,會自動查看這些組件是否應用了過渡CSS類,然后再恰當的時機插入和刪除這些類,從而實現過渡效果。過渡類名在官方文檔中有介紹,還有一張過渡示意圖,這里我就不再介紹了。
比如說我現在需要一個透明度過渡效果。我可以這樣編寫CSS類。
.v-enter-active {
transition: all 1s;
}
.v-leave-active {
transition: all 1s;
}
.v-enter, .v-leave-to {
opacity: 0;
}
然后用下面的方法使用,就可以看到實際效果了。
<div id="s9">
<h3>按鈕過渡</h3>
<button @click="show = !show">改變狀態</button>
<transition>
<p v-if="show">Hello</p>
</transition>
</div>
<script>
let vm9 = new Vue({
el: '#s9',
data: {
show: true
}
})
當然對于我這種前端小白來說,自己編寫過渡和動畫效果還是有點困難。幸好有很多第三方動畫庫,而且Vue允許我們自定義類名,以便和這些動畫庫配合使用。比方說Animate.css,我們可以將CDN添加到頁面中來使用。
<link rel="stylesheet">
然后自定義類名即可。
<transition enter-active-class="animated fadeInLeft"
leave-active-class="animated fadeOutUpBig">
<p v-if="show">Hello</p>
</transition>
完整的單文件例子可以查看我的示例項目。
Vue工程化
前面介紹了Vue的基本概念,但是這些概念無法直接用在項目中。下面通過Vue和各種工具鏈的使用,來介紹如何用Vue創建實際前端項目。
從模板創建Vue項目
首先確保你安裝了NodeJS,然后安裝Vue命令行工具。如果npm速度太慢的話,可以使用淘寶鏡像來加速。
npm install -g vue-cli
安裝完成之后,使用vue-cli
來創建模板項目。由于WebPack打包工具現在非常流行,所以這里選擇創建WebPack模板。創建的時候除了Vue之外,其他組件如vue-router、eslint等都不要選。
vue init webpack your-app-name
項目創建完畢之后,切換到項目文件夾中,可以看到已經生成了一堆文件。然后我們使用npm i
來安裝所有的依賴包。安裝完成之后,使用npm run dev
來運行測試服務器。這個項目模板支持熱重載等特性,所以我們接下來的開發過程可以直接在此基礎上進行,不需要重啟服務器。這時候我們也可以使用WebStorm的開發工具編輯項目,充分享受IDE帶來的便捷。
下面介紹一下模板項目的結構。build和config文件夾存放的是項目的構建文件和配置文件,會有WebPack和npm使用。node_modules是項目所需的模塊存放位置。src文件夾下存放著項目所需的源代碼,主要是JavaScript和Vue文件。assets文件夾存放的是項目所需的靜態文件,例如圖片、樣式表等。components文件夾是Vue組件的存放位置。App.vue是項目默認的跟組件。main.js是項目的入口JavaScript文件。index.html是項目的默認HTML文件。圖里面還有一個sample.html,就是上面我介紹Vue時使用的單HTML文件。
單文件組件
前面介紹了Vue強大的組件功能,但是這種組件是不能擴展的。一般情況下,項目中應該使用單文件組件。在上面創建的項目中,實際上已經包含了一個單文件組件。讓我們看看實際的項目應該如何組織這些組件。
先來看看主HTML文件index.html
,它的內容很簡單。它的真實內容會由WebPack打包進去。一般情況下我們只需要保持不變就好了。當然頁面標題之類的屬性還是要改的。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue-sample</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
然后來看看項目入口文件main.js
,它的內容如下。可以看到它的作用很簡單,創建根Vue實例,并將根應用組件App
注入其中。
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
template: '<App/>',
components: { App }
})
然后來看看根組件App.vue
中寫了什么,這是一個單文件組件,它調用了另一個單文件組件<hello-world/>
。單文件組件和前面介紹的組件一樣,都有一個模板屬性,需要注意模板屬性中的元素必須有一個根元素,不能出現多個并列的元素。還有一個腳本塊,這里是單文件組件中代碼邏輯部分,需要注意的是,這個地方必須向外暴露創建Vue實例所需的那個屬性對象。這里還有一個樣式塊,是單文件組件修改樣式的地方。
<template>
<div id="app">

<hello-world/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
<style>
...
</style>
Vue路由快速入門
安裝
最簡單的辦法就是在前面創建模板項目的時候同時選擇使用vue-router。如果沒有在創建項目是選擇vue-router,就需要手動添加到項目中。
下面用前面創建的沒有安裝vue-router的模板項目做例子來介紹。首先需要安裝vue-router并將其添加到package.json
文件中。
npm i -S vue-router
然后創建src/router/index.js
文件,并在其中添加如下代碼。這樣會在全局注冊Vue路由組件。
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router()
最后在項目入口文件src/main.js
中在全局Vue實例中注冊路由。
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
template: '<App/>',
components: {App}
})
這樣Vue路由功能就注冊好了。
添加路由
下面來添加第一個路由。和Vue實例一樣,router實例也可以在構造的時候通過參數來配置。首先在路由構造函數中添加路由屬性,每個路由都需要有路徑、組件名以及實際組件。
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: HelloWorld
},
],
})
添加好路由之后,為了能讓程序隨路由變化而顯示不同內容,我們還需要使用vue-router預設的組件<router-view/>
,它會在運行的時候替換為我們所定義的組件。在這個例子中,只需要將App.vue
文件中的hello-world
組件替換為router-view
即可。
<template>
<div id="app">

<router-view></router-view>
</div>
</template>
切換為HTML5歷史模式
在使用Vue路由的時候,我們會發現瀏覽器中的地址長的是這個樣子:xxx/#/
。這是Vue路由的默認哈希模式,優點就是兼容性強。還有另外一種模式就是HTML歷史模式。要使用這種模式很簡單,在構造Vue路由的時候,將mode
參數設置為history
即可。這樣一來,瀏覽器地址欄就會變成正常狀態。當然這種模式也有缺點,就是假如后臺沒配置好,訪問某些頁面可能會返回404錯誤。所以具體使用哪種模式還需要自己仔細考慮。
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: HelloWorld
},
],
mode: 'history'
})
Vue路由相對于Vue核心框架來說,沒什么復雜的概念,基本上很容易理解和上手。所以我這里就不做過多介紹了。官方文檔介紹的更加完整。
Vue和視圖框架
通過以上學習我們可以看到Vue可以算是一個MVVM框架,主要作用就是將前臺頁面和數據綁定起來。為了做出漂亮的視覺效果,我們還需要和其他視圖框架進行集成。
和Bootstrap 4集成
Bootstrap是最著名的前端框架之一,可以幫助我們迅速創建漂亮的頁面。現在它的最新版本是4.0.0-beta
,基本可以在項目中投入使用了。現在假設我們有一個啟用了路由功能的基于WebPack的Vue模板項目,來看看如何安裝Bootstrap 4吧。
首先,用npm安裝Bootstrap 4和相關的幾個依賴包。這里特別注意Bootstrap的版本,這里我們用的是4 。如果不加版本號的話,會安裝3的穩定版。不過現在穩定版已經停止更新了,不會再添加任何新功能了,只進行bug修復和維護。
npm install -S bootstrap@4.0.0-beta jquery popper.js
安裝好之后,還需要修改WebPack配置文件。在Vue模板中,配置文件有三個,webpack.base.conf.js
、webpack.dev.conf.js
和webpack.prod.conf.js
,分別代表基礎配置、開發配置和生產配置。為了讓配置在所有條件下生效,我們需要在webpack.base.conf.js
中配置。辦法也很簡單,添加plugins
屬性和下面的插件即可。如果在該文件中沒有導入webpack
模塊,還需要在開頭添加一行const webpack = require('webpack')
導入該模塊。
plugins: [
...
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
Popper: ['popper.js', 'default'],
})
...
]
然后在項目入口文件src/main.js
中引入Bootstrap的樣式文件和JavaScript文件即可。
import Vue from 'vue'
import App from './App'
import router from './router'
// 引入Bootstrap文件
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.min.css'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
...
})
最后別忘了在index.html
中添加Bootstrap的meta標簽。
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
然后在頁面中就可以使用Bootstrap樣式來開發程序了。
和ElementUI集成
element-ui是Vue 2.0的一組組件庫,可以幫助我們快速開發項目。
首先通過npm安裝。
npm i element-ui -S
然后在main.js
文件中寫入以下內容。
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-default/index.css'
import App from './App.vue'
Vue.use(ElementUI)
new Vue({
el: '#app',
render: h => h(App)
})
element-ui的效果如圖。