Vuejs知識點彙總
元件
- 元件是可複用的 Vue 例項,且帶有一個名字
- 每用一次元件,就會有一個它的新例項被建立
- data 必須是一個函式
data: function () { return { count: 0 } }
1. 註冊元件
-
全域性註冊
可以用在任何新建立的 Vue 根例項的模板中。第一個引數是元件名
Vue.component('my-component-name', { // ... options ... })
-
區域性註冊
即在哪註冊在哪用,這樣就不會過多的佔用記憶體,首先註冊一個區域性元件
var ComponentA={ props:['title'], template:`<h3>{{title}}</h3>` }
然後例項的
components
物件中使用,屬性名就是元件名,屬性值就是你想傳入的元件new Vue({ el: '#app', components:{ 'blog-title':ComponentA } })
注意:推薦使用kebab-case(短橫線分割命名)給元件命名,例如該例子中的
<blog-title>
,否則容易報錯:
注意:每個元件必須只有一個根元素,即
template
裡只能有一個根標籤
2. Prop
#prop大小寫
prop對大小寫不敏感,所以可以這樣使用:
Vue.component('blog', { props: ['postTitle'], template: '<h3>{{ postTitle }}</h3>' })
<blog post-title="hello!"></blog>
#prop型別
一般情況下是以字串陣列形式列出的 prop:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
也可以給每個prop指定值型別。屬性名是prop名稱,屬性值是prop型別
props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object, callback: Function, contactsPromise: Promise // or any other constructor } //也可以是Data、Symbol
#傳遞prop
一個例子
Vue.component('blog-post', {
props: ['title'], //給元件定義一個屬性
template: '<h3>{{ title }}</h3>'
})
<blog-post title="My journey with Vue"></blog-post> //傳值
-
靜態傳遞
# 傳入字串 <blog-post title="My journey with Vue"></blog-post> #有時候需要用v-bind告訴vue這是一個js表示式而不是字串 # 傳入布林值, <blog-post :is-published="false"></blog-post> # 傳入陣列 <blog-post :comment-ids="[234, 266, 273]"></blog-post> # 傳入物件 <blog-post :author="{name: 'Veronica',company: 'Veridian Dynamics'}"></blog-post> # 傳入一個物件所有的屬性
-
動態傳遞
new Vue({ el: '#blog', data: { posts: [ { id: 1, title: 'My journey with Vue' }, { id: 2, title: 'Blogging with Vue' }, { id: 3, title: 'Why Vue is so fun' } ] } })
<blog-post v-for="post in posts" :key="post.id" :title="post.title" ></blog-post>
當需要傳遞的屬性很多時,可以將這些屬性成合成一個。在這個例子中,可以把所有
post
所有的屬性如title、content寫在一個post
中:
-
重構元件
原本子元件
Vue.component('blog-post', { props: ['title','content'], template: ` <div> <h3>{{ title }}</h3> <div v-html="content"></div> </div> ` })
現在子元件
Vue.component('blog-post', { props: ['post'], template: ` <div> <h3>{{ post.title }}</h3> <div v-html="post.content"></div> </div> ` })
-
建立例項
new Vue({ el: '#blog', data: { posts: [ { id: 1, title: 'My journey with Vue',content:'111' }, { id: 2, title: 'Blogging with Vue',content:'222' }, { id: 3, title: 'Why Vue is so fun',content:'333'} ] } })
-
在例項中使用元件
原本父級
<blog-post v-for="post in posts" :key="post.id" :title="post.title" :content="post.comtent"></blog-post>
現在父級
<blog-post v-for="post in posts" :key="post.id" :post="post"></blog-post>
#單項資料流
父級 prop 的更新會向下流動到子元件中,但是反過來則不行
#prop驗證
可以為元件的 prop 指定驗證要求。
- 當 prop 驗證失敗的時候,(開發環境構建版本的) Vue 將會產生一個控制檯的警告。
- prop 會在一個元件例項建立之前進行驗證
Vue.component('my-component', {
props: {
//1. 基礎的型別檢查 (null和undefined會通過任何型別驗證)
propA: Number,
//2. 多個可能的型別
propB: [String, Number],
//3. 必填的字串
propC: {
type: String,
required: true
},
//4. 帶有預設值的數字
propD: {
type: Number,
default: 100
},
//5.自定義驗證函式。下面例子表示必須匹配下列字串中的一個
propF: {
validator: function (value) {
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
3. 自定義事件
#事件名
推薦始終使用 kebab-case 的事件名
this.$emit('my-event')
<my-component @my-event="doSomething"></my-component>
#監聽子元件事件
-
建立例項
new Vue({ el: '#demo', data: { posts: [/* ... */], postFontSize: 1 } })
-
用
$emit
給子元件新增事件Vue.component('blog-post', { props: ['post'], template: ` //... <button @click="$emit('enlarge-text')">Enlarge</button> //... ` })
-
v-on
監聽子元件事件。當子元件觸發時,開始響應<div id="demo"> <div :style="{ fontSize: postFontSize + 'em' }"> <blog-post ... @enlarge-text="postFontSize += 0.1" ></blog-post> </div> </div>
$emit
可以接收第二個引數
-
給子元件事件新增引數
<button v-on:click="$emit('enlarge-text', 0.1)">Enlarge</button>
-
父級通過
$event
獲取整個引數值<blog-post ... @enlarge-text="postFontSize += $event" ></blog-post>
第二種寫法:
<blog-post ... @enlarge-text="enlargeText" ></blog-post>
傳過來的引數值會作為該方法的第一個引數
methods: { enlargeText: function (num) { this.postFontSize += num } }
#自定義事件中的v-model
-
普通情況下自定義事件
<input v-model="searchText">
等價於
<input :value="searchText" @input="searchText = $event.target.value">
-
在元件上自定義事件
<custom-input v-model="searchText"/>
等價於
<custom-input :value="searchText" @input="searchText = $event"/>
這時候需要更改子元件,才能讓其正常運作。
Vue.component('custom-input', { props: ['value'], template: ` <input :value="value" @input="$emit('input', $event.target.value)" > ` })
解析:這時子元件的
input
觸發時,會丟擲$event.target.value
,父級會監聽到並接收$event.target.value
。此時父級的$event
實際上就等於子元件丟擲的$event.target.value
,變化後的searchText
的值會繫結在父級的value上,然後通過props
傳回子元件,子元件接收到這個props值後就繫結在input
的value上,這時候就在頁面呈現出效果了
#繫結原生事件
使用 v-on
的 .native
修飾符:
<base-input @focus.native="onFocus"></base-input>
注意:
.native
監聽的是元件的根元素。如果想監聽到子元素,需要用到$listeners
物件
4. 插槽
#一個例子
-
在子元件模板中加上一個插槽
<slot></slot>
Vue.component('alert-box', { template: ` <div> <strong>Error!</strong> <slot></slot> </div> ` })
-
在父級元件內新增內容後,內容就會自動放進插槽內
<alert-box>Something bad happened.</alert-box>
注意:如果子的
template
中沒有包含一個slot
元素,則該元件起始標籤和結束標籤之間的任何內容都會被拋棄
#預設內容
預設內容會在沒有提供內容的時候被渲染。只需要將內容放在slot
中:
//在一個子元件的template中
<button>
<slot>Submit</slot>
</button>
//1. 父級中沒有新增任何內容
<submit-button></submit-button>
// 渲染後備內容:
<button>Submit</button>
//2. 父級中有內容
<submit-button>Save</submit-button>
// 後備內容會被取代:
<button>Save</button>
#具名插槽
當我們需要多個插槽時,具名插槽很有用:
-
元件模板中,給
slot
新增name
屬性//假設這是base-layout元件的模板,需要分別給header、main、footer新增插槽: <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> //這個插槽沒有名字,name的值預設為default </main> <footer> <slot name="footer"></slot> </footer> </div>
-
父級中,用帶有
v-slot
的template
包裹內容,v-slot
指定插槽名稱<base-layout> <template v-slot:header> <h1>I am a header</h1> </template> //任何沒有按規定包裹的內容都會被視為預設插槽的內容 <p>A paragraph for the main content.</p> <p>And another one.</p> <template v-slot:footer> <p>I am a footer</p> </template> </base-layout>
v-slot
可以縮寫:<template #header> <h1>I am a header</h1> </template>
#編譯作用域
插槽的作用域與例項相同。即能訪問到例項的資料,而不能訪問元件的資料
//可以訪問
<navigation-link url="/profile">{{ user.name }}</navigation-link>
//不可以訪問
<navigation-link url="/profile">{{ url }}</navigation-link>
#插槽作用域
如果想在父級插槽內容中訪問到子元件的資料
-
在子元件的
slot
中繫結資料Vue.component('user-info', { //user作為屬性繫結資料。在這裡user屬性被稱為插槽prop template: `<span><slot :user="userdata">{{userdata.current}}</slot></span>`, data:()=>({ userdata:{ before:'lihua', current:'xiaoming' } }), })
-
用
v-slot
來定義插槽 prop 的名字。名字也可以是其他<user-info v-slot:default="slotProps"> {{slotProps.user.before}} </user-info>
由於指定的插槽是default,所以以上也可以簡寫成:注意不要與具名插槽混淆
<user-info v-slot="slotProps"> {{slotProps.user.before}} </user-info>
自 2.6.0 起有所更新。已廢棄的使用
slot-scope
。
# 動態插槽名
<base-layout>
<template v-slot:[dynamicSlotName]>
...
</template>
</base-layout>
5. 動態元件
如果在一個多標籤介面實現元件切換,可以通過 Vue 的 <component>
元素加一個特殊的 is
attribute 來實現::
<!-- 切換tab值 -->
<button v-for="tab in tabs" :key="tab" @click="currentTab = tab">{{tab}}</button>
<!-- 元件會在 `currentTabComponent` 改變時改變 -->
<component v-bind:is="currentTabComponent"></component>
Vue.component("com1", {
template: "<div>com1</div>"
});
Vue.component("com2", {
template: "<div>com2</div>"
});
Vue.component("com3", {
template: "<div>com3</div>"
});
new Vue({
el: '#app',
data:{
currentTab:"com1",
tabs:["com1", "com2", "com3"]
},
computed: {
//currentTabComponent可以是已註冊元件的名字,或一個元件的選項物件
currentTabComponent: function () {
return this.currentTab
}
}
})