Vue基礎知識

Vue.js(讀音/vju?/, 類似于 view)是一個構(gòu)建數(shù)據(jù)驅(qū)動的web 界面的漸進式框架布疙。Vue.js的目標是通過盡可能簡單的API 實現(xiàn)響應的數(shù)據(jù)綁定和組合的視圖組件。只聚焦于視圖層乎莉。

一埠啃、Vue實例

1死宣、創(chuàng)建一個vue實例

每個 Vue 應用都是通過用Vue 函數(shù)創(chuàng)建一個新的Vue 實例開始的:

?????? var vm = new Vue({ //選項? })

2、數(shù)據(jù)與方法

當一個Vue 實例被創(chuàng)建時碴开,它向Vue 的響應式系統(tǒng)中加入了其data 對象中能找到的所有的屬性毅该。當這些屬性的值發(fā)生改變時,視圖將會產(chǎn)生“響應”潦牛,即匹配更新為新的值眶掌。

只有當實例被創(chuàng)建時data 中存在的屬性才是響應式的。也就是說如果你添加一個新的屬性巴碗,那么對它的改動將不會觸發(fā)任何視圖的更新

使用 Object.freeze()畏线,這會阻止修改現(xiàn)有的屬性,也意味著響應系統(tǒng)無法再追蹤變化良价。

除了數(shù)據(jù)屬性,Vue 實例還暴露了一些有用的實例屬性與方法蒿叠。它們都有前綴$明垢,以便與用戶定義的屬性區(qū)分開來。

二市咽、模板語法

1痊银、插值

數(shù)據(jù)綁定最常見的形式就是使用“Mustache”語法(雙大括號)的文本插值:Mustache標簽將會被替代為對應數(shù)據(jù)對象上msg 屬性的值。無論何時施绎,綁定的數(shù)據(jù)對象上msg 屬性發(fā)生了改變溯革,插值處的內(nèi)容都會更新贞绳。

<span>Message:{{ msg }}</span>

通過使用v-once 指令撑蒜,你也能執(zhí)行一次性地插值垮衷,當數(shù)據(jù)改變時,插值處的內(nèi)容不會更新册招。

<span v-once>Message:{{msg}}</span>

?????? 原始html:雙大括號會將數(shù)據(jù)解釋為普通文本抖单,而非HTML 代碼萎攒。為了輸出真正的HTML,你需要使用v-html 指令:

<p>Using v-html directive:<span v-html="rowhtml"></span></p>

?????? 特性:Mustache語法不能作用在HTML 特性上矛绘,遇到這種情況應該使用v-bind 指令:

<p v-bind:id="textid"></p>

?????? 使用JavaScript表達式:對于所有的數(shù)據(jù)綁定耍休,Vue.js 都提供了完全的JavaScript 表達式支持。這些表達式會在所屬 Vue 實例的數(shù)據(jù)作用域下作為JavaScript 被解析货矮。有個限制就是羊精,每個綁定都只能包含單個表達式,所以下面的例子都不會生效囚玫。

<!-- 這是語句喧锦,不是表達式-->

{{ var a = 1 }}

流控制也不會生效,請使用三元表達式-->

{{ if (ok) { return message } }}

2劫灶、指令

?????? 指令 (Directives) 是帶有v- 前綴的特殊屬性裸违。指令屬性的值預期是單個JavaScript 表達式 (v-for 是例外情況,稍后我們再討論)本昏。指令的職責是供汛,當表達式的值改變時,將其產(chǎn)生的連帶影響涌穆,響應式地作用于DOM怔昨。

<p? v-if="seen">現(xiàn)在你看到我了</p>

v-if 指令將根據(jù)表達式seen 的值的真假來插入/移除<p> 元素。

?????? 參數(shù):一些指令能夠接收一個“參數(shù)”宿稀,在指令名稱之后以冒號表示趁舀。例如,v-bind指令可以用于響應式地更新HTML 屬性:

<a v-bind:href="href"></a>

<a :href="href"></a>

在這里 href 是參數(shù)祝沸,告知v-bind 指令將該元素的 href 屬性與表達式url 的值綁定矮烹。

另一個例子是v-on指令,它用于監(jiān)聽DOM事件罩锐,在這里參數(shù)是監(jiān)聽的事件名奉狈。

<a v-on:click="dosomething">...</a>

<a @click="dosomething"></a>

可以用方括號括起來的 JavaScript 表達式作為一個指令的參數(shù)

<a v-bind:[name]="textid"></a>

name其值為id,則上式可以轉(zhuǎn)換成<a v-bind:id="textid"></a>

?????? 修飾符:修飾符(Modifiers) 是以半角句號 . 指明的特殊后綴涩惑,用于指出一個指令應該以特殊方式綁定仁期,例如:

.prevent 修飾符告訴v-on 指令對于觸發(fā)的事件調(diào)event.preventDefault():

<form v-on:submit.prevent="onSubmit"></form>

三、計算屬性和偵聽器

1、計算屬性

<p>Computed reversed message: "{{ reversedMessage }}"</p>

computed: {

??? //計算屬性的getter

??? reversedMessage: function () {

????? // `this`指向vm 實例

????? return this.message.split('').reverse().join('')

??? }

? }

2跛蛋、在表達式中調(diào)用方法

<p>Reversedmessage: "{{ reversedMessage() }}"</p>

// 在組件中

methods: {

? reversedMessage: function () {

??? return this.message.split('').reverse().join('')

? }

}

3熬的、計算屬性vs方法

?????? 兩種方式的最終結(jié)果確實是完全相同的。然而赊级,不同的是計算屬性是基于它們的響應式依賴進行緩存的押框。計算屬性只有在它的相關(guān)響應式依賴發(fā)生改變時才會重新求值。這就意味著只要message 還沒有發(fā)生改變此衅,多次訪問 reversedMessage 計算屬性會立即返回之前的計算結(jié)果强戴,而不必再次執(zhí)行函數(shù)。相比之下挡鞍,每當觸發(fā)重新渲染時骑歹,調(diào)用方法將總會再次執(zhí)行函數(shù)。

4墨微、偵聽屬性

?????? 當你有一些數(shù)據(jù)需要隨著其它數(shù)據(jù)變動而變動時道媚,你很容易濫用watch

watch: {

??? firstName: function (val) {

????? this.fullName = val + ' ' +this.lastName

??? },

??? lastName: function (val) {

????? this.fullName = this.firstName + '' + val

??? }

? }

5、計算屬性vs偵聽屬性

computed: {

??? fullName: function () {

????? return this.firstName + ' ' +this.lastName

??? }

? }

偵聽屬性代碼命令式且重復

6翘县、計算屬性的setter

computed: {

? fullName: {

??? // getter

??? get: function () {

????? return this.firstName + ' ' +this.lastName

??? },

??? // setter

??? set: function (newValue) {

????? var names = newValue.split(' ')

????? this.firstName = names[0]

????? this.lastName = names[names.length- 1]

??? }

? }

}

7最域、偵聽器

?????? 雖然計算屬性在大多數(shù)情況下更合適,但有時也需要一個自定義的偵聽器锈麸。Vue通過watch 選項提供了一個更通用的方法镀脂,來響應數(shù)據(jù)的變化。當需要在數(shù)據(jù)變化時執(zhí)行異步或開銷較大的操作時忘伞,這個方式是最有用的薄翅。

????使用?watch?選項允許我們執(zhí)行異步操作 (訪問一個 API),限制我們執(zhí)行該操作的頻率氓奈,并在我們得到最終結(jié)果前翘魄,設置中間狀態(tài)。這些都是計算屬性無法做到的舀奶。

四暑竟、class與style綁定

1、綁定HTMLClass

?????? 對象語法:

v-bind:class 指令也可以與普通的class 屬性共存

綁定的數(shù)據(jù)對象不必內(nèi)聯(lián)定義在模板里:

data:? {

? classObject: {

??? active: true,

??? 'text-danger': false

? }

}

數(shù)組語法:

<div v-bind:class="[activeClass,errorClass]"></div>

把一個數(shù)組傳給v-bind:class育勺,以應用一個 class 列表:

data:? {

? activeClass: 'active',

? errorClass: 'text-danger'

}

渲染為:<div class="active text-danger"></div>

用在組件上:當在一個自定義組件上使用class 屬性時但荤,這些類將被添加到該組件的根元素上面。這個元素上已經(jīng)存在的類不會被覆蓋涧至。

?2纱兑、綁定內(nèi)聯(lián)樣式

對象語法:

<div v-bind:style="{color:activeColor,fontSize:fontSize+'px'}"></div>

data: {

? activeColor: 'red',

? fontSize: 30

}

直接綁定到一個樣式對象通常更好,這會讓模板更清晰:

<div v-bind:style="styleObject"></div>

data:? {

? styleObject: {

??? color: 'red',

??? fontSize: '13px'

? }

}

數(shù)組語法:

v-bind:style 的數(shù)組語法可以將多個樣式對象應用到同一個元素上:

<div :style="[baseStyles, overridingStyles]"></div>

自動添加前綴:

當v-bind:style 使用需要添加瀏覽器引擎前綴的 CSS 屬性時化借,如transform,Vue.js 會自動偵測并添加相應的前綴捡多。

多重值

可以為style 綁定中的屬性提供一個包含多個值的數(shù)組蓖康,常用于提供多個帶前綴的值铐炫,例如:

<div :style="{display:['-webkit-box', '-ms-flexbox', 'flex']}"></div>

這樣寫只會渲染數(shù)組中最后一個被瀏覽器支持的值。在本例中蒜焊,如果瀏覽器支持不帶瀏覽器前綴的flexbox倒信,那么就只會渲染 display: flex。

五泳梆、條件渲染

1.v-if

在<template> 元素上使用 v-if 條件渲染分組:

因為v-if 是一個指令鳖悠,所以必須將它添加到一個元素上。但是如果想切換多個元素呢优妙?此時可以把一個<template> 元素當做不可見的包裹元素乘综,并在上面使用 v-if。最終的渲染結(jié)果將不包含<template> 元素套硼。

?????? 可以使用v-else 指令來表示 v-if 的“else塊”卡辰,v-else 元素必須緊跟在帶 v-if 或者v-else-if 的元素的后面,否則它將不會被識別邪意,v-else-if 也必須緊跟在帶v-if 或者v-else-if 的元素之后九妈。

用key管理可復用元素

?????? Vue為你提供了一種方式來表達“兩個元素是完全獨立的,不要復用它們”雾鬼。只需添加一個具有唯一值的key 屬性即可:

2萌朱、v-show

另一個用于根據(jù)條件展示元素的選項是v-show 指令:

不同的是帶有v-show 的元素始終會被渲染并保留在 DOM 中。v-show只是簡單地切換元素的CSS 屬性display策菜。v-show 不支持<template> 元素晶疼,也不支持 v-else。

3做入、v-if vs v-show

v-if 是“真正”的條件渲染冒晰,因為它會確保在切換過程中條件塊內(nèi)的事件監(jiān)聽器和子組件適當?shù)乇讳N毀和重建。v-if也是惰性的:如果在初始渲染時條件為假竟块,則什么也不做——直到條件第一次變?yōu)檎鏁r壶运,才會開始渲染條件塊。

相比之下浪秘,v-show 就簡單得多——不管初始條件是什么蒋情,元素總是會被渲染,并且只是簡單地基于CSS 進行切換耸携。

一般來說棵癣,v-if 有更高的切換開銷,而v-show 有更高的初始渲染開銷夺衍。因此狈谊,如果需要非常頻繁地切換,則使用v-show 較好;如果在運行時條件很少改變河劝,則使用 v-if 較好壁榕。

4、v-if 與v-for?

當v-if 與v-for 一起使用時赎瞎,v-for 具有比v-if 更高的優(yōu)先級牌里。

六、列表渲染

1务甥、用v-for把一個數(shù)組對應為一組元素

用 v-for 指令根據(jù)一組數(shù)組的選項列表進行渲染牡辽。v-for指令需要使用item in items 形式的特殊語法,items 是源數(shù)據(jù)數(shù)組并且item 是數(shù)組元素迭代的別名敞临。

?????? 在v-for 塊中态辛,我們擁有對父作用域?qū)傩缘耐耆L問權(quán)限。v-for還支持一個可選的第二個參數(shù)為當前項的索引哟绊。

<ul id="example-2">

<li v-for="(item,index) in items">

??? {{ parentMessage }} - {{ index }} -? {{ item.message }}

</li>

</ul>

var? example2 = new Vue({

? el: '#example-2',

? data: {

??? parentMessage: 'Parent',

??? items: [

????? { message: 'Foo' },

????? { message: 'Bar' }

?? ?]

? }

})

也可以用? of 替代 in 作為分隔符

2因妙、一個對象的v-for

可以用v-for 通過一個對象的屬性來迭代。

<ul id="v-for-object">

<li v-for="value in object">

{{value}}

</li>

</ul>

new? Vue({

? el: '#v-for-object',

? data: {

??? object: {

????? firstName: 'John',

????? lastName: 'Doe',

????? age: 30

??? }

? }

})

也可以提供第二個的參數(shù)為鍵名:

? {{ key }}: {{ value }}

第三個參數(shù)為索引:

? {{ index }}. {{ key }}: {{ value }}

3票髓、key

為了給Vue 一個提示攀涵,以便它能跟蹤每個節(jié)點的身份,從而重用和重新排序現(xiàn)有元素洽沟,你需要為每項提供一個唯一key 屬性以故。理想的key 值是每項都有的且唯一的id。這個特殊的屬性相當于Vue 1.x 的 track-by 裆操,但它的工作方式類似于一個屬性怒详,所以你需要用v-bind 來綁定動態(tài)值。建議盡可能在使用 v-for 時提供key踪区,因為它是Vue 識別節(jié)點的一個通用機制昆烁,key并不與v-for 特別關(guān)聯(lián)。

4缎岗、數(shù)組更新檢測

?變異方法:

Vue 包含一組觀察數(shù)組的變異方法静尼,所以它們也將會觸發(fā)視圖更新。

push()? pop()?shift()? unshift()? splice()?sort()? reverse()

變異方法(mutation method)传泊,顧名思義鼠渺,會改變被這些方法調(diào)用的原始數(shù)組。

替換數(shù)組:非變異(non-mutating method) 方法眷细,例如:filter(),

concat() 和 slice() 拦盹。這些不會改變原始數(shù)組,但總是返回一個新數(shù)組溪椎。當使用非變異方法時普舆,可以用新數(shù)組替換舊數(shù)組:

注意事項:

由于JavaScript 的限制恬口,Vue 不能檢測以下變動的數(shù)組:

當你利用索引直接設置一個項時:

?????? Vue.set(vm.items, indexOfItem, newValue)

也可以使用vm.$set實例方法,該方法是全局方法 Vue.set 的一個別名:

?????? vm.$set(vm.items, indexOfItem, newValue)

?????? 當你修改數(shù)組的長度時

?????? 使用vm.items.splice(newLength)

5奔害、對象更改檢測注意事項

?????? 由于JavaScript 的限制楷兽,Vue 不能檢測對象屬性的添加或刪除:可以使用

Vue.set(object,key, value) 方法向嵌套對象添加響應式屬性,也可以使用vm.$set 實例方法华临,它只是全局 Vue.set 的別名:Vue.$set(object,key, value)

?????? 有時你可能需要為已有對象賦予多個新屬性,比如使用Object.assign() 或 _.extend()端考。在這種情況下雅潭,你應該用兩個對象的屬性創(chuàng)建一個新的對象

vm.userProfile =Object.assign({}, vm.userProfile, {

? age: 27,

? favoriteColor: 'Vue Green'

})

6、顯示過濾/排序結(jié)果

有時却特,我們想要顯示一個數(shù)組的過濾或排序副本扶供,而不實際改變或重置原始數(shù)據(jù)。在這種情況下裂明,可以創(chuàng)建返回過濾或排序數(shù)組的計算屬性椿浓。

<li v-for="value in evenNumbers">{{ n }}</li>

data:? {

??numbers: [ 1, 2, 3, 4, 5 ]

},

computed: {

? evenNumbers: function () {

??? return this.numbers.filter(function? (number) {

????? return number % 2 === 0

??? })

? }

}

在計算屬性不適用的情況下(例如,在嵌套v-for 循環(huán)中) 你可以使用一個method 方法

<li v-for="value in even(numbers)">{{ n }}</li>

data:? {

? numbers: [ 1, 2, 3, 4, 5 ]

},

methods: {

? even: function (numbers) {

??? return numbers.filter(function? (number) {

????? return number % 2 === 0

??? })

? }

}

7闽晦、一段取值范圍的v-for

?<span v-for="n in 10"> {{ n }}</span>

8扳碍、在template上使用v-for

類似于v-if,你也可以利用帶有v-for 的 <template> 渲染多個元素仙蛉。

9笋敞、v-for with v-if

當它們處于同一節(jié)點,v-for的優(yōu)先級比v-if 更高荠瘪,這意味著v-if 將分別重復運行于每個v-for 循環(huán)中:

10夯巷、一個組件的v-for

在自定義組件里,你可以像任何普通元素一樣用 v-for 哀墓。

當在組件中使用 v-for 時趁餐,key 現(xiàn)在是必須的。

然而篮绰,任何數(shù)據(jù)都不會被自動傳遞到組件里后雷,因為組件有自己獨立的作用域。為了把迭代數(shù)據(jù)傳遞到組件里阶牍,我們要用 props :

七喷面、事件處理

1、監(jiān)聽事件

可以用v-on 指令監(jiān)聽DOM 事件走孽,并在觸發(fā)時運行一些JavaScript 代碼惧辈。

<button v-on:click="count+=1">Add1</button>

<p>{{count}}</p>

var? example1 = new Vue({

? el: '#example-1',

? data: {

??? counter: 0

? }

})

2、事件處理方法

直接把JavaScript 代碼寫在 v-on 指令中是不可行的磕瓷。因此v-on 還可以接收一個需要調(diào)用的方法名稱盒齿。

3念逞、內(nèi)聯(lián)處理器中的方法

除了直接綁定到一個方法,也可以在內(nèi)聯(lián)JavaScript 語句中調(diào)用方法边翁,有時也需要在內(nèi)聯(lián)語句處理器中訪問原始的DOM 事件翎承。可以用特殊變量$event 把它傳入方法符匾。

4叨咖、事件修飾符

方法只有純粹的數(shù)據(jù)邏輯,而不是去處理DOM 事件細節(jié)啊胶。解決了這個問題甸各,Vue.js為v-on 提供了事件修飾符,修飾符是由點開頭的指令后綴來表示的焰坪。

<!-- 阻止單擊事件繼續(xù)傳播-->

<a v-on:click.stop="dothis"></a>

提交事件不再重載頁面-->

<form v-on:submit.prevent="onsubmit"></form>

修飾符可以串聯(lián)-->

<a v-on:click.stop.prevent="dothat"></a>

添加事件監(jiān)聽器時使用事件捕獲模式,即元素自身觸發(fā)的事件先在此處處理趣倾,然后才交由內(nèi)部元素進行處理-->

<div v-on:click.capture="dothis"></div>

只當在 event.target 是當前元素自身時觸發(fā)處理函數(shù),即事件不是從內(nèi)部元素觸發(fā)的-->

<div v-on:click.self="dothis"></div>

使用修飾符時,順序很重要某饰。

<!-- 點擊事件將只會觸發(fā)一次-->

<a v-on:click.once="dothis"></a>

<!-- 滾動事件的默認行為(即滾動行為)將會立即觸發(fā)儒恋,而不會等待 `onScroll` 完成,這其中包含 `event.preventDefault()`的情況-->

<div v-on:scroll.passive="onScroll"></div>

不要把.passive 和 .prevent 一起使用黔漂,因為.prevent 將會被忽略诫尽,同時瀏覽器可能會向你展示一個警告。請記住瘟仿,.passive會告訴瀏覽器你不想阻止事件的默認行為箱锐。

5、按鍵修飾符

<!-- 只有在`keyCode` 是 13 時調(diào)用`vm.submit()` -->

縮寫語法-->

全部的按鍵別名:

.enter? .tab?.delete (捕獲“刪除”和“退格”鍵)? .esc?.space? .up? .down?.left? .right

可以通過全局vue.config.keyCodes 對象自定義按鍵修飾符別名

自動匹配按鍵修飾符

你也可直接將KeyboardEvent.key暴露的任意有效按鍵名轉(zhuǎn)換為kebab-case 來作為修飾符:

在上面的例子中劳较,處理函數(shù)僅在$event.key === 'PageDown' 時被調(diào)用驹止。

6、系統(tǒng)修飾符

可以用如下修飾符來實現(xiàn)僅在按下相應按鍵時才觸發(fā)鼠標或鍵盤事件的監(jiān)聽器观蜗。

.ctrl? .alt?.shift? .meta

.exact 修飾符允許你控制由精確的系統(tǒng)修飾符組合觸發(fā)的事件臊恋。

?????? 鼠標按鈕修飾符.left? .right? .middle這些修飾符會限制處理函數(shù)僅響應特定的鼠標按鈕。

7墓捻、為什么在HTML中監(jiān)聽事件

所有的Vue.js 事件處理方法和表達式都嚴格綁定在當前視圖的ViewModel 上抖仅,它不會導致任何維護上的困難。實際上砖第,使用v-on 有幾個好處:

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

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

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

八、表單輸入綁定

1唧喉、基礎用法

你可以用v-model 指令在表單 <input> 及<textarea> 元素上創(chuàng)建雙向數(shù)據(jù)綁定捣卤。它會根據(jù)控件類型自動選取正確的方法來更新元素。

<input v-model="data1" placeholder="hahaha">

? ? <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">

? ? <label for="jack">Jack</label>

? ? <input type="checkbox" id="john" value="John" v-model="checkedNames">

? ? <label for="john">John</label>

? ? <br>

? ? <span>Checked names: {{ checkedNames }}</span>

2八孝、值綁定

有時我們可能想把值綁定到Vue 實例的一個動態(tài)屬性上腌零,這時可以用v-bind 實現(xiàn),并且這個屬性的值可以不是字符串唆阿。

3、修飾符

?????? .lazy:在默認情況下锈锤,v-model在每次input 事件觸發(fā)后將輸入框的值與數(shù)據(jù)進行同步 (除了上述輸入法組合文字時)驯鳖。你可以添加lazy 修飾符,從而轉(zhuǎn)變?yōu)槭褂胏hange 事件進行同步:

?????? .number:如果想自動將用戶的輸入值轉(zhuǎn)為數(shù)值類型久免,可以給v-model 添加 number 修飾符:

???? .trim:如果要自動過濾用戶輸入的首尾空白字符浅辙,可以給v-model 添加 trim 修飾符:

4、在組件上使用v-model(后面返回來學習)

九阎姥、組件

1记舆、什么是組件

?????? 組件(Component) 是 Vue.js 最強大的功能之一。組件可以擴展HTML 元素呼巴,封裝可重用的代碼泽腮。在較高層面上,組件是自定義元素衣赶,Vue.js的編譯器為它添加特殊功能诊赊。在有些情況下,組件也可以表現(xiàn)為用is 特性進行了擴展的原生HTML 元素府瞄。

所有的Vue 組件同時也都是Vue 的實例碧磅,所以可接受相同的選項對象(除了一些根級特有的選項)并提供相同的生命周期鉤子。

2遵馆、使用組件

要注冊一個全局組件鲸郊,可以使用Vue.component(tagName, options)。例如:

Vue.component('my-component',? {data:function(){

return {count:0}

},template:'<button v-on:click="count++">You clicked me {{ count }} times.</button>'})

組件在注冊之后货邓,便可以作為自定義元素 <my-component></my-component> 在一個實例的模板中使用秆撮。注意確保在初始化根實例之前注冊組件:

***一個組件的?data?選項必須是一個函數(shù),因此每個實例可以維護一份被返回對象的獨立的拷貝:

創(chuàng)建根實例

new Vue({

? el: '#example'

})

局部注冊:

你不必把每個組件都注冊到全局逻恐。你可以通過某個 Vue 實例/組件的實例選項 components 注冊僅在其作用域中可用的組件:

var? Child = {

? template: 'A custom? component!'

}

new Vue({

? // ...

? components: {

??? //

將只在父組件模板中可用

??? 'my-component': Child

? }

})

Dom模板解析注意事項:

當使用? DOM 作為模板時 (例如像吻,使用 el 選項來把? Vue 實例掛載到一個已有內(nèi)容的元素上)峻黍,你會受到 HTML 本身的一些限制,因為? Vue 只有在瀏覽器解析拨匆、規(guī)范化模板之后才能獲取其內(nèi)容姆涩,在自定義組件中使用這些受限制的元素時會導致一些問題,自定義組件 <my-row> 會被當作無效的內(nèi)容惭每,因此會導致錯誤的渲染結(jié)果骨饿。變通的方案是使用特殊的 is 特性:應當注意,如果使用來自以下來源之一的字符串模板台腥,則沒有這些限制:

JavaScript

? 內(nèi)聯(lián)模板字符串

.vue

? 組件

因此宏赘,請盡可能使用字符串模板。

Data必須是函數(shù):構(gòu)造 Vue 實例時傳入的各種選項大多數(shù)都可以在組件里使用黎侈。只有一個例外:data 必須是函數(shù)察署。

組件組合:組件設計初衷就是要配合使用的,最常見的就是形成父子組件的關(guān)系:組件 A 在它的模板中使用了組件? B峻汉。在 Vue 中贴汪,父子組件的關(guān)系可以總結(jié)為 prop 向下傳遞,事件向上傳遞休吠。父組件通過 prop 給子組件下發(fā)數(shù)據(jù)扳埂,子組件通過事件給父組件發(fā)送消息。

3瘤礁、Prop

使用prop傳遞數(shù)據(jù)阳懂,組件實例的作用域是孤立的。這意味著不能 (也不應該)

? 在子組件的模板內(nèi)直接引用父組件的數(shù)據(jù)柜思。父組件的數(shù)據(jù)需要通過 prop 才能下發(fā)到子組件中岩调。

Vue.component('child',? {

? //

聲明props

? props: ['message'],

? //

就像? data 一樣,prop 也可以在模板中使用

? //

同樣也可以在? vm 實例中通過 this.message 來使用

? template: '{{ message? }}'

})

camelCase? vs. kebab-case

HTML

? 特性是不區(qū)分大小寫的酝蜒。所以誊辉,當使用的不是字符串模板時,camelCase (駝峰式命名)

? 的 prop 需要轉(zhuǎn)換為相對應的? kebab-case (短橫線分隔式命名):

Vue.component('child',? ? {

? //

在? ? JavaScript 中使用camelCase

? props: ['myMessage'],

? template: '{{ myMessage? ? }}'

})


<!--

? ? 在 HTML 中使用kebab-case -->

動態(tài)Prop

與綁定到任何普通的? HTML 特性相類似亡脑,我們可以用 v-bind 來動態(tài)地將 prop 綁定到父組件的數(shù)據(jù)堕澄。每當父組件的數(shù)據(jù)變化時,該變化也會傳導給子組件:

如果你想把一個對象的所有屬性作為 prop 進行傳遞霉咨,可以使用不帶任何參數(shù)的 v-bind (即用? v-bind 而不是v-bind:prop-name)

將等價于:

? v-bind:text="todo.text"

v-bind:is-complete="todo.isComplete"

>

字面量語法vs動態(tài)語法

初學者常犯的一個錯誤是使用字面量語法傳遞數(shù)值:

<!-- 傳遞了一個字符串"1" -->

因為它是一個字面量? ? prop蛙紫,它的值是字符串? ? "1" 而不是一個數(shù)值。如果想傳遞一個真正的? ? JavaScript 數(shù)值途戒,則需要使用 v-bind坑傅,從而讓它的值被當作 JavaScript 表達式計算:

<!--傳遞真正的數(shù)值-->

單向數(shù)據(jù)流

Prop

? ? 是單向綁定的:當父組件的屬性變化時,將傳導給子組件喷斋,但是反過來不會唁毒。在兩種情況下蒜茴,我們很容易忍不住想去修改 prop 中數(shù)據(jù):

Prop

? ? 作為初始值傳入后,子組件想把它當作局部數(shù)據(jù)來用浆西;

Prop

? ? 作為原始數(shù)據(jù)傳入粉私,由子組件處理成其它數(shù)據(jù)輸出。

?? 定義一個局部變量近零,并用 prop 的值初始化它:

props:? ? ? ['initialCounter'],

data: function () {

? return { counter:? ? ? this.initialCounter }

}

?? 定義一個計算屬性诺核,處理 prop 的值并返回:

props:? ? ? ['size'],

computed: {

? normalizedSize: function () {

??? return? ? ? this.size.trim().toLowerCase()

? }

}

Prop驗證

我們可以為組件的? prop 指定驗證規(guī)則。如果傳入的數(shù)據(jù)不符合要求久信,Vue

? 會發(fā)出警告窖杀,要指定驗證規(guī)則,需要用對象的形式來定義 prop裙士,而不能用字符串數(shù)組:

Vue.component('example',? {

? props: {

??? //

基礎類型檢測? (`null` 指允許任何類型)

??? propA: Number,

??? //

可能是多種類型

??? propB: [String, Number],

??? //

必傳且是字符串

??? propC: {

????? type: String,

????? required: true

??? },

??? //

數(shù)值且有默認值

??? propD: {

????? type: Number,

????? default: 100

??? },

??? //

數(shù)組/對象的默認值應當由一個工廠函數(shù)返回

??? propE: {

????? type: Object,

????? default: function () {

??????? return { message: 'hello' }

????? }

??? },

??? //

自定義驗證函數(shù)

??? propF: {

????? validator: function (value) {

??????? return value > 10

????? }

??? }

? }

})

type

? 可以是下面原生構(gòu)造器:

String? Number?

? Boolean? Function? Object?

? Array? Symbol

type

? 也可以是一個自定義構(gòu)造器函數(shù)入客,使用 instanceof 檢測。

當? prop 驗證失敗腿椎,Vue 會拋出警告 (如果使用的是開發(fā)版本)痊项。注意 prop 會在組件實例創(chuàng)建之前進行校驗,所以在 default 或? validator 函數(shù)里酥诽,諸如 data、computed 或? methods 等實例屬性還無法使用皱埠。

4肮帐、非prop特性

所謂非? prop 特性,就是指它可以直接傳入組件边器,而不需要定義相應的? prop训枢。盡管為組件定義明確的 prop 是推薦的傳參方式,組件的作者卻并不總能預見到組件被使用的場景忘巧。所以恒界,組件可以接收任意傳入的特性,這些特性都會被添加到組件的根元素上砚嘴。

替換/合并現(xiàn)有的特性

對于多數(shù)特性來說十酣,傳遞給組件的值會覆蓋組件本身設定的值。即例如傳遞 type="large" 將會覆蓋 type="date" 且有可能破壞該組件际长!所幸我們對待 class 和? style 特性會更聰明一些耸采,這兩個特性的值都會做合并? (merge) 操作,讓最終生成的值為:form-control

? date-picker-theme-dark工育。

5虾宇、自定義事件

使用v-on綁定自定義事件:每個 Vue 實例都實現(xiàn)了事件接口,即:

使用? $on(eventName) 監(jiān)聽事件

使用? $emit(eventName, optionalPayload) 觸發(fā)事件

父組件可以在使用子組件的地方直接用 v-on 來監(jiān)聽子組件觸發(fā)的事件如绸。

給組件綁定原生事件

有時候嘱朽,你可能想在某個組件的根元素上監(jiān)聽一個原生事件旭贬。可以使用 v-on 的修飾符.native

.sync修飾符

.sync

? 還是有其適用之處搪泳,比如在開發(fā)可復用的組件庫時稀轨。我們需要做的只是讓子組件改變父組件狀態(tài)的代碼更容易被區(qū)分。

使用自定義事件的表單輸入組件:

自定義事件可以用來創(chuàng)建自定義的表單輸入組件森书,使用 v-model 來進行數(shù)據(jù)雙向綁定靶端。

自定義組件的v-model

默認情況下,一個組件的? v-model 會使用 value prop 和 input 事件凛膏。但是諸如單選框杨名、復選框之類的輸入類型可能把 value 用作了別的目的。model

? 選項可以避免這樣的沖突猖毫。

非父子組件的通信

有時候台谍,非父子關(guān)系的兩個組件之間也需要通信。在簡單的場景下吁断,可以使用一個空的 Vue 實例作為事件總線:

6趁蕊、使用插槽分發(fā)內(nèi)容

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

編譯作用域:父組件模板的內(nèi)容在父組件作用域內(nèi)編譯;子組件模板的內(nèi)容在子組件作用域內(nèi)編譯沛厨。

單個插槽:除非子組件模板包含至少一個 <slot> 插口宙地,否則父組件的內(nèi)容將會被丟棄。當子組件模板只有一個沒有屬性的插槽時逆皮,父組件傳入的整個內(nèi)容片段將插入到插槽所在的 DOM 位置宅粥,并替換掉插槽標簽本身。

具名插槽:<slot>

? 元素可以用一個特殊的特性 name 來進一步配置如何分發(fā)內(nèi)容电谣。多個插槽可以有不同的名字秽梅。具名插槽將匹配內(nèi)容片段中有對應 slot 特性的元素。仍然可以有一個匿名插槽剿牺,它是默認插槽风纠,作為找不到匹配的內(nèi)容片段的備用插槽。如果沒有默認插槽牢贸,這些找不到匹配的內(nèi)容片段將被拋棄竹观。

作用域插槽:作用域插槽是一種特殊類型的插槽,用作一個 (能被傳遞數(shù)據(jù)的)

? 可重用模板,來代替已經(jīng)渲染好的元素臭增。

7懂酱、動態(tài)組件

通過使用保留的? <component> 元素,并對其 is 特性進行動態(tài)綁定誊抛,你可以在同一個掛載點動態(tài)切換多個組件:

var? ? vm = new Vue({

? el: '#example',

? data: {

??? currentView: 'home'

? },

? components: {

??? home: { /* ... */ },

??? posts: { /* ... */ },

??? archive: { /* ... */ }

? }

})



組件在 vm.currentview 變化時改變藻糖!-->

也可以直接綁定到組件對象上:

var? Home = {

? template: '

Welcome? home!

'

}

var vm = new Vue({

? el: '#example',

? data: {

??? currentView: Home

? }

})

如果把切換出去的組件保留在內(nèi)存中鳖敷,可以保留它的狀態(tài)或避免重新渲染。為此可以添加一個 keep-alive 指令參數(shù):



非活動組件將被緩存!-->


8正罢、雜項

編寫可復用組件:在編寫組件時巩步,最好考慮好以后是否要進行復用松忍。一次性組件間有緊密的耦合沒關(guān)系潭枣,但是可復用組件應當定義一個清晰的公開接口,同時也不要對其使用的外層數(shù)據(jù)作出任何假設宾毒。

Vue

? 組件的 API 來自三部分——prop驼修、事件和插槽:

(1)Prop 允許外部環(huán)境傳遞數(shù)據(jù)給組件;

(2)事件允許從組件內(nèi)觸發(fā)外部環(huán)境的副作用诈铛;

(3)插槽允許外部環(huán)境將額外的內(nèi)容組合在組件中乙各。

子組件引用

盡管有? prop 和事件,但是有時仍然需要在 JavaScript 中直接訪問子組件幢竹。為此可以使用 ref 為子組件指定一個引用? ID耳峦。


var? parent = new Vue({ el: '#parent' })

//

訪問子組件實例

var child = parent.$refs.profile

當? ref 和 v-for 一起使用時,獲取到的引用會是一個數(shù)組焕毫,包含和循環(huán)數(shù)據(jù)源對應的子組件妇萄。

異步組件:在大型應用中,我們可能需要將應用拆分為多個小模塊咬荷,按需從服務器下載。為了進一步簡化轻掩,Vue.js 允許將組件定義為一個工廠函數(shù)幸乒,異步地解析組件的定義。Vue.js 只在組件需要渲染時觸發(fā)工廠函數(shù)唇牧,并且把結(jié)果緩存起來罕扎,用于后面的再次渲染。

Vue.component('async-example',? function (resolve, reject) {

? setTimeout(function () {

??? //

將組件定義傳入? resolve 回調(diào)函數(shù)

??? resolve({

????? template: '

I am? async!

'

??? })

? }, 1000)

})

組件命名約定:當注冊組件? (或者 prop) 時丐重,可以使用? kebab-case (短橫線分隔命名)腔召、camelCase (駝峰式命名)

? 或 PascalCase (單詞首字母大寫命名)。

遞歸組件:組件在它的模板內(nèi)可以遞歸地調(diào)用自己扮惦。不過臀蛛,只有當它有 name 選項時才可以這么做,當你利用 Vue.component 全局注冊了一個組件,全局的 ID 會被自動設置為組件的? name浊仆。要確保遞歸調(diào)用有終止條件 (比如遞歸調(diào)用時使用 v-if 并最終解析為? false)客峭。

組件間的循環(huán)引用:假設你正在構(gòu)建一個文件目錄樹,像在 Finder 或資源管理器中抡柿。你可能有一個 tree-folder 組件以及一個? tree-folder-contents 組件舔琅,在我們的例子中,可以選擇讓 tree-folder 組件中來做這件事洲劣。我們知道引起矛盾的子組件是 tree-folder-contents备蚓,所以我們要等到 beforeCreate 生命周期鉤子中才去注冊它。

內(nèi)聯(lián)模板:如果子組件有? inline-template 特性囱稽,組件將把它的內(nèi)容當作它的模板郊尝,而不是把它當作分發(fā)內(nèi)容。這讓模板編寫起來更靈活粗悯。



這些將作為組件自身的模板虚循。


而非父組件透傳進來的內(nèi)容。


inline-template

? 讓模板的作用域難以理解样傍。使用 template 選項在組件內(nèi)定義模板或者在 .vue 文件中使用? template 元素才是最佳實踐横缔。

X-template:另一種定義模板的方式是在 JavaScript 標簽里使用? text/x-template 類型,并且指定一個 id衫哥。


Hello hello? ? hello


Vue.component('hello-world',? ? {

? template: '#hello-world-template'

})

這在有很多大模板的演示應用或者特別小的應用中可能有用茎刚,其它場合應該避免使用,因為這將模板和組件的其它定義分離了撤逢。

對低開銷的靜態(tài)組件使用? v-once:盡管在 Vue 中渲染 HTML 很快膛锭,不過當組件中包含大量靜態(tài)內(nèi)容時,可以考慮使用 v-once 將渲染結(jié)果緩存起來蚊荣,就像這樣:

Vue.component('terms-of-service',? ? {

? template: '\


\


Terms of? ? Service

\

????? ...

很多靜態(tài)內(nèi)容...\

??? \

? '

})

十初狰、組件注冊

1、組件名

給予組件的名字可能依賴于你打算拿它來做什么互例。當直接在 DOM 中使用一個組件? (而不是在字符串模板或單文件組件)的時候奢入,我們強烈推薦遵循W3C規(guī)范中的自定義組件名 (字母全小寫且必須包含一個連字符)。

當使用? kebab-case (短橫線分隔命名) 定義一個組件時媳叨,你也必須在引用這個自定義元素時使用 kebab-case腥光,例如? <my-component-name>。

當使用? PascalCase (駝峰式命名) 定義一個組件時糊秆,你在引用這個自定義元素時兩種命名法都可以使用武福。也就是說 <my-component-name> 和 <MyComponentName> 都是可接受的。注意痘番,盡管如此捉片,直接在 DOM (即非字符串的模板)

? 中使用時只有 kebab-case 是有效的平痰。

2、全局注冊

到目前為止界睁,我們只用過? Vue.component 來創(chuàng)建組件觉增,這些組件是全局注冊的。也就是說它們在注冊之后可以用在任何新創(chuàng)建的 Vue 根實例? (new Vue) 的模板中翻斟。

3逾礁、局部注冊

4、模塊系統(tǒng)

在模塊系統(tǒng)中局部注冊:

需要在局部注冊之前導入每個你想使用的組件访惜。例如嘹履,在一個假設的 ComponentB.js 或? ComponentB.vue 文件中:

import? ? ComponentA from './ComponentA'

import ComponentC from './ComponentC'

export default {

? components: {

??? ComponentA,

??? ComponentC

? },

? // ...

}

現(xiàn)在? ComponentA 和 ComponentC 都可以在 ComponentB 的模板中使用了。

基礎組件的自動化全局注冊

可能你的許多組件只是包裹了一個輸入框或按鈕之類的元素债热,是相對通用的砾嫉。我們有時候會把它們稱為基礎組件,它們會在各個組件中被頻繁的用到窒篱。

所以會導致很多組件里都會有一個包含基礎組件的長列表:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末焕刮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墙杯,更是在濱河造成了極大的恐慌配并,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件高镐,死亡現(xiàn)場離奇詭異溉旋,居然都是意外死亡,警方通過查閱死者的電腦和手機嫉髓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門观腊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人算行,你說我怎么就攤上這事梧油。” “怎么了州邢?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵儡陨,是天一觀的道長。 經(jīng)常有香客問我偷霉,道長,這世上最難降的妖魔是什么褐筛? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任类少,我火速辦了婚禮,結(jié)果婚禮上渔扎,老公的妹妹穿的比我還像新娘硫狞。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布残吩。 她就那樣靜靜地躺著财忽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪泣侮。 梳的紋絲不亂的頭發(fā)上即彪,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音活尊,去河邊找鬼隶校。 笑死,一個胖子當著我的面吹牛蛹锰,可吹牛的內(nèi)容都是我干的深胳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼铜犬,長吁一口氣:“原來是場噩夢啊……” “哼舞终!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起癣猾,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤敛劝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后煎谍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攘蔽,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年呐粘,在試婚紗的時候發(fā)現(xiàn)自己被綠了满俗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡作岖,死狀恐怖唆垃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情痘儡,我是刑警寧澤辕万,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站沉删,受9級特大地震影響渐尿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜矾瑰,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一砖茸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧殴穴,春花似錦凉夯、人聲如沸货葬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽震桶。三九已至,卻和暖如春征绎,著一層夾襖步出監(jiān)牢的瞬間蹲姐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工炒瘸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淤堵,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓顷扩,卻偏偏與公主長得像拐邪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子隘截,可洞房花燭夜當晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 每個 Vue 應用都是通過用 Vue 函數(shù)創(chuàng)建一個新的 Vue 實例開始的: 實例生命周期鉤子 每個 Vue 實例...
    Timmy小石匠閱讀 1,372評論 0 11
  • Vue.js是什么 Vue.js是一個漸進式javascript框架婶芭,漸進式就是由淺入深东臀、由簡單到復雜的方式去使用...
    A鄭家慶閱讀 1,099評論 0 2
  • 什么是組件? 組件 (Component) 是 Vue.js 最強大的功能之一犀农。組件可以擴展 HTML 元素惰赋,封裝...
    youins閱讀 9,451評論 0 13
  • 慕課網(wǎng)Vue基礎知識學習 1.基礎知識 掛載點: el對應的id 模板:指的就是掛載點DOM內(nèi)部的標簽內(nèi)容,可以在...
    果木山閱讀 666評論 0 2
  • 主要還是自己看的呵哨,所有內(nèi)容來自官方文檔赁濒。 介紹 Vue.js 是什么 Vue (讀音 /vju?/,類似于 vie...
    Leonzai閱讀 3,329評論 0 25