vue大筆記

Vue

Vue是一個前端js框架,由尤雨溪開發,是個人項目

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的功能劃分為如下幾點:

渲染數據

操作dom(寫一些效果)

操作cookie等存儲機制api

在前端開發中,如何高效的操作dom、渲染數據是一個前端工程師需要考慮的問題,而且當數據量大,流向較亂的時候,如何正確使用數據,操作數據也是一個問題

而js框架對上述的幾個問題都有自己趨于完美的解決方案,開發成本降低。高性能高效率。唯一的缺點就是需要使用一定的成本來學習。

Vue官網介紹

vue是漸進式JavaScript框架

vue的主張較弱

“漸進式框架”和“自底向上增量開發的設計”是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

阮大神博客

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

這是純純的MVC的模式,但是很多框架都會有一些更改

前端mvc框架,如angularjs,backbone:

會發現,用戶可以直接操作controller(例如用戶更改hash值,conrtoller直接監聽hash值變化后執行邏輯代碼,然后通知model更改)

控制器可以直接操作view,如果,讓某一個標簽獲得進入頁面獲得焦點,不需要model來控制,所以一般會直接操作(angularJS,指令)

view可以直接操作model (數據雙向綁定)

MVP:

mvp

view和model不能直接通信,所有的交互都由presenter來做,其他部分的通信都是雙向的

view較薄 ,presenter較為厚重

MVVM:

mvvm

MVVM和MVP及其相似,只是view和viewmodel的通信是雙向綁定,view的操作會自動的像viewmodel通過

v-for

這是一個指令,只要有v-的就是指令(directive 操作dom )

在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 有幾個好處:

掃一眼 HTML 模板便能輕松定位在 JavaScript 代碼里對應的方法。

因為你無須在 JavaScript 里手動綁定事件,你的 ViewModel 代碼可以是非常純粹的邏輯,和 DOM 完全解耦,更易于測試。

當一個 ViewModel 被銷毀時,所有的事件處理器都會自動被刪除。你無須擔心如何自己清理它們。

模板語法

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

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

使用v-html指令可以解析html格式的數據

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

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

防止表達式閃爍:

v-cloak

給模板內的元素添加v-cloak屬性后,元素在vue沒有加載完的時候就有這個屬性,當vue加載完成后這個屬性就消失了,所以我們可以給這個屬性設置css樣式為隱藏

? ? <style>

? ? [v-cloak]{

? ? ? ? visibility: hidden;

? ? }

? ? </style>

v-text/v-html

v-text會指定將模板內元素的textContent屬性替換為指令值所代表的數據,也可以用于防止閃爍 v-html可以解析標簽,更改元素的innerHTML,性能比v-text較差

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中如果想要使用過濾器就需要自定義

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

全局定義

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()

? ? })

局部定義

在實例、組件的配置項中設置 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里使用,其他的指令等地方都不能用

作業:自定義類似于angularJS中的currency、order、filter過濾器

條件渲染

在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的框架/工具都是這么做的:

根據現有的真實dom來生成一個完整的虛擬dom樹結構

當數據變化,或者說是頁面需要重新渲染的時候,會重新生成一個新的完整的虛擬dom

拿新的虛擬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 中數據:

Prop 作為初始值傳入后,子組件想把它當作局部數據來用;

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插槽來實現

匿名插槽

<aaa>abc</aaa>

template:"<h1><slot></slot></h1>"

在父組件中使用子組件的時候,在子組件標簽內部寫的內容,在子組件的模板中可以通過來使用

具名插槽

父組件在子組件標簽內寫的多個內容我們可以給其設置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 完成之后移除。

如果有多個元素需要用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做一個事件)、數據共享

模式:父子組件間、非父子組件

父組件可以將一條數據傳遞給子組件,這條數據可以是動態的,父組件的數據更改的時候,子組件接收的也會變化

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

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

父子間數據共享(雙向控制),基本不會使用,違背了單向數據流

父組件可以將一個方法傳遞給子組件,子組件調用這個方法的時候,就可以給父組件傳遞數據

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

父組件可以將一個事件綁定在子組件的身上,這個事件的處理程序是父組件某一個方法,當子組件觸發自己的這個被綁定的事件的時候,相當于觸發了父組件的方法

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

在組件間可以用過ref形成ref鏈,組件還擁有一個關系鏈($parent,$children,$root),通過這兩種鏈;理論來說,任意的兩個組件都可以互相訪問,互相進行通信

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

event bus 事件總線 小天使 專注于非父子組件的通信,其實父子組件也可以使用,只是沒有必要

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

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

大量組件間數據共享的時候 vuex

組件的生命周期

每一個組件或者實例都會經歷一個完整的生命周期,總共分為三個階段:初始化、運行中、銷毀

實例、組件通過new Vue() 創建出來之后會初始化事件和生命周期,然后就會執行beforeCreate鉤子函數,這個時候,數據還沒有掛載ね,只是一個空殼,無法訪問到數據和真實的dom,一般不做操作

掛載數據,綁定事件等等,然后執行created函數,這個時候已經可以使用到數據,也可以更改數據,在這里更改數據不會觸發updated函數,在這里可以在渲染前倒數第二次更改數據的機會,不會觸發其他的鉤子函數,一般可以在這里做初始數據的獲取

接下來開始找實例或者組件對應的模板,編譯模板為虛擬dom放入到render函數中準備渲染,然后執行beforeMount鉤子函數,在這個函數中虛擬dom已經創建完成,馬上就要渲染,在這里也可以更改數據,不會觸發updated,在這里可以在渲染前最后一次更改數據的機會,不會觸發其他的鉤子函數,一般可以在這里做初始數據的獲取

接下來開始render,渲染出真實dom,然后執行mounted鉤子函數,此時,組件已經出現在頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了,可以在這里操作真實dom等事情...

當組件或實例的數據更改之后,會立即執行beforeUpdate,然后vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比之后重新渲染,一般不做什么事兒

當更新完成后,執行updated,數據已經更改完成,dom也重新render完成,可以操作更新后的虛擬dom

當經過某種途徑調用$destroy方法后,立即執行beforeDestroy,一般在這里做一些善后工作,例如清除計時器、清除非指令綁定的事件等等

組件的數據綁定、監聽...去掉后只剩下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編譯,我們需要自己修改配置

下載對應工具:node-sass(4.0.0) sass-loader

在build目錄下的webpack.base.conf.js中的module.rule里添加如下配置

{

? ? test: /\.scss$/,

? ? loader:'style-loader!css-loader!sass-loader'

}

在需要使用scss代碼的組件的style標簽中添加 lang='scss'

vue-router

現在的應用都流行SPA應用(single page application)

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

單頁面應用就是用戶通過某些操作更改地址欄url之后,動態的進行不同模板內容的無刷新切換,用戶體驗好。

Vue中會使用官方提供的vue-router插件來使用單頁面,原理就是通過檢測地址欄變化后將對應的路由組件進行切換(卸載和安裝)

簡單路由實現:

引入vue-router,如果是在腳手架中,引入VueRouter之后,需要通過Vue.use來注冊插件

? ? import Vue from 'vue'

? ? import Router from 'vue-router'

? ? Vue.use(Router)

創建router路由器

? ? new Router(options)

創建路由表并配置在路由器中

? ? var routes = [

? ? ? ? {path,component}//path為路徑,component為路徑對應的路由組件

? ? ]

? ? new Router({

? ? ? ? routes

? ? })

在根實例里注入router,目的是為了讓所有的組件里都能通過this.$router、this.$route來使用路由的相關功能api

? ? new Vue({

? ? el: '#app',

? ? router,

? ? template: '<App/>',

? ? components: { App }

? ? })

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

使用router-link來創建切換的工具,會渲染成a標簽,添加to屬性來設置要更改的path信息,且會根據當前路由的變化為a標簽添加對應的router-link-active/router-link-exact-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

組件支持用戶在具有路由功能的應用中(點擊)導航。 通過 to 屬性指定目標地址,默認渲染成帶有正確鏈接的 標簽,可以通過配置 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

詳細請看文檔

響應式原理

因為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的使用:

創建store:

import Vue from 'vue'

import Vuex from 'vuex'

Vue.use(Vuex)

//可以設置store管理的state/getter,mutations,actions

const store = new Vuex.Store({

})

設置state

state就是一個純對象,上面有一些狀態掛載,而且一個應用應該只有一個數據源:單一狀態樹、唯一數據源

import state from './modules/state'

//可以設置store管理的state/getter,mutations,actions

const store = new Vuex.Store({

? ? state

})

在根實例里配置store

這樣,我們就可以在任意的組件中通過this.$store來使用關于store的api

import store from './store'

new Vue({

? el: '#app',

? router,

? store,

? template: '<App/>',

? components: { App }

})

在組件中使用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

? ? ? ? }

? ? }),

},

getters

有的時候,我們需要根據state中的某一個狀態派生出一個新的狀態,例如,我們state中有一個num,在某些組件中需要用到是num的二倍的一個狀態,我們就可以通過getters來創建

const getters = {

? ? doublenum(state){

? ? ? ? return state.num*2

? ? }

}

創建了之后,在組件中通過this.$store.getters來獲取里面的數據

當然vuex也提供了mapGetters輔助函數來幫助我們在組件中使用getters里的狀態,且,使用的方法和mapState一模一樣

使用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一樣

使用actions來處理異步操作

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中

vuex的使用:

目前市場上有兩種使用vuex的情況,

第一種:將需要共享、需要管理的狀態放入vuex中管理,也就是說在必要時使用

第二種:將所有的數據都交由vuex管理,由vuex來承擔更多的責任,組件變得更輕量級,視圖層更輕

---

##### 自定義指令

在實現回到頂部功能的時候,我們寫了一個backTop組件,接下來需要通過監聽window.scroll事件來控制這個組件顯示隱藏

因為可能會有其他的組件會用到這樣的邏輯,所以將此功能做成一個自定義指令:

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

問題:

唯一需要注意的是,在指令的鉤子函數中我們可以訪問到el,也就是使用指令的標簽,但是我們不能直接更改value(指令的值所代表的數據)

所以我們使用引用類型來進行地址的傳遞來解決這個問題

接下來有寫了一個v-back-top指令,就是將回到頂部功能做成一個指令,哪個組件或者dom需要使用到回到頂部,就加上這個指令就可以,設置不同的參數來控制在不同的情況下觸發

##### Vue的組件庫

組件庫就是通用組件的集合

pc:element-ui? iview

mobile: mint-ui

##### nextTick

當我們在使用一些插件的時候,經常需要在dom更新完成后進行必要操作,但是在vue中提供的api只有updated鉤子函數,而在這個函數里,任意數據的變化導致的dom更新完成都會觸發,所以很可能會造成無關數據的影響,而使用監聽的話只能監聽到數據的變化,此時dom還沒有更新,我們只能強行使用setTimeout來處理

這里推薦大家使用nextTick全局方法:

在下次 DOM 更新循環結束之后執行延遲回調。在修改數據之后立即使用這個方法,獲取更新后的 DOM。

eq:

getBillBoards(){

? ? axios.get(this.$root.config.host+'mz/v4/api/billboard/home',{

? ? ? ? params:{__t:Date.now()}

? ? }).then(res => {

? ? ? ? console.log(res.data.data.billboards)

? ? ? ? this.billboards = res.data.data.billboards

? ? ? ? //當數據更新,dom循環完成后,執行回調

? ? ? ? Vue.nextTick(function () {

? ? ? ? ? ? new Swiper('.app-home-banner',{

? ? ? ? ? ? ? ? loop:true

? ? ? ? ? ? })

? ? ? ? })

? ? })

}

##### keep-alive

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

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

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

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

使用keep-alive緩存的組件連帶它的子組件們都會擁有activated、deactivated鉤子函數,會在切換回來和要切換出去的時候觸發

比如,main做了緩存,但是main的banner我們希望每次都去重新獲取數據,所以就在banner的activated里獲取數據

### Vue試題分析

1. v-for可以實現數據遍歷顯示,不僅可以遍歷數組,也可以遍歷對象,還可以從數值中取值:

v-for='n in 10' n會打印1-10

2. vue的生命周期鉤子:

通用:beforeCreate/created/beforeMount/mounted/beforeUpdate/updated/beforeDestroy/destroyed

路由守衛:beforeRouteEnter/beforeRouteUpdate (2.2 新增)/beforeRouteLeave

keep-alive:activated/deactivated

3. v-if v-show

v-if是真正的條件渲染,會確保在切換中條件塊內的事件監聽、子組件都會適當的被銷毀和重建

v-show總是將節點渲染在dom中,只是基于css:display來控制節點的顯示和隱藏

v-if有更高的切換開始,v-show有更高的初始渲染開銷

v-if是惰性的,初始條件為假,就不會渲染

4. axios相關

axios請求的時候不會帶上cookie,不會影響帶寬,可以通過withCredentials:true來設置

對axios 的請求頭進行設置:

axios.defaults.headers = {'Content-Type':'...'}

vue2.0不在更新維護vue-resource,官方推薦使用axios

axios攔截器可以攔截請求和響應,在then、catch之前攔截

6. 組件實例的作用域是孤立的,意味著不能(不應該)在子組件模板里直接引用父組件的數據,要讓子組件使用父組件數據的話,需要通過props來將父組件的數據傳遞給子組件,子組件不能也不應該修改父組件傳入的數據,但是可以通過傳入引用類型的數據來實現數據共享

7.為了讓組件可以組合,我們需要一種方式來混合父組件的內容與子組件自己的模板。這個過程被稱為內容分發 (即 Angular 用戶熟知的“transclusion”)。Vue.js 實現了一個內容分發 API,參照了當前 Web Components 規范草案,使用特殊的 <slot> 元素作為原始內容的插槽。

a-template:

<p>hello world</p>

<b>

<h1>hello world</h1>

</b>

b-template:

<slot></slot>

....

8. 如果把切換出去的組件保存在內存中,保留狀態避免重新渲染,可以使用keep-alive

include exclude

9. 注冊方式:

全局:Vue.component(name,Vue.extend({}))

局部:{ components:{name:Vue.extend({})} }

10. 事件總線實現非父子組件通信

//創建bus

let bus = new Vue()

//a

new Vue({

template:'...',

mounted(){

bus.$on('emit-a',function(){

alert(1)

})

}

})

//b

new Vue({

template:'...',

methods:{

emitA(){

bus.$emit('emit-a')

}

}

})

//當b組件的emitA方法被調用的時候,A組件就會執行alert(1)

11. methods和計算屬性的區別

假設我們有一個數據為num,還希望擁有一個數據為doublenum,而且希望doublenum的值永遠都是num的二倍

方法:

* 因為是直接顯示在模板中,也就是說,我們可以來一個doublenum的方法,這個方法返回num的二倍,將這個方法放到模板中的某個地方執行 {{doublenum()}}

? 但是,當無關的例如一個str的數據更改的時候,組件會重新創建虛擬dom樹,與上一次的虛擬dom樹對比之后重新渲染,這個時候在重新渲染模板的時候doublenum函數會被再次的調用,造成不必要的性能浪費


* 創建一個doublenum數據,使其初始值為num的二倍,然后利用watch來監聽這兩個數據,在改變的時候更改對應的數據,但是需要初始的為doublenum賦值為num的二倍,如果num是動態獲取到的,doublenun賦值會更繁瑣

* computed計算數據,我們可以利用computed來創建一條新的doublenum數據。并且設置它的getter和setter,并與num建立關系,且computed會緩存,在重新渲染的時候,不會重新執行getter和setter

computed:{

doublenum:{

get(){

return this.num*2

},

set(val){

this.num = val/2

}

}

}

12. 綁定class的對象語法和數組語法

<a :class="{a:true,b:false,c:1}"> => </a> => <a class='a c'></a>

data(){

return {

c:'c'

}

}

<a :class = '["a","b",c]'></a> => </a> => <a class='a b c'></a>

13.

new Vue({

el:"#example-3",

methods:{

say(str){

alert(str)

}

}

})

14. 單向數據流

prop是單向綁定的,父組件屬性變化,傳遞給子組件,但是,子組件數據變化,不能直接傳遞給父組件,也就是數據的流行是從父組件流向子組件的,為了防止子組件修改父組件的數據(會讓應用的數據流變的更難開發、更新、維護)

使用了vuex工具的時候,store中數據在組件中使用的過程也是單向數據流,state->vue component->actions->mutations->state->vue component

15. this.$router.push/replace({name:'user',params:{userId:1})

this.$router.push/replace({path:'/register',query:{plan:private})

##### key相關

當數據改變之后,vue會創建新的虛擬dom來和原來的虛擬dom做對比,在創建新的虛擬的dom的時候,會根據key來查找在原來的虛擬dom中有沒有某個部分,如果原來的有,這次的也需要,就會實現復用,而且在做diff對比的時候,如果有key會加快對比的查找速度,提高性能

盡量循環的時候不要將key設置為數組的索引,因為當刪除某一個元素的時候,就會導致刪除位置下面的所有元素的key值都與上一次虛擬dom的key值不同,導致復用失敗,這個時候我們最好使用關鍵的唯一的,例如id這樣的數據作為key

如果數據變化只是值的變化而不是條數和位置的變化,可以使用索引作為key

##### Vue.use()

Vue.use會查找插件對象里的install方法去執行,并且給install方法里傳入Vue對象

var a = {

? ? install(Vue){

? ? ? ? Vue.component("my-a",{...})

? ? }

}

Vue.use(a)

##### 進入域后根據不同的情況顯示不同的頁面(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

---

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容