Vue的相關知識點

 
 
 
 
 
 
 
 
Vue近幾年來特別的受關注,三年前的時候angularJS霸佔前端JS框架市場很長時間,接着react框架橫空出世,由於它有一個特性是虛擬DOM,從性能上碾軋angularJS,這個時候,vue1.0悄悄的問世了,它的優雅,輕便也吸引了一部分用戶,開始收到關注,16年中旬,VUE2.0問世,這個時候vue無論從性能上,仍是從成本上都隱隱超過了react,火的一塌糊塗,這個時候,angular開發團隊也開發了angular2.0版本,而且改名爲angular,吸取了react、vue的優勢,加上angular自己的特色,也吸引到不少用戶,目前已經迭代到5.0了。

學習vue是如今前端開發者必須的一個技能。
 
前端js框架到底在幹嗎,爲何要用
 
js框架幫助開發者寫js邏輯代碼,在開發應用的時候js的功能劃分爲以下幾點:

1. 渲染數據

2. 操做dom(寫一些效果)

3. 操做cookie等存儲機制api
 
在前端開發中,如何高效的操做dom、渲染數據是一個前端工程師須要考慮的問題,並且當數據量大,流向較亂的時候,如何正確使用數據,操做數據也是一個問題

而js框架對上述的幾個問題都有本身趨於完美的解決方案,開發成本下降。高性能高效率。惟一的缺點就是須要使用必定的成原本學習。
 
Vue官網介紹

vue是漸進式JavaScript框架

「漸進式框架」和「自底向上增量開發的設計」是Vue開發的兩個概念

Vue能夠在任意其餘類型的項目中使用,使用成本較低,更靈活,主張較弱,在Vue的項目中也能夠輕鬆融匯其餘的技術來開發,而且由於Vue的生態系統特別龐大,能夠找到基本全部類型的工具在vue項目中使用

特色:易用(使用成本低),靈活(生態系統完善,適用於任何規模的項目),高效(體積小,優化好,性能好)

Vue是一個MVVM的js框架,可是,Vue 的核心庫只關注視圖層,開發者關注的只是m-v的映射關係
 
與AngularJS的對比
 
Vue的不少api、特性都與angularJS類似,實際上是由於Vue在開發的時候借鑑了不少AngularJS中的特色,而AngularJS中固有的缺點,在Vue中已經解決,也就是青出於藍而勝於藍,Vue的學習成本比AngularJS低不少,由於複雜性就低

AngularJS是強主張的,而Vue更靈活

Vue的數據流是單向的,數據流行更清晰

Angular裏指令能夠是操做dom的,也能夠封裝一段結構邏輯代碼,例如:廣告展現模塊

Vue中的指令只是操做dom的,用組件來分離結構邏輯

AngularJS的性能比不上Vue
 
Vue的使用
 
Vue不支持IE8,由於使用了ES5的不少特性

能夠直接經過script標籤來引入vue.js,有開發版本和生產版本,開發版本通常咱們在開發項目的時候引入,當最後開發完成上線的時候引入生產版本,開發版本沒有壓縮的,而且有不少提示,而生產版本所有刪掉了

在Vue中提供了一個腳手架(命令行工具)能夠幫咱們快速的搭建基於webpack的開發環境...
 
Vue的實例
 
每個應用都有一個根實例,在根實例裏咱們經過組件嵌套來實現大型的應用

也就是說組件不必定是必須的,可是實例是必需要有的

在實例化實例的時候咱們能夠傳入一個;配置項,在配置項中設置不少屬性方法能夠實現複雜的功能


在配置中能夠設置el的屬性,el屬性表明的是此實例的做用範圍

在配置中同過設置data屬性來爲實例綁定數據
 
 
mvc/mvvm
 
[阮大神博客](http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html)

mvc 分爲三層,其實M層是數據模型層,它是真正的後端數據在前端js中的一個映射模型,他們的關係是:數據模型層和視圖層有映射關係,model改變,view展現也會更改,當view產生用戶操做或會反饋給controller,controller更改model,這個時候view又會進行新的數據渲染

![MVC](http://image.beekka.com/blog/2015/bg2015020105.png)

這是純純的MVC的模式,可是不少框架都會有一些更改

前端mvc框架,如angularjs,backbone:

![前端MVC](http://image.beekka.com/blog/2015/bg2015020108.png)

會發現,用戶能夠直接操做controller(例如用戶更改hash值,conrtoller直接監聽hash值變化後執行邏輯代碼,而後通知model更改)

控制器能夠直接操做view,若是,讓某一個標籤得到進入頁面得到焦點,不須要model來控制,因此通常會直接操做(angularJS,指令)

view能夠直接操做model (數據雙向綁定)

MVP:

[mvp](http://image.beekka.com/blog/2015/bg2015020109.png)

view和model不能直接通訊,全部的交互都由presenter來作,其餘部分的通訊都是雙向的

view較薄 ,presenter較爲厚重
 
 
MVVM:

[mvvm](http://image.beekka.com/blog/2015/bg2015020110.png)

MVVM和MVP及其類似,只是view和viewmodel的通訊是雙向綁定,view的操做會自動的像viewmodel經過
 
v-for

在vue中能夠經過v-for來循環數據的通知循環dom,語法是item in/of items,接收第二個參數是索引 (item,index) of items,還能夠循環鍵值對,第一個參數是value,第二個是key,第三個依然是索引
 
v-on
 
在vue中還有v-on來爲dom綁定事件,在v-on:後面加上要綁定的事件類型,值裏能夠執行一些簡單javascript表達式:++ -- = ...

能夠將一些方法設置在methods裏,這樣就能夠在v-on:click的值裏直接寫方法名字能夠,默認會在方法中傳入事件對象,當寫方法的時候加了()就能夠傳參,這個時候若是須要事件對象,那就主動傳入$event

v-on綁定的事件能夠是任意事件,v-on:能夠縮寫爲@
 
爲何在 HTML 中監聽事件?

你可能注意到這種事件監聽的方式違背了關注點分離 (separation of concern) 這個長期以來的優良傳統。但沒必要擔憂,由於全部的 Vue.js 事件處理方法和表達式都嚴格綁定在當前視圖的 ViewModel 上,它不會致使任何維護上的困難。實際上, 使用 v-on 有幾個好處:

1. 掃一眼 HTML 模板便能輕鬆定位在 JavaScript 代碼裏對應的方法。
2. 由於你無須在 JavaScript 裏手動綁定事件,你的 ViewModel 代碼能夠是很是純粹的邏輯,和 DOM 徹底解耦,更易於測試。
3. 當一個 ViewModel 被銷燬時,全部的事件處理器都會自動被刪除。你無須擔憂如何本身清理它們。
 
模板語法

在vue中,咱們使用mustache插值({{}})來將數據渲染在模板中

使用v-once指令能夠控制只能插入一次值,當數據變化的時候,模板對應的視圖不更新

使用v-html指令能夠解析html格式的數據

在html標籤屬性裏不能使用mustache插值,這個時候給元素添加動態屬性的時候使用v-bind來綁定屬性,能夠縮寫成:

在使用v-bind綁定class和內聯樣式的時候,vue作了一些優化,可使用對象語法和數組的語法來控制

防止表達式閃爍:
 
1. v-cloak

給模板內的元素添加v-cloak屬性後,元素在vue沒有加載完的時候就有這個屬性,當vue加載完成後這個屬性就消失了,因此咱們能夠給這個屬性設置css樣式爲隱藏
 
<style>
    [v-cloak]{
        visibility: hidden;
    }
    </style>

  

2. v-text/v-html

v-text會指定將模板內元素的textContent屬性替換爲指令值所表明的數據,也能夠用於防止閃爍
v-html能夠解析標籤,更改元素的innerHTML,性能比v-text較差

3. v-pre

跳過元素和其子元素的編譯過程,能夠用來顯示mustache
 
vue-resource
 
這是一款vue的插件,能夠用來進行數據交互,支持的請求方式:GET/POST/JSONP/OPTIONS...

這個插件官方宣佈不在更新維護,也就是說盡可能不要使用
 
計算屬性、監聽
 
有的時候咱們須要在模板中使用數據a,這個時候就須要用到表達式,可是有的地方咱們須要對a數據進行一些簡單的處理後才能使用,那麼咱們就會在表達式中寫一些js邏輯運算
 
<div id="example">
   {{ message.split('').reverse().join('') }}
</div>

  

這樣咱們的維護就會很是困難,也不便於閱讀

那め咱們就能夠在methods裏設置一個方法,在模板的表達式中使用這個方法
 
<p>Reversed message: "{{ reversedMessage() }}"</p>
    // 在組件中
    methods: {
        reversedMessage: function () {
            return this.message.split('').reverse().join('')
        }
    }

  

可是這個時候,只要vm中有數據變化,這個變化的數據可能和咱們關注的數據無關,可是vm都會從新渲染模板,這個時候表達式中的方法就會從新執行,大大的影響性能


這個時候其實咱們可使用監聽器裏完成:

在vm實例中設置watch屬性,在裏面經過鍵值對來設置一些監聽,鍵名爲數據名,值能夠是一個函數,這個函數在數據改變以後纔會執行,兩個參數分別是性格前的值和更改後的值
 
a: function (val, oldVal) {
        console.log('new: %s, old: %s', val, oldVal)
    }

 

值還能夠是一個方法名字,當數據改變的時候這個方法會執行

當數據爲object的時候,object的鍵值對改變不會被監聽到(數組的push等方法能夠),這個時候須要設置深度監聽:
 
c: {
        deep:true,
        handler:function (val, oldVal) {
            console.log('new: %s, old: %s', val, oldVal)
        }
    }

 

監聽的handler函數前面的這幾種寫法都是在數據變化的時候纔會執行,初始化的時候不會執行,可是若是設置immediate爲true就能夠了
 
num:{
        immediate:true,
        handler:function(val){
            this.nums = val*2
        }
    }

 

咱們在回到上面的問題,用監聽器加上immediate屬性就能夠作到該效果,可是你們能夠看到的是邏輯稍稍有點複雜

watch還能夠經過實例對象直接使用:vm.$watch,返回一個取消監聽的函數,這個函數執行以後會取消監聽


咱們通常都會用到一個叫計算屬性的東西來解決:

計算屬性就是在實例配置項中經過computed來爲vm設置一個新的數據,而這個新數據會擁有一個依賴(一條已經存在的數據),當依賴發送變化的時候,新數據也會發送變化

與方法的方式相比,它性能更高,計算屬性是基於它們的依賴進行緩存的。計算屬性只有在它的相關依賴發生改變時纔會從新求值。相比之下,每當觸發從新渲染時,調用方法將總會再次執行函數。

與watch相比,寫起來簡單,邏輯性更清晰,watch通常多用於,根據數據的變化而執行某些動做,而至於這些動做是在幹什麼其實無所謂,而計算屬性更有針對性,根據數據變化而更改另外一個數據

計算屬性也擁有getter和setter,默認寫的是getter,設置setter執行能夠當此計算屬性數據更改的時候去作其餘的一些事情,至關於watch這個計算屬性
 
xm:{
        get:function(){//getter 當依賴改變後設置值的時候
            return this.xing+'丶'+this.ming
        },
        set:function(val){//setter 當自身改變後執行
            this.xing = val.split('丶')[0]
            this.ming = val.split('丶')[1]
        }
    }

 

過濾器
 
vue中能夠設置filter(過濾器)來實現數據格式化,雙花括號插值和 v-bind 表達式中使用



vue1.0的有默認的過濾器,可是在2.0的時候所有給去掉了

因此在vue中若是想要使用過濾器就須要自定義

自定義的方法有兩種:全局定義和局部定義,全局定義的過濾器在任意的實例、組件中均可以使用,局部定義就是在實例、組件中定義,只能在這個實例或組件中使用

1. 全局定義

Vue.filter(name,handler)

name是過濾器的名字,handler是數據格式化處理函數,接收的第一個參數就是要處理的數據,返回什麼數據,格式化的結果就是什麼

在模板中經過 | (管道符) 來使用,在過濾器名字後面加()來傳參,參數會在handler函數中第二個及後面的形參來接收
 
<p>{{msg | firstUpper(3,2)}}</p>

    Vue.filter('firstUpper',function (value,num=1,num2) {
        console.log(num2)
        return value.substr(0,num).toUpperCase()+value.substr(num).toLowerCase()
    })

 

2. 局部定義

在實例、組件的配置項中設置 filters,鍵名爲過濾器名,值爲handler
 
filters:{
        firstUpper:function (value,num=1,num2) {
        console.log(num2)
        return value.substr(0,num).toUpperCase()+value.substr(num).toLowerCase()
        }
    }

 

注意:

過濾器只能在mustache插值、v-bind裏使用,其餘的指令等地方都不能用

條件渲染
 
在Vue中可使用v-if來控制模板裏元素的顯示和隱藏,值爲true就顯示,爲false就隱藏

v-if控制的是是否渲染這個節點

當咱們須要控制一組元素顯示隱藏的時候,能夠用template標籤將其包裹,將指令設置在template上,等等vm渲染這一組元素的時候,不會渲染template

當有else分支邏輯的時候,能夠給該元素加上v-else指令來控制,v-else會根據上面的那個v-if來控制,效果與v-if相反,注意,必定要緊挨着

還有v-else-if指令能夠實現多分支邏輯
 
   <input type="text" v-model="mode">  
      <template  v-if="mode=='A'">
        <h1>1.title</h1>
        <p>個人第一個P標籤</p>  
      </template>
     <template  v-else-if="mode=='B'">
        <h1>2.title</h1>
        <p>個人第二個P標籤</p>
     </template>
     <template  v-else-if="mode=='C'">
        <h1>3.title</h1>
        <p>個人第三個P標籤</p>
     </template>
     <template  v-else>
       
        <p>很差意思,輸入有誤</p>
     </template>

 

須要注意的另外一個地方是:Vue 會盡量高效地渲染元素,一般會複用已有元素而不是從頭開始渲染。這樣確實能使Vue變得更快,性能更高,可是有的時候咱們須要讓實例去更新dom而不是複用,就須要給dom加上不一樣的key屬性,由於vue在判斷到底渲染什麼的時候,包括哪些dom能夠複用,都會參考key值,若是dom表現基本一致,符合複用的條件,可是key值不一樣,依然不會複用


Vue還提供了v-show指令,用法和v-if基本同樣,控制的是元素的css中display屬性,從而控制元素的顯示和隱藏 , 不能和v-else配合使用,且不能使用在template標籤上,由於template不會渲染,再更改它的css屬性也不會渲染,不會生效
 
v-if vs v-show
 
v-if 是「真正」的條件渲染,由於它會確保在切換過程當中條件塊內的事件監聽器和子組件適當地被銷燬和重建。
v-if 也是惰性的:若是在初始渲染時條件爲假,則什麼也不作——直到條件第一次變爲真時,纔會開始渲染條件塊。
相比之下,v-show 就簡單得多——無論初始條件是什麼,元素老是會被渲染,而且只是簡單地基於 CSS 進行切換。
通常來講,v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。所以,若是須要很是頻繁地切換,則使用 v-show 較好;若是在運行時條件不多改變,則使用 v-if 較好。
 
mixin
 
在Vue中,咱們能夠經過定義多個mixin來實現代碼抽離複用,便於維護,提高頁面的邏輯性

要注意的是:data屬性不要使用mixin,由於從邏輯上來講,每個實例、組件的數據都應該是獨立的

一個mixin其實就是一個純粹的對象,上面掛載着抽離出來的配置,在某一個實例中,經過mixins選項(數組)導入後,此實例就擁有導入的mixin的配置

且導入的配置不會覆蓋原有的,而是合併到一塊兒
 
虛擬dom
 
頻繁且複雜的dom操做一般是前端性能瓶頸的產生點,Vue提供了虛擬dom的解決辦法

虛擬的DOM的核心思想是:對複雜的文檔DOM結構,提供一種方便的工具,進行最小化地DOM操做。這句話,也許過於抽象,卻基本概況了虛擬DOM的設計思想

(1) 提供一種方便的工具,使得開發效率獲得保證
(2) 保證最小化的DOM操做,使得執行效率獲得保證


也就是說,虛擬dom的框架/工具都是這麼作的:

1. 根據現有的真實dom來生成一個完整的虛擬dom樹結構
2. 當數據變化,或者說是頁面須要從新渲染的時候,會從新生成一個新的完整的虛擬dom
3. 拿新的虛擬dom來和舊的虛擬dom作對比(使用diff算法),。獲得須要更新的地方以後,更新內容

這樣的話,就能大量減小真實dom的操做,提升性能
 
組件化
模塊化就是將系統功能分離成獨立的功能部分的方法,通常指的是單個的某一種東西,例如js、css

而組件化針對的是頁面中的整個完整的功能模塊劃分,組件是一個html、css、js、image等外鏈資源,這些部分組成的一個聚合體

優勢:代碼複用,便於維護

劃分組件的原則:具備大量的佈局結構的,或者是獨立的邏輯的,都應該分紅組件

組件應該擁有的特性:可組合,可重用,可測試,可維護
 
組件
 
在vue中,咱們經過Vue.extend來建立Vue的子類,這個東西其實就是組件

也就是說Vue實例和組件的實例有差異可是差異不帶,由於畢竟一個是父類一個是子類

通常的應用,會擁有一個根實例,在根實例裏面都是一個一個的組件

由於組件是要嵌入到實例或者父組件裏的,也就是說,組件能夠互相嵌套,並且,全部的組件最外層必須有一個根實例,因此組件分爲:全局組件和局部組件

全局組件在任意的實例、父級組件中都能使用,局部組件只能在建立本身的父級組件或者實例中使用

組件經過不一樣的註冊方法成爲全局、局部組件

建立組件:
 
Vue.extend(options)

  

全局註冊:
 
  var App = Vue.extend({
        template:"<h1>hello world</h1>"
    })
    Vue.component('my-app',App)

  

簡便寫法:
 
  // 建立組件構造器和註冊組件合併一塊兒  
    Vue.component('hello',{//Vue會自動的將此對象給Vue.extend
        template:"<h1>hello</h1>"
    })

  

組件經過template來肯定本身的模板,template裏的模板必須有根節點,標籤必須閉合

組件的屬性掛載經過:data方法來返回一個對象做爲組件的屬性,這樣作的目的是爲了每個組件實例都擁有獨立的data屬性

局部註冊:
 
 
  new Vue({
        el:"#app",
        components:{
            'my-app':App
        }
    })

  

簡便寫法
 
 data:{},
    components:{
        'hello':{
            template:"<h1>asdasdasdasdasdas</h1>"
        }
    }

  

在實例或者組件中註冊另外一個組件,這個時候,被註冊的組件只能在註冊它的實例或組件的模板中使用,一個組件能夠被多個組件或實例註冊
 
注意瀏覽器規則
 
由於vue在解析模板的時候會根據某些html的規則,例如,在table裏只能放tr,td,th..,若是放入組件不會解析 這個時候咱們能夠放入tr使用is方式來標識這個tr實際上是組件
 
<table id="app">
    <tr is="hello"></tr>
</table>

  

template
 
咱們能夠在html的某個地方經過template標籤來定義組件的模板,在組件的template屬性中經過選擇器指定對應的template標籤內容就能夠了,注意,須要給template標籤加id來指定
 
<template id="my-hello">
    <div>
        <h1>hello world</h1>
        <p>hahahah</p>
    </div>
</template>
//組件中
template:"#my-hello"

  

is切換
 
在實例、組件的模板中的某一個標籤上,能夠經過is屬性來指定爲另外一個目標的組件,這個時候咱們通常會使用component標籤來佔位、設置is屬性來指定目標組件
 
<component :is="type"></component>

//組件中
data:{
    type:'aaa'
},
components:{
    'aaa':{template:"<h1>AAAAAAAAAAAAA</h1>"},
    'bbb':{template:"<h1>BBBBBBBBBBBBB</h1>"}
}

  

組件嵌套
 
應用中劃分的組件可能會不少,爲了更好的實現代碼複用,因此必然會存在組件的嵌套關係

組件設計初衷就是要配合使用的,最多見的就是造成父子組件的關係:組件 A 在它的模板中使用了組件 B。
 
 
prop 傳遞數據
 
組件實例的做用域是孤立的,父組件不能直接使用子組件的數據,子組件也不能直接使用父組件的數據

父組件在模板中使用子組件的時候能夠給子組件傳遞數據
 
 
<bbb money="2"></bbb>

  

子組件須要經過props屬性來接收後才能使用
 
 
'bbb':{
    props:['money']
}

  

若是父組件傳遞屬性給子組件的時候鍵名有'-',子組件接收的時候寫成小駝峯的模式
 
 
<bbb clothes-logo='amani' clothes-price="16.58"></bbb>
    
props:['clothesLogo','clothesPrice']

  

咱們能夠用 v-bind 來動態地將 prop 綁定到父組件的數據。每當父組件的數據變化時,該變化也會傳導給子組件
 
 
單向數據流
 
Prop 是單向綁定的:當父組件的屬性變化時,將傳導給子組件,可是反過來不會。這是爲了防止子組件無心間修改了父組件的狀態,來避免應用的數據流變得難以理解。

另外,每次父組件更新時,子組件的全部 prop 都會更新爲最新值。這意味着你不該該在子組件內部改變 prop。若是你這麼作了,Vue 會在控制檯給出警告。

在兩種狀況下,咱們很容易忍不住想去修改 prop 中數據:

1. Prop 做爲初始值傳入後,子組件想把它看成局部數據來用;

2. Prop 做爲原始數據傳入,由子組件處理成其它數據輸出。
 
 
對這兩種狀況,正確的應對方式是:

定義一個局部變量,並用 prop 的值初始化它:
 
props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}
//定義一個計算屬性,處理 prop 的值並返回:
props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

  

注意在 JavaScript 中對象和數組是引用類型,指向同一個內存空間,若是 prop 是一個對象或數組,在子組件內部改變它會影響父組件的狀態。
 
 
prop驗證
 
咱們能夠爲組件的 prop 指定驗證規則。若是傳入的數據不符合要求,Vue 會發出警告。這對於開發給他人使用的組件很是有用

驗證主要分爲:類型驗證、必傳驗證、默認值設置、自定義驗證
 
 
props:{
    //類型驗證:
    str:String,
    strs:[String,Number],
    //必傳驗證
    num:{
        type:Number,
        required:true
    },
    //默認數據
    bool:{
        type:Boolean,
        // default:true,
        default:function(){

            return true
        }
    },
    //自定義驗證函數
    nums:{
        type:Number,
        validator: function (value) {
            return value %2 == 0
        }
    }
}

當父組件傳遞數據給子組件的時候,子組件不接收,這個數據就會掛載在子組件的模板的根節點上

  

slot
 
vue裏提供了一種將父組件的內容和子組件的模板整合的方法:內容分發,經過slot插槽來實現
 
 
1. 匿名插槽
 
<aaa>abc</aaa>

template:"<h1><slot></slot></h1>"
 
在父組件中使用子組件的時候,在子組件標籤內部寫的內容,在子組件的模板中能夠經過<slot></slot>來使用

 

2. 具名插槽

父組件在子組件標籤內寫的多個內容咱們能夠給其設置slot屬性來命名,在子組件的模板經過經過使用帶有name屬性的slot標籤來放置對應的slot,當slot不存在的時候,slot標籤內寫的內容就出現
 
<my-button>提交</my-button>
<my-button>重置</my-button>
<my-button></my-button>

template:"<button><slot>按鈕</slot></button>"

  

transition
 
Vue提供了transition組件來幫助咱們實現過渡效果,依據就是在控制元素顯示隱藏的時候爲dom在指定的時刻添加上對應的類名

而咱們只要在這些類名裏寫上對應的css樣式

在進入/離開的過渡中,會有 6 個 class 切換(v表明的是transition的name屬性的值)。

v-enter:定義進入過渡的開始狀態。在元素被插入時生效,在下一個幀移除。

v-enter-active:定義過渡的狀態。在元素整個過渡過程當中做用,在元素被插入時生效,在 transition/animation 完成以後移除。這個類能夠被用來定義過渡的過程時間,延遲和曲線函數。

v-enter-to: 2.1.8版及以上 定義進入過渡的結束狀態。在元素被插入一幀後生效 (於此同時 v-enter 被刪除),在 transition/animation 完成以後移除。

v-leave: 定義離開過渡的開始狀態。在離開過渡被觸發時生效,在下一個幀移除。

v-leave-active:定義過渡的狀態。在元素整個過渡過程當中做用,在離開過渡被觸發後當即生效,在 transition/animation 完成以後移除。這個類能夠被用來定義過渡的過程時間,延遲和曲線函數。

v-leave-to: 2.1.8版及以上 定義離開過渡的結束狀態。在離開過渡被觸發一幀後生效 (於此同時 v-leave 被刪除),在 transition/animation 完成以後移除。
 
![className](https://cn.vuejs.org/images/transition.png)

若是有多個元素須要用transition-group包裹,而且須要有key值作標記

animate.css:

引入animate.css以後,按照下面的寫法:
 
<transition
    leave-active-class="animated fadeOut"
    enter-active-class="animated slideInLeft">
        <p v-if="isShow" class="box"></p>
</transition>

  

渲染函數和jsx
 
在vue中咱們能夠不用template來指定組件的模板,而是用render函數來建立虛擬dom結構,用這種方法優勢就是性能高,缺點就是使用成本高,代碼可讀性較低,可使用jsx來在render函數中建立,這樣既提升了性能,又減小了成本

可是,咱們在使用了vue-cli腳手架以後,由於腳手架中有對template標籤轉換虛擬dom的處理,因此,不須要使用jsx,咱們也能高效的轉換爲createElement形式

  

Vue裏組件的通訊
 
通訊:傳參、控制、數據共享(A操控B作一個事件)

模式:父子組件間、非父子組件
 
1. 父組件能夠將一條數據傳遞給子組件,這條數據能夠是動態的,父組件的數據更改的時候,子組件接收的也會變化

子組件被動的接收父組件的數據,子組件不要再更改這條數據了


2. 父組件若是將一個引用類型的動態數據傳遞給子組價的時候,數據會變成雙向控制的,子組件改數據的時候父組件也能接收到數據變化,由於子組件改的時候不是在改數據,而是在改數據裏的內容,也就是說引用類型數據的地址始終沒有變化,不算改父組件數據

父子間數據共享(雙向控制)

3. 父組件能夠將一個方法傳遞給子組件,子組件調用這個方法的時候,就能夠給父組件傳遞數據

父組件被動的接收子組件的數據

4. 父組件能夠將一個事件綁定在子組件的身上,這個事件的處理程序是父組件某一個方法,當子組件觸發本身的這個被綁定的事件的時候,至關於觸發了父組件的方法

父組件被動的接收子組件的數據


5. 在組件間能夠用過ref造成ref鏈,組件還擁有一個關係鏈($parent,$children,$root),經過這兩種鏈;理論來講,任意的兩個組件均可以互相訪問,互相進行通訊

任意組件通訊,用的少...


6. event bus 事件總線 小天使 專一於非父子組件的通訊,其實父子組件也可使用,只是沒有必要

在B組件的某個鉤子函數爲event_bus綁定一個事件,事件的處理程序是B想作的事情

在A組件的某一個操做裏,觸發event_bus綁定的事件


7. 大量組件間數據共享的時候 vuex
 
 
組件的生命週期
 
每個組件或者實例都會經歷一個完整的生命週期,總共分爲三個階段:初始化、運行中、銷燬

![生命週期圖示](https://cn.vuejs.org/images/lifecycle.png)

1. 實例、組件經過new Vue() 建立出來以後會初始化事件和生命週期,而後就會執行beforeCreate鉤子函數,這個時候,數據尚未掛載ね,只是一個空殼,沒法訪問到數據和真實的dom,通常不作操做

2. 掛載數據,綁定事件等等,而後執行created函數,這個時候已經可使用到數據,也能夠更改數據,在這裏更改數據不會觸發updated函數,在這裏能夠在渲染前倒數第二次更改數據的機會,不會觸發其餘的鉤子函數,通常能夠在這裏作初始數據的獲取

3. 接下來開始找實例或者組件對應的模板,編譯模板爲虛擬dom放入到render函數中準備渲染,而後執行beforeMount鉤子函數,在這個函數中虛擬dom已經建立完成,立刻就要渲染,在這裏也能夠更改數據,不會觸發updated,在這裏能夠在渲染前最後一次更改數據的機會,不會觸發其餘的鉤子函數,通常能夠在這裏作初始數據的獲取

4. 接下來開始render,渲染出真實dom,而後執行mounted鉤子函數,此時,組件已經出如今頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了,能夠在這裏操做真實dom等事情...

5. 當組件或實例的數據更改以後,會當即執行beforeUpdate,而後vue的虛擬dom機制會從新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比以後從新渲染,通常不作什麼事兒

6. 當更新完成後,執行updated,數據已經更改完成,dom也從新render完成,能夠操做更新後的虛擬dom

7. 當通過某種途徑調用$destroy方法後,當即執行beforeDestroy,通常在這裏作一些善後工做,例如清除計時器、清除非指令綁定的事件等等

8. 組件的數據綁定、監聽...去掉後只剩下dom空殼,這個時候,執行destroyed,在這裏作善後工做也能夠
 
 
vue-cli腳手架
 
如今使用前端工程化開發項目是主流的趨勢,也就是說,咱們須要使用一些工具來搭建vue的開發環境,通常狀況下咱們使用webpack來搭建,在這裏咱們直接使用vue官方提供的,基於webpack的腳手架工具:vue-cli

安裝方法:
 
全局安裝 vue-cli
npm install --global vue-cli
建立一個基於 webpack 模板的新項目
vue init webpack my-project
//init以後能夠定義模板的類型
安裝依賴,走你
cd my-project
npm install
npm run dev

  

模板類型:

simple 對應的是一個超級簡單的html文件

webpack 在配置的時候能夠選擇是否須要vue-router

注意的是,模板建立的時候會詢問使用須要使用ESLINT來標準化咱們的代碼

在腳手架中,開發目錄是src文件夾,build負責打包的,config是負責配置(內置服務器的端口、proxy代理),static是靜態目錄,test是測試

src中main.js是入口文件,在裏面建立了一個根實例,根實例的模板就是根組件App的模板,其餘的組件都在根組件裏面進行嵌套實現。

每個組件都是一個單文件組件,這種文件會被webpack利用vue-loader的工具進行編譯

template部分負責寫組件的模板內容,script中建立組件。style裏寫組件的樣式

assets目錄也是靜態目錄,在這個目標中的文件咱們使用相對路徑引入,而static目錄中的文件使用絕對地址來引入

在style上添加scoped能使這個style裏的樣式只做用於當前的組件,不加scoped就是全局樣式

習慣於在App.vue根組件的style裏寫全局樣式,而每一個組件的style最好都是局部的


配置sass編譯環境

vue-cli沒有內置sass編譯,咱們須要本身修改配置
 
 
1. 下載對應工具:node-sass sass-loader

2. 在build目錄下的webpack.base.conf.js中的module.rule裏添加以下配置
 
{
    test: /\.scss$/,
    loader:'style-loader!css-loader!sass-loader'
}

  

3. 在須要使用scss代碼的組件的style標籤中添加 lang='scss'
 
vue-router
 
如今的應用都流行SPA應用(single page application)

傳統的項目大多使用多頁面結構,須要切換內容的時候咱們每每會進行單個html文件的跳轉,這個時候受網絡、性能影響,瀏覽器會出現不定時間的空白界面,用戶體驗很差

單頁面應用就是用戶經過某些操做更改地址欄url以後,動態的進行不一樣模板內容的無刷新切換,用戶體驗好。

Vue中會使用官方提供的vue-router插件來使用單頁面,原理就是經過檢測地址欄變化後將對應的路由組件進行切換(卸載和安裝)
 
簡單路由實現:
 
1. 引入vue-router,若是是在腳手架中,引入VueRouter以後,須要經過Vue.use來註冊插件
 
 import Vue from 'vue'
  import Router from 'vue-router'
  Vue.use(Router)

  

2. 建立router路由器
 
new Router(options)

  

3. 建立路由表並配置在路由器中
 
var routes = [
   {path,component}//path爲路徑,component爲路徑對應的路由組件
 ]

 new Router({
     routes
 })

  

4. 在根實例裏注入router,目的是爲了讓全部的組件裏都能經過this.$router、this.$route來使用路由的相關功能api
 
new Vue({
    el: '#app',
    router,
    template: '<App/>',
    components: { App }
})

  

5. 利用router-view來指定路由切換的位置

6. 使用router-link來建立切換的工具,會渲染成a標籤,添加to屬性來設置要更改的path信息,且會根據當前路由的變化爲a標籤添加對應的router-link-active類名
 
<router-link to="main">main</router-link>
<router-link to="news">news</router-link>
.router-link-active{
    color:red;
}

  

多級路由:
 
在建立路由表的時候,能夠爲每個路由對象建立children屬性,值爲數組,在這個裏面又能夠配置一些路由對象來使用多級路由,注意:一級路由path前加'/'
 
const routes = [
  {path:'/main',component:AppMain},
  {path:'/news',component:AppNews,children:[
    {path:'inside',component:AppNewsInside},
    {path:'outside',component:AppNewsOutside}
  ]},
]

  

二級路由組件的切換位置依然由router-view來指定(指定在父級路由組件的模板中)
 
<router-link to='inside'>inside</router-link>
<router-link to='outside'>outside</router-link>

<router-view></router-view>

  

默認路由和重定向:
 
當咱們進入應用,默認像顯示某一個路由組件,或者當咱們進入某一級路由組件的時候想默認顯示其某一個子路由組件,咱們能夠配置默認路由:
 
{path:'',component:'/main'}

  

當咱們須要進入以後進行重定向到其餘路由的時候,或者當url與路由表不匹配的時候:
 
{path:'',redirect:'/main'}

{path:'**',redirect:'/main'}

  

命名路由
 
咱們能夠給路由對象配置name屬性,這樣的話,咱們在跳轉的時候直接寫name:main就會快速的找到此name屬性對應的路由,不須要寫大量的urlpath路徑了
 
動態路由匹配
 
有的時候咱們須要在路由跳轉的時候跟上參數,路由傳參的參數主要有兩種:路徑參數、queryString參數

路由參數須要在路由表裏設置
 
{path:'/user/:id',component:User}

  

上面的代碼就是給User路由配置接收id的參數,多個參數繼續在後面設置

在組件中能夠經過this.$route.params來使用

queryString參數不須要在路由表設置接收,直接設置?後面的內容,在路由組件中經過this.$route.query接收
 
router-link
 
<router-link> 組件支持用戶在具備路由功能的應用中(點擊)導航。 經過 to 屬性指定目標地址,默認渲染成帶有正確連接的 <a> 標籤,能夠經過配置 tag 屬性生成別的標籤.。另外,當目標路由成功激活時,連接元素自動設置一個表示激活的 CSS 類名。

router-link的to屬性,默認寫的是path(路由的路徑),能夠經過設置一個對象,來匹配更多
 
:to='{name:"detail",params:{id:_new.id},query:{content:_new.content}}'

  

name是要跳轉的路由的名字,也能夠寫path來指定路徑,可是用path的時候就不能使用params傳參,params是傳路徑參數,query傳queryString參數

replace屬性能夠控制router-link的跳轉不被記錄\

active-class屬性能夠控制路徑切換的時候對應的router-link渲染的dom添加的類名
 
編程式導航
 
有的時候須要在跳轉前進行一些動做,router-link直接跳轉,須要在方法裏使用$router的方法
 
router.push = router-link:to
router.replace = router-link:to.replace
router.go() = window.history.go

  

路由模式
 
路由有兩種模式:hash、history,默認會使用hash模式,可是若是url裏不想出現醜陋hash值,在new VueRouter的時候配置mode值爲history來改變路由模式,本質使用H5的histroy.pushState方法來更改url,不會引發刷新,可是須要後端進行路由的配置
 
路由鉤子
 
在某些狀況下,當路由跳轉前或跳轉後、進入、離開某一個路由前、後,須要作某些操做,就可使用路由鉤子來監聽路由的變化

全局路由鉤子:
 
router.beforeEach((to, from, next) => {
    //會在任意路由跳轉前執行,next必定要記着執行,否則路由不能跳轉了
  console.log('beforeEach')
  console.log(to,from)
  
  next()
})

router.afterEach((to, from) => {
    //會在任意路由跳轉後執行
  console.log('afterEach')
})

  

單個路由鉤子:
只有beforeEnter,在進入前執行,to參數就是當前路由
 
routes: [
    {
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...
      }
    }
  ]

  

路由組件鉤子:
 
beforeRouteEnter (to, from, next) {
    // 在渲染該組件的對應路由被 confirm 前調用
    // 不!能!獲取組件實例 `this`
    // 由於當守衛執行前,組件實例還沒被建立
  },
  beforeRouteUpdate (to, from, next) {
    // 在當前路由改變,可是該組件被複用時調用
    // 舉例來講,對於一個帶有動態參數的路徑 /foo/:id,在 /foo/1 和 /foo/2 之間跳轉的時候,
    // 因爲會渲染一樣的 Foo 組件,所以組件實例會被複用。而這個鉤子就會在這個狀況下被調用。
    // 能夠訪問組件實例 `this`
  },
  beforeRouteLeave (to, from, next) {
    // 導航離開該組件的對應路由時調用
    // 能夠訪問組件實例 `this`
  }

  

命名視圖
 
有時候想同時(同級)展現多個視圖,而不是嵌套展現,例如建立一個佈局,有 sidebar(側導航) 和 main(主內容) 兩個視圖,這個時候命名視圖就派上用場了。你能夠在界面中擁有多個單獨命名的視圖,而不是隻有一個單獨的出口。若是 router-view 沒有設置名字,那麼默認爲 default。
 
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

  

一個視圖使用一個組件渲染,所以對於同個路由,多個視圖就須要多個組件。確保正確使用 components 配置(帶上 s)
 
const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,//默認的,沒有name的router-view
        a: Bar,
        b: Baz
      }
    }
  ]
})

  

prop將路由與組件解耦
 
在組件中接收路由參數須要this.$route.params.id,代碼冗餘,如今能夠在路由表裏配置props:true
 
{path:'detail/:id',component:AppNewsDetail,name:'detail',props:true}

  

在路由本身中能夠經過props接收id參數去使用了

props:['id']
 
Axios 數據交互工具
 
vue官方宣佈在2.0版本中再也不對Vue-resource進行維護了,推薦使用axios工具

注意,axios默認配置不會設置session-cookie,須要進行配置

axios.defaults.withCredentials = true

詳細請看[文檔](https://www.kancloud.cn/yunye/axios/234845)
 
 
響應式原理
 
由於vue是mvvm的框架,因此當數據變化的時候,視圖會當即更新,視圖層產生操做後會自動通知vm來更改model,因此咱們能夠實現雙向數據綁定,而其中的原理就是實例會將設置的data逐個遍歷利用Object.defineProperty給數據生成getter和setter,當數據變化地方時候setter會監聽到而且通知對應的watcher工具進行邏輯運算會更新視圖

vuex借鑑了flux和redux的思想,可是flux和redux是獨立且完整的架構,vuex是耦合與vue框架的,因此使用成本要比flux、redux低
 
聲明式渲染
 
在vue中,咱們能夠先在vue實例中聲明數據,而後經過{{}}等方式渲染在dom中
 
Vuex
 
Vuex是vue官方的一款狀態管理工具,什麼是狀態呢?咱們在前端開發中有一個概念:數據驅動,頁面中任意的顯示不一樣,都應該有一條數據來控制,而這條數據又叫作state,狀態。

在vue中。組件間進行數據傳遞、通訊很頻繁,而父子組件和非父子組件的通訊功能也比較完善,可是,惟一困難的就是多組件間的數據共享,這個問題由vuex來處理
 
Vuex的使用
 
1. 建立store:
 
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)


//能夠設置store管理的state/getter,mutations,actions
const store = new Vuex.Store({

})

  

2. 設置state

state就是一個純對象,上面有一些狀態掛載,並且一個應用應該只有一個數據源:單一狀態樹、惟一數據源
 
import state from './modules/state'
//能夠設置store管理的state/getter,mutations,actions
const store = new Vuex.Store({
    state
})

  

3. 在根實例裏配置store
這樣,咱們就能夠在任意的組件中經過this.$store來使用關於store的api
 
import store from './store'
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App }
})

  

4. 在組件中使用state

由於在組件中能夠經過this.$store來訪問store,因此咱們也能夠經過this.$store.state來使用state中管理的數據
 
 
data(){
    return {
        num:this.$store.state.num
    }
}

  

可是咱們發現,這樣使用的話,當state的數據更改的時候,vue組件並不會從新渲染,不會觸發組件的相關生命週期函數

也就是說,若是想要在組件中響應式的使用的時候,咱們須要經過計算屬性(computed)來使用
 
computed:{
    num(){
        return this.$store.state.num
    }
}

  

這樣的寫法很無趣,並且若是使用的狀態較多會產生冗餘的感受,因此vuex提供了mapState輔助函數,幫助咱們在組件中獲取並使用vuex的store中保存的狀態

因此咱們能夠這樣寫:
 
computed:mapState(['num'])

  

可是若是組件中已經有了num這個數據了,而state中的數據名字也叫num就會照成衝突,這個時候咱們能夠在組件使用state的時候,給狀態起個別名:
 
computed:mapState({
    // _num:'num',//鍵名爲別名,值字符串表明的是真正的狀態
    _num(state){//方法名爲別名,函數體裏還能夠對真正的狀態作出一些處理
        return state.num
    }
})

  

可是,有的時候咱們在組件中還有本身的業務邏輯須要用到計算屬性:
 
computed:{
    a(){
        return num+1
    },
    ...mapState({
        // _num:'num',//鍵名爲別名,值字符串表明的是真正的狀態
        _num(state){//方法名爲別名,函數體裏還能夠對真正的狀態作出一些處理
            return state.num
        }
    }),
}

  

5. getters
 
有的時候,咱們須要根據state中的某一個狀態派生出一個新的狀態,例如,咱們state中有一個num,在某些組件中須要用到是num的二倍的一個狀態,咱們就能夠經過getters來建立
 
const getters = {
    doublenum(state){
        return state.num*2
    }
}

  

建立了以後,在組件中經過this.$store.getters來獲取裏面的數據

固然vuex也提供了mapGetters輔助函數來幫助咱們在組件中使用getters裏的狀態,且,使用的方法和mapState如出一轍
 
 
5. 使用mutations更改state
 
咱們不能直接在組件中更改state:this.$store.state.num=2,而是須要使用mutations來更改,mutations也是一個純對象,裏面包含不少更改state 的方法,這些方法的形參接收到state,在函數體裏更改,這時,組件用到的數據也會更改,實現響應式。

可是咱們也不能直接調用mutations 的方法,須要使用this.$store.commit來調用,第一個參數爲調用的方法名,第二げ參數爲傳遞參數
 
const mutations = {
    increment(state){
        state.num++
    }
}
 
vuex提供了mapMutations方法來幫助咱們在組件中調用mutations 的方法,使用方法和mapState、mapGetters同樣

 

6. 使用actions來處理異步操做

更改state的時候須要調用mutations,可是mutations中的函數不能出現異步的動做,由於這樣會致使mutations維護困難,由於mutations應該是純粹的,只是作一些更改state的動做的一個工具,不要在其中加入一些其餘的相關異步動做

Action 相似於 mutation,不一樣在於:

Action 提交的是 mutation,而不是直接變動狀態。
Action 能夠包含任意異步操做。

也就是說,若是有這樣的需求:在一個異步處理以後,更改狀態,咱們在組件中應該先調用actions,來進行異步動做,而後由actions調用mutation來更改數據

 

const actions = {
    [CHANGE_NUM]({commit}){
        alert(1)
        setTimeout(() => {
            let num = Math.floor(Math.random()*10)
            //調用mitations的方法

            commit(CHANGE_NUM,num)
        }, 1000);
    }
}

  

如上,actions的方法中能夠進行異步的動做,且形參會接收store,從中取出commit方法用以調用mutations的方法

在組件中經過this.$store.dispatch方法調用actions的方法

固然也可使用mapMutations來輔助使用


組件使用數據且經過異步動做更改數據的一系列事情:

1.生成store,設置state
2.在根實例中注入store
3.組件經過計算屬性或者mapState來使用狀態
4.用戶產生操做,調用actions的方法,而後進行異步動做
5.異步動做以後,經過commit調用mutations的方法
6.mutations方法被調用後,更改state
7.state中的數據更新以後,計算屬性從新執行來更改在頁面中使用的狀態
8.組件狀態被更改...建立新的虛擬dom......
9.組件的模板更新以後從新渲染在dom中

 

自定義指令
 
在實現回到頂部功能的時候,咱們寫了一個backTop組件,接下來須要經過監聽window.scroll事件來控制這個組件顯示隱藏

由於可能會有其餘的組件會用到這樣的邏輯,因此將此功能作成一個自定義指令:

根據滾動的距離控制一個數據爲true仍是爲false(v-scroll-show)

問題:

惟一須要注意的是,在指令的鉤子函數中咱們能夠訪問到el,也就是使用指令的標籤,可是咱們不能直接更改value(指令的值所表明的數據)

因此咱們使用引用類型來進行地址的傳遞來解決這個問題

接下來有寫了一個v-back-top指令,就是將回到頂部功能作成一個指令,哪一個組件或者dom須要使用到回到頂部,就加上這個指令就能夠,設置不一樣的參數來控制在不一樣的狀況下觸發
 
Vue的組件庫
 
組件庫就是通用組件的集合

pc:element-ui iview

mobile: mint-ui

##### keep-alive

在component組件、router-view外面包裹上keep-alive的話,就會對組件進行緩存,當切換回來的時候,組件會當即渲染,理論來講,切換組件的時候其實會把上一個組件銷燬,使用了keep-alive則不會

設置include、exclude屬性控制有選擇的緩存

include匹配到的組件會被緩存,exclude匹配到的不會被緩存

值能夠爲逗號隔開的字符串include = 'a,b';正則:include = '/a|b/';數組:include=['a','b']

 

進入域後根據不一樣的狀況顯示不一樣的頁面(PC/MOBILE)

 

不少狀況下,一個應用會有PC和移動端兩個版本,而這兩個版本由於差異大,內容多,因此不能用響應式開發可是單獨開發,而域名只有一個,用戶進入域後直接返回對應設備的應用,作法主要有兩種:

1. 前端判斷並跳轉

進入一個應用或者一個空白頁面後,經過navigator.userAgent來判斷用戶訪問的設備類型,進行跳轉

2. 後端判斷並響應對應的應用

用戶地址欄進入域的時候,服務器能接收到請求頭上包含的userAgent信息,判斷以後返回對應應用

 

 function foo(){// 第16行
        getName = function(){console.log(1)}
        return this
    }
    foo.getName = function(){console.log(2)}
    foo.prototype.getName = function(){console.log(3)}
    var getName = function(){console.log(4)}
    function getName(){console.log(5)}


    foo.getName()//2
    //foo是一個函數,也能夠說是一個對象,因此它也能夠掛載一些屬性和方法,18行在其上掛載了一個getName方法
    //執行的結果是
    
    getName()//4
    //21行有一個全局函數,全局函數聲明提早後被20行的getName覆蓋,因此輸出4

    foo().getName()//1
    //foo()執行完成後,將全局的getName也就是window.getName給更改後返回this,而在這裏this執行的就是window,因此最後執行的就是window.getName,因此輸出1

    getName()//1
    //在上面已經更改全局的getName,因此依然是1

    new foo.getName()//2
    //new 操做符在實例化構造器的時候,會執行構造器函數,也就是說,foo.getName會執行,輸出2

    new foo().getName()//3
    //new操做符的優先級較高,因此會先new foo()獲得一個實例,而後再執行實例的getName方法,這個時候,實例的構造器裏沒有getName方法,就會執行構造器原型上的getName方法

    new new foo().getName()//3
    //先執行new foo()獲得一個實例,而後在new 這個實例的getName方法,這個時候會執行這個方法,因此輸出3

    //除了本地對象的方法,其餘的函數都能new
相關文章
相關標籤/搜索