Vue是一套用於構建用戶界面的漸進式框架。所謂漸進式即是指我們可以通過Vue構建從簡單到複雜的頁面應用,並且Vue.js壓縮文件只有33K,構建簡單的頁面不會顯得臃腫,同時Vue構建的複雜頁面也不會顯得簡陋。 Vue實現了DOM對象和數據的雙向綁定,你不用直接操作DOM,這項工作完全由Vue來完成,... ...
一 簡介
1,什麼是vue
Vue (讀音 /vjuː/,類似於 view) 是一套用於構建用戶界面的漸進式框架。所謂漸進式即是指我們可以通過Vue構建從簡單到複雜的頁面應用,並且Vue.js壓縮文件只有33K,構建簡單的頁面不會顯得臃腫,同時Vue構建的複雜頁面也不會顯得簡陋。
Vue實現了DOM對象和數據的雙向綁定,你不用直接操作DOM,這項工作完全由Vue來完成,你可以把更多的精力放到業務邏輯上來。
2,安裝
Vue目前最新的版本是2.6.x。當然,Vue也提供了開發版和生產版兩種文件。由於Vue使用了ECMAScript 5的特性,所以IE8及之前版本的瀏覽器不被支持。
Vue支持多種方式安裝,<script>標簽、CDN,CLI以及NPM。學習階段建議使用MDN或本地引入。
如果你想構建大型應用,請使用NPM安裝,方便配合webpack或類似的打包工具。如果你正在開發單頁面應用(SPA),那麼Vue提供的CLI工具可能是更好的選擇。這兩種方式請關註Vue官網。
1 //MDN
2 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
3 //本地
4 <script src="js/vue.js"></script>
二 vue實例
1,創建Vue實例
通常,每個Vue的應用都是通過創建一個Vue實例開始的:
1 var vm = new Vue({
2 // some code
3 });
vm是ViewModel的縮寫,許多文檔或教程也使用app來接收返回的對象,這都無所謂了,你只要知道我們需要聲明一個變數來接收Vue實例就行了。
在創建Vue實例時,你可以傳遞一個對象,這個對象包含了你可能要用到的數據、方法、Vue實例生命周期鉤子等。稍後將一一講解。
2,數據
當一個 Vue 實例被創建時,參數對象的data屬性綁定的對象中的所有屬性都被加入到 Vue 的響應式系統中。當這些屬性的值發生改變時,視圖將會產生“響應”,即修改為新的值。一般這會體現到HTML頁面上。
1 var obj = {name: 'ren'};
2 var vm = new Vue({
3 data: obj
4 });
5 //你可以直接使用vm代替data來訪問其綁定的對象屬性(這裡是obj.name)
6 obj.name = 'pen';
7 vm.name;//'pen'
8
9 vm.name = 'ken';
10 obj.name;//'ken'
11 //以上即可驗證Vue的數據雙向綁定
需要註意的是,要想實現數據的雙向綁定,在創建Vue實例之前,這些數據就應該已經被定義了。
1 //接上面的例子
2 obj.age = 12;
3 vm.age;//undefined
另一個需要註意的點是Object.freeze(),該方法會凍結對象,阻止修改對象現有的屬性,這就意味了Vue的響應式系統無法再對該對象起作用了。
1 var obj = {};
2 Object.freeze(obj);
3 var vm = new Vue({
4 data: obj
5 });
6 //這裡vm和obj的雙向綁定將失效
除了數據屬性外,Vue還提供了一些有用的實例屬性和方法,他們都有首碼$,用以區分用戶變數。
1 vm.$data === data;//true
2 vm.$el === document.getElementById();//true
3 vm.$watch();
4 vm.props;
Vue還有很多其他的屬性和方法,詳情請看Vue實例屬性。
3,方法
Vue在初始化的時候,我們還可以添加幾個屬性,methods、computed、watch。
1 var vm = new Vue({
2 el:'#app',
3 data:{
4 firstName:'',
5 lastName:''
6 },
7 methods:{
8 handler1:function(){},
9 handler2:function(){}
10 },
11 computed:{
12 fullName:fucntion(){
13 return this.firstName + ' ' + this.lastName ;
14 },
15 },
16 watch:{
17 fullName:function(){
18 console.log('The name has changed again');
19 }
20 }
21 });
methods中一般定義一些事件處理函數,使用v-on指令綁定;computed中一般定義需要複雜計算才能的出的值;watch一般用於偵聽某些值的變化,比如例子中用於偵聽fullName的變化,每當fullName發生變化,都會執行其綁定的函數。
4,生命周期
每個 Vue 實例在被創建時都要經過一系列的初始化過程。例如,需要設置數據監聽、編譯模板、將實例掛載到 DOM 併在數據變化時更新 DOM 等。同時在這個過程中也會運行一些叫做生命周期鉤子的函數,這給了用戶在不同階段添加自己的代碼的機會。下麵列舉了幾個常用的生命周期鉤子函數。
1 var vm = new Vue({
2 data:{},
3 //實例創建之前
4 beforeCreate:function(){},
5 //實例創建之後
6 created:function(){},
7 //實例掛載之前
8 beforeMount:function(){},
9 //實例掛載之後
10 mounted:function(){},
11 //數據更新之前
12 beforeUpdate:function(){},
13 //數據更新之後
14 updated:function(){}
15 });
完整的Vue實例生命周期示意圖:
Vue通過vm.el掛載指定DOM元素,掛載DOM元素實際上是用vm.$el替換原始的DOM元素。這樣我們就可以通過只操作虛擬的DOM元素vm.$el,來實現操作真實的DOM對象的目的了。
1 var vm = new Vue({
2 el: '#app',
3 data:{}
4 });
5 //記住,el通過id定位元素
三 模板語法
1,插值
插值一般使用雙大括弧語法:{{ msg }},中間添加變數名,這個變數一般是data或computed中的一個屬性名。這樣就可以實現HTML內容跟隨變數變化了。
雙大括弧把內部的變數解析為文本,而通過v-html指令,可以使瀏覽器把變數解析為HTML代碼。v-html有一個特點:它必須添加到一個HTML元素上,變數生成的HTML代碼最終都以該元素為祖先元素。
1 <!-- 文本 -->
2 <div id="app">{{ name }}</div>
3 <!-- HTML -->
4 <div id="app">
5 <p v-html="html"></p>
6 </div>
7 <script>
8 var obj = {
9 name:'ren',
10 html:'<span style="color:red"></span>'
11 };
12 var vm = new Vue({
13 el:'#app',
14 data:obj
15 });
16 </script>
{{ }}裡面不僅可以填寫簡單的變數表達式,它同時也支持更為複雜的計算表達式。
1 <p>{{ number + 1 }}</p>
2 <p>{{ ok ? 'YES' : 'NO' }}</p>
3 <p>{{ message.split('').reverse().join('') }}</p>
2,指令
第一小節提到的v-html,和它類似的v-*什麼的就時Vue提供的指令。比如,你可以通過v-once指令來實現一次性的插值,當數據改變時,插值處的內容不會再更新。
1 <div id="app" v-once>{{ name }}</div>
再比如,你要給HTML元素添加屬性,那麼你可能會用到v-bind指令。
<div v-bind:class="myClass"></div>
<!-- 元素將被添加一個mycalss變數保存的值的類,同時,它也可以是一個稍複雜的計算表達式,如'my'+msg。如果你想移除該屬性,你只需把null賦值給對應的變數 -->
亦或是你要給HTML元素綁定事件,v-on指令可以幫你實現。
1 <a v-on:click="eventHandler">link</a>
2 <!-- eventHandler是事件處理函數 -->
v-model指令可以雙向綁定元素的value值與指定的變數。
1 <input type='text' name='name' v-model='name'></input>
2 ***********************************************
3 var vm = Vue({
4 data:{
5 name:'ren'
6 }
7 });
8 //輸入框中的值會與vm.name同步
指令的作用是當指令綁定的表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。這裡只需明白什麼是Vue指令即可,常用的指令將在稍後的章節一一說明。
3,動態參數
如果你覺得上面的方式有失靈活,那麼Vue的動態參數或許能夠幫到你。Vue從2.6.0開始,允許你使用複雜表達式來定義指令最終的參數,不過你應該用[]方括弧把它括起來。
1 <a v-bind:[attributeName]="url"> link </a>
2 <!-- 具體哪個屬性會被添加,完全依賴方括弧中的表達式的計算值 -->
Vue指令還可以添加修飾符,使用.點來添加Vue指令的修飾符。例如.prevent,它告訴指令調用event.preventDefault()阻止事件預設行為。
1 <button v-on:submit.prevent="onSubmit">form</button>
2 <!-- 點擊按鈕時使用自定義函數,並通過.prevent阻止預設行為 -->
其他指令也有相應的修飾符,接下來的學習中會慢慢接觸到。
4,簡寫
對於使用頻率極高的v-bind和v-on指令,Vue提供了簡寫形式。
1 <!-- 完整語法 -->
2 <a v-bind:href="url">...</a>
3 <a v-on:click="doSomething">...</a>
4 <!-- 縮寫 -->
5 <a :href="url">...</a>
6 <a @click="doSomething">...</a>
7 <!-- 使用:冒號代替v-bind:,使用@替代v-on: -->
四 計算屬性和偵聽器
1,計算屬性
模板內的表達式非常便利,但是設計它們的初衷是用於簡單運算的。在模板中放入太多的邏輯會讓模板過重且難以維護。
所以,如果需要經過複雜的邏輯才能得到最終的值,建議你使用Vue的計算屬性。
1 var vm = new Vue({
2 el: '#app',
3 data: {
4 name: 'ren'
5 },
6 computed: {
7 reversedName: function () {
8 // `this` 指向 vm 實例
9 return this.name.split('').reverse().join('');
10 }
11 }
12 });
13 ********************************************************************
14 <div id="app">{{reversedNmae}}</div>
15 //計算屬性專門用於處理數據計算,需要指定返回值
2,偵聽器
偵聽器的作用是動態的監測數據的變化。
1 <input type='text' name='name' v-model='name'></input>
2 *************************************************************
3 var vm = Vue({
4 data:{
5 name:''
6 }
7 watch:{
8 name:function(){
9 console.log(The name has changed again);
10 }
11 }
12 });
13 //每當vm.name屬性發生改變時,控制台都會輸出一條信息
五 class和style
操作元素的 class 列表和內聯樣式是數據綁定的一個常見需求。因為它們都是屬性,所以我們可以用 v-bind
處理它們:只需要通過表達式計算出字元串結果即可。
不過,字元串拼接麻煩且易錯。因此,在將 v-bind
用於 class
和 style
時,Vue.js 做了專門的增強。表達式結果的類型除了字元串之外,還可以是對象或數組。
1,綁定class
綁定class屬性有兩種方式,對象和數組。
首先是對象方式,請看下麵的例子:
1 <div class='class0' v-bind:class="{class1:isclass1,class2:isclass2}"></div>
2 *********************************************************
3 data:{
4 isclass1:true,
5 isclass2:false
6 }
7 //通過data對象的isclass1和isclass2屬性控制class1和class2是否被添加到div上,同時div上原來定義的class0不受影響
如果需要操作的class列表很大,那麼你可以在data里添加一個classObj對象,專門用來存儲class控制變數。你當然也可以通過計算屬性computed來動態的計算哪些class屬性會被添加到div上。
1 <div v-bind:class="classObj"></div>
2 ******************************************************
3 //數據對象
4 data:{
5 classObj:{
6 isclass1:true,
7 isclass2:true
8 }
9 }
10 //計算屬性
11 computed:{
12 classObj:function(){
13 return {
14 //既然使用計算屬性,返回的對象應該是複雜計算得來的結果,由於只是舉例,所以這裡也只是簡單的賦值了
15 isclass1:true,
16 isclass2:true
17 }
18 }
19 }
除了對象綁定class屬性外,Vue還提供了數組綁定的方式。
1 <div v-bind:class="[class1,class2]">
2 ***************************************
3 data:{
4 class1:'myClass',
5 class2:'yourClass'
6 }
數組方式還支持動態的綁定class屬性,這是通過三元運算實現的。
1 <div v-bind:class="[iscalss1 ? class1 : '' , isclass2 ? class2 : '',class3]"></div>
2 *****************************************************************
3 data:{
4 isclass1:true,
5 isclass2:false
6 class3:'myClass'
7 }
8 //通過三元運算動態的綁定也可以和靜態綁定組合使用
2,綁定內聯樣式
內聯樣式使用過HTML標簽的style屬性實現的,所以Vue同樣使用v-bind指令來添加內聯樣式。
1 <div v-bind:style="{ color: myColor, fontSize: fontSize + 'px' }"></div>
2 ************************************************
3 data: {
4 myColor: 'red',
5 fontSize: 30
6 }
註意,css屬性名可以使用駝峰式或短橫線分隔樣式,若果使用短橫線分隔方式,記得用引號把它引起來。
直接綁定一個樣式對象通常更好,這會讓模板更清晰,同時也可以和class一樣,使用Vue的計算屬性conputed動態生成。
1 <div v-bind:style="styleObject"></div>
2 *************************************************
3 data: {
4 styleObject: {
5 color: 'red',
6 fontSize: '13px'
7 }
8 }
最後,綁定style屬性也有數組語法,使用方式和綁定class的數組語法一樣,這裡不再贅述。
六 條件渲染
有時候我們可能需要在特定情況才需要渲染某些HTML元素,另外一些情況希望隱藏它,Vue提供了條件渲染的方式。
1,v-if
v-if指令根據綁定的條件,來決定是否渲染該元素。同時Vue還提供了另外兩個指令:v-else-if和v-else,這讓條件渲染變得更加靈活和強大。
1 <div v-if="answer === 'A'">A</div>
2 <div v-else-if="answer === 'B'">B</div>
3 <div v-else-if="answer === 'C'">C</div>
4 <div v-else>D</div>
5 ********************************************
6 computed:function(){
7 //some code
8 return answer;
9 }
10 //根據answer的值,決定渲染那個元素
請註意,在同一個邏輯區域內,使用這三個指令的元素必須緊挨著,否者他們會失效。另外,v-else-if可以出現多次,而v-if和v-else只能在首位各出現一次。
如果你想一次控制多個元素,那麼你可以把條件指令作用到<template>元素上,最終的渲染結果將不包含<template>元素,而只包含其內部的元素。
1 <template v-if="ok">
2 <h1>Title</h1>
3 <p>Paragraph 1</p>
4 <p>Paragraph 2</p>
5 </template>
6 //當v-if接收到真值時,<template>元素不會出現在頁面上,而h1和p會出現
2,v-show
v-show並不是真正意義上的條件渲染,它只是簡單的操控元素的display屬性,來達到顯示或隱藏元素的目的。而v-if不經保證元素隱藏,還能保證綁定的事件能被及時的銷毀或重建。
1 <h1 v-show="ok">Hello!</h1>
2 <!-- 當ok為真值時,h1將被顯示,否則將被隱藏 -->
七 列表
在Vue中渲染列表需要用到v-for指令。v-for可以通過數組或對象渲染列表。
1,數組渲染
1 <ul>
2 <li v-for="(value,index) in arr">{{index}}:{{value}}</li>
3 </ul>
4 **************************************************
5 data:{
6 arr:[1,2,3]
7 }
8 //value是元素,index是下標,下標是可選的參數
你甚至可以顯示一個數組經過過濾或排序後的版本,而不實際改變或重置原始數據。在這種情況下,可以創建一個計算屬性,來返回過濾或排序後的數組。
1 <li v-for="n in newArr">{{ n }}</li>
2 ********************************************
3 data: {
4 arr: [ 1, 2, 3, 4, 5 ]
5 },
6 computed: {
7 newArr: function () {
8 return this.arr.filter(function (val) {
9 return val % 2 === 0;
10 })
11 }
12 }
2,對象渲染
1 <ul>
2 <li v-for="(value,name,index) in arr">{{parentMsg}}:{{index}}:{{value}}</li>
3 </ul>
4 **************************************************
5 data:{
6 parendMsg:'parent',
7 arr:{
8 name:'ren',
9 age:12
10 }
11 }
12 //結果:
13 //parent:0:ren
14 //parent:1:age
15 //value是屬性值,name是屬性名,index是序號(一般同Object.keys()的順序),name和key都是可選的
從上面例子可以看出,v-for指令不僅可以訪問綁定的對象,還可以訪問其父域內的變數。
3,渲染順序
預設狀態下,當綁定的數據項順序被改變時,Vue不會主動的去修改已渲染的列表,如果要保證列表順序始終與數據項一致,你應該給每一項的屬性key提供一個唯一值,建議是數字或字元串等原始值。
1 <div v-for="(item,index) in arr" v-bind:key="index"></div>
2 <!-- 數組可以使用index,對象可以使用name -->
4,更新檢測
我們知道,在JavaScript中,有很多方法可以修改數組和對象。但是,並不是所有的方法都能觸發Vue的響應,即並不是所有的方法都能觸發視圖更新。
對於數組,Vue 不能檢測以下數組的變動:
a:當你利用索引直接設置一個數組項時,例如:vm.items[indexOfItem] = newValue;
b:當你修改數組的長度時,例如:vm.items.length = newLength;
對於對象,Vue 不能檢測對象屬性的添加和刪除。詳情見本文2.2節。
幸運的是,Vue額外提供了vm.set方法來解決該問題。
1 //Vue.set(object, name, value);
2 var obj = {
3 name:'ren',
4 age:12
5 };
6 var vm = new Vue({
7 data:{
8 person:obj
9 }
10 });
11 vm.set(vm.person,'sex','male');
12 //新的sex屬性是響應式的。
需要註意的是,第一個參數必須是一個對象,即該data的屬性應該綁定的是一個對象,才能使用該方法。
八 表單
上面3.2小節簡單介紹的v-model指令,這裡將詳細介紹表單與它的關係,及用法。
1,文本綁定
1 <!-- 單行文本 -->
2 <input v-model="message">
3 <p>Message is: {{ message }}</p>
4 <!-- 多行文本 -->
5 <p>{{ message }}</p>
6 <textarea v-model="message"></textarea>
請註意:在文本區域插值 <textarea>{{text}}</textarea>
並不會生效,應用 v-model
來代替。
2,單選
1 <input type="radio" id="one" value="One" v-model="picked">
2 <label for="one">One</label>
3 <br>
4 <input type="radio" id="two" value="Two" v-model="picked">
5 <label for="two">Two</label>
6 <br>
7 <span>Picked: {{ picked }}</span>
8 *****************************************************
9 data:{
10 picked:''
11 }
3,覆選
1 <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
2 <label for="jack">Jack</label>
3 <input type="checkbox" id="john" value="John" v-model="checkedNames">
4 <label for="john">John</label>
5 <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
6 <label for="mike">Mike</label>
7 <br>
8 <span>Checked names: {{ checkedNames }}</span>
9 *****************************************************
10 data:{
11 checkNames:[]
12 }
13 <!-- 如果只有一個覆選項,那麼不使用數組會更方便 -->
4,下拉列表
1 <select v-model="selected">
2 <option disabled value="">請選擇</option>
3 <option>A</option>
4 <option>B</option>
5 <option>C</option>
6 </select>
7 <p>Selected: {{ selected }}</