Vue高級特性概念原理詳細(xì)分析
1. 自定義v-model
Vue中的自定義v-model指的是在自定義組件中使用v-model語法糖來實現(xiàn)雙向綁定。在Vue中,通過v-model指令可以將表單元素的值與組件實例的數(shù)據(jù)進(jìn)行雙向綁定。但是對于自定義組件,如果要實現(xiàn)v-model的雙向綁定,就需要自定義v-model的實現(xiàn)方式。
自定義v-model需要在自定義組件中提供一個value屬性和一個input事件,并在組件模板中使用v-bind將value屬性(text1)綁定到input元素的value屬性上,并通過v-on監(jiān)聽input事件,當(dāng)input事件觸發(fā)時將輸入框的值通過$emit方法發(fā)送出去。這樣就可以在父組件中使用v-model語法糖來實現(xiàn)自定義組件的雙向綁定了。
下面是一個自定義組件v-model的實例代碼:
<!-- ChildComponent.vue -->
<template>
<div>
<input :value="text1" @input="$emit('change1', $event.target.value)">
</div>
</template>
<script>
export default {
model: {
prop: 'text1',
event: 'change1'
},
props: {
text1 : String,
default(){
return ''
}
},
// ...
}
</script>
在父組件中使用該組件,并使用v-model語法糖實現(xiàn)雙向數(shù)據(jù)綁定:
<!-- ParentComponent.vue -->
<template>
<div>
<child-component v-model="message"></child-component>
<p>Message: {{ message }}</p>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: { ChildComponent },
data() {
return {
message: ''
}
}
}
</script>
2. $nextTick
在Vue中,$nextTick是一個實例方法,它用于在DOM更新完成后執(zhí)行一些操作,例如修改DOM、操作DOM元素等。它的作用是將回調(diào)函數(shù)延遲到下次DOM更新循環(huán)之后執(zhí)行,從而確保在回調(diào)函數(shù)執(zhí)行時,DOM已經(jīng)被更新了。
$nextTick會將回調(diào)函數(shù)放入一個隊列中,在下次DOM更新循環(huán)時執(zhí)行該隊列中的所有回調(diào)函數(shù)。這個過程可以確保在回調(diào)函數(shù)執(zhí)行時,DOM已經(jīng)被更新,因此可以進(jìn)行一些操作,例如獲取更新后的DOM節(jié)點、修改DOM屬性等。
下面是一個使用$nextTick方法,獲取組件data更新后的DOM長度的代碼:
<template>
<div id="app">
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{{item}}
</li>
</ul>
<button @click="addItem">添加一項</button>
</div>
</template>
<script>
export default {
name: 'app',
data() {
return {
list: ['a', 'b', 'c']
}
},
methods: {
addItem() {
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.list.push(`${Date.now()}`)
this.$nextTick(() => {
// 獲取 DOM 元素
const ulElem = this.$refs.ul1
// eslint-disable-next-line
console.log( ulElem.childNodes.length )
})
}
}
}
</script>
每點擊’添加一項‘按鈕后,會更新List數(shù)組,在數(shù)組中新添加3個元素,并打印出DOM元素的長度。如果不使用$nextTick方法,那么在第一次點擊后打印的數(shù)字為3,然而DOM元素實際長度已經(jīng)變?yōu)?了。下面是使用$nextTick方法的效果圖,在第一次點擊按鈕后,打印的數(shù)字就是6。

3. slot 插槽
基本使用
使用插槽的目的是父組件需要向子組件中插入一段內(nèi)容。
<!-- 父組件 -->
<template>
<div>
<p>vue 高級特性</p>
<hr>
<!-- slot -->
<SlotDemo :url="website.url">
{{website.title}}
</SlotDemo>
</div>
</template>
<script>
import SlotDemo from './SlotDemo'
export default {
components: {
SlotDemo,
},
data() {
return {
name: '雙越',
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序員的夢工廠'
},
}
}
}
</script>
<!-- 子組件 -->
<template>
<a :href="url" rel="external nofollow" rel="external nofollow" >
<slot>
默認(rèn)內(nèi)容,即父組件沒設(shè)置內(nèi)容時,這里顯示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {}
}
}
</script>

作用域插槽 ScopedSlot
父組件希望使用子組件中的data數(shù)據(jù)作為插槽中的內(nèi)容,可以使用作用域插槽。
<!-- 父組件 -->
<template>
<div>
<p>vue 高級特性</p>
<hr>
<!-- 作用域插槽寫法 -->
<ScopedSlotDemo :url="website.url">
<template v-slot="slotProps">
{{slotProps.slotData.title}}
</template>
</ScopedSlotDemo>
</div>
</template>
<script>
import ScopedSlotDemo from './ScopedSlotDemo'
export default {
components: {
ScopedSlotDemo,
},
data() {
return {
name: '雙越',
website: {
url: 'http://imooc.com/',
title: 'imooc',
subTitle: '程序員的夢工廠'
},
}
}
}
</script>
<!-- 子組件 -->
<template>
<a :href="url" rel="external nofollow" rel="external nofollow" >
<slot :slotData="website">
{{website.subTitle}} <!-- 默認(rèn)值顯示 subTitle ,即父組件不傳內(nèi)容時 -->
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
data() {
return {
website: {
url: 'http://wangEditor.com/',
title: 'wangEditor',
subTitle: '輕量級富文本編輯器'
}
}
}
}
</script>

具名插槽
Vue中的具名插槽是指可以在一個組件中定義多個插槽,并使用不同的名稱來標(biāo)識它們的用途。相對于默認(rèn)插槽,具名插槽可以更靈活地定制組件的樣式和行為。
具名插槽可以在組件內(nèi)部使用<slot>標(biāo)簽進(jìn)行定義,同時可以通過在<slot>標(biāo)簽上添加name屬性來指定插槽的名稱。如果在組件的使用者中,需要為具名插槽提供自定義的內(nèi)容,可以使用v-slot指令來綁定具名插槽。

4. Vue 動態(tài)組件
Vue動態(tài)組件是一種在運行時動態(tài)選擇要渲染的組件的技術(shù)。它可以根據(jù)不同的條件渲染不同的組件,從而使應(yīng)用程序更加靈活和可擴展。在Vue中,使用特殊的組件元素<component>來實現(xiàn)動態(tài)組件。<component>元素有一個is屬性,它可以接受一個組件名或一個組件對象。當(dāng)is屬性的值發(fā)生變化時,<component>元素會銷毀當(dāng)前組件實例并創(chuàng)建一個新的組件實例。
下面給出一個動態(tài)組件的使用場景:
假設(shè)我們有兩個組件,一個是LoginForm,一個是SignupForm,它們分別表示登錄和注冊表單。我們希望根據(jù)用戶點擊的按鈕來動態(tài)選擇展示哪個表單。首先,需要在父組件中定義兩個子組件,并設(shè)置一個變量currentForm來控制當(dāng)前展示的組件,在這個父組件中,我們引入LoginForm和SignupForm組件,并使用<component>元素動態(tài)渲染它們。這里currentForm變量初始值為空字符串,因此初始時不會渲染任何組件。當(dāng)用戶點擊"登錄"或“注冊”按鈕時,我們可以通過調(diào)用showLoginForm和showSignupForm方法來更新currentForm變量的值,從而動態(tài)渲染對應(yīng)的表單組件。
<!--父組件-->
<template>
<div>
<button @click="showLoginForm">登錄</button>
<button @click="showSignupForm">注冊</button>
<component :is="currentForm"></component>
</div>
</template>
<script>
import LoginForm from './LoginForm.vue'
import SignupForm from './SignupForm.vue'
export default {
components: {
LoginForm,
SignupForm
},
data() {
return {
currentForm: ''
}
},
methods: {
showLoginForm() {
this.currentForm = 'LoginForm'
},
showSignupForm() {
this.currentForm = 'SignupForm'
}
}
}
</script>
我們需要在子組件中定義具體的表單。假設(shè)LoginForm和SignupForm組件分別是以下形式:
<!--LoginForm.vue-->
<template>
<form>
<input type="text" placeholder="用戶名">
<input type="password" placeholder="密碼">
<button type="submit">登錄</button>
</form>
</template>
<!--SignupForm.vue-->
<template>
<form>
<input type="text" placeholder="用戶名">
<input type="password" placeholder="密碼">
<input type="password" placeholder="確認(rèn)密碼">
<button type="submit">注冊</button>
</form>
</template>
5. Vue 異步組件
異步組件與常規(guī)組件的不同之處在于,異步組件只有在需要的時候才會被加載,而不是在應(yīng)用初始化時就被全部加載。異步組件的應(yīng)用場景是:當(dāng)某個組件的體積比較大時,例如Echarts文件,如果應(yīng)用初始化時就加載,會非常慢,嚴(yán)重影響性能。此時可以將該組件設(shè)置為異步組件,在需要使用該組件時,再加載該組件。異步組件通過import()函數(shù)引入。
以下代碼中的FormDemo組件中包含多個表單,可以通過將其設(shè)置為異步組件,在需要的時候再將其加載。
<template>
<div>
<p>vue 高級特性:異步組件</p>
<hr>
<!-- 異步組件 -->
<FormDemo v-if="showFormDemo"/>
<button @click="showFormDemo = true">show form demo</button>
</div>
</template>
<script>
export default {
components: {
FormDemo: () => import('./FormDemo'), // 使用import函數(shù),引入需要異步渲染的組件
},
data() {
return {},
showFormDemo: false // 首先將異步組件的 v-if 屬性值設(shè)置為 false
}
}
</script>

6. 使用 keep-alive 緩存組件
keep-alive是Vue內(nèi)置的一個組件,可以將其用于需要緩存的動態(tài)組件,避免每次重新渲染時都要執(zhí)行組件的 created() 、mounted()、destoryed()等鉤子函數(shù),從而提高組件的性能。
keep-alive 組件可以包裹動態(tài)組件,使其被緩存。被緩存的組件在組件切換時并不會被銷毀,而是被保留在內(nèi)存中,下次需要渲染時直接從緩存中讀取組件實例,避免了組件的重新創(chuàng)建和重新渲染。
<template>
<div>
<button @click="changeState('A')">A</button>
<button @click="changeState('B')">B</button>
<button @click="changeState('C')">C</button>
<keep-alive>
<KeepAliveStageA v-if="state === 'A'"/>
<KeepAliveStageB v-if="state === 'B'"/>
<KeepAliveStageC v-if="state === 'C'"/>
</keep-alive>
</div>
</template>
<script>
import KeepAliveStageA from './KeepAliveStateA'
import KeepAliveStageB from './KeepAliveStateB'
import KeepAliveStageC from './KeepAliveStateC'
export default {
components: {
KeepAliveStageA,
KeepAliveStageB,
KeepAliveStageC
},
data() {
return {
state: 'A'
}
},
methods: {
changeState(state) {
this.state = state
}
}
}
</script>
<!--KeepAliveStageA組件-->
<template>
<p>state A</p>
</template>
<script>
export default {
mounted() {
console.log('A mounted')
},
destroyed() {
console.log('A destroyed')
}
}
</script>
<!--KeepAliveStageB組件-->
<template>
<p>state B</p>
</template>
<script>
export default {
mounted() {
console.log('B mounted')
},
destroyed() {
console.log('B destroyed')
}
}
</script>
<!--KeepAliveStageC組件-->
<template>
<p>state C</p>
</template>
<script>
export default {
mounted() {
console.log('C mounted')
},
destroyed() {
console.log('C destroyed')
}
}
</script>
當(dāng)組件沒有被keep-alive組件包裹時,每次渲染新的組件就會執(zhí)行當(dāng)前已渲染組件的destoryed()函數(shù),然后再執(zhí)行需要渲染組件的mounted()函數(shù),效果如下圖所示:

如果將需要渲染的組件通過keep-alive組件包裹起來,那么當(dāng)前頁面中已渲染的組件不會執(zhí)行destoryed()函數(shù),渲染過的組件也不會再次執(zhí)行mounted()函數(shù),效果如下圖所示:

7. mixin 混入
在Vue中,mixin是一種可重用組件的機制,它可以將一組選項混入到多個Vue組件中。使用mixin,可以將通用的選項抽象出來,然后在需要的組件中混入這些選項,從而實現(xiàn)代碼復(fù)用和邏輯共享。
mixin存在一些問題:
- 變量來源不明確,不利于閱讀
- 多個mixin可能會造成命名沖突
- mixin和組件可能會出現(xiàn)多對多的關(guān)系,復(fù)雜度高
<template>
<div>
<p>{{name}} {{major}} {{city}}</p>
<button @click="showName">顯示姓名</button>
</div>
</template>
<script>
import myMixin from './mixin'
export default {
mixins: [myMixin], // 可以添加多個,會自動合并起來
data() {
return {
name: '小明',
major: 'web 前端'
}
},
methods: {
},
mounted() {
console.log('component mounted', this.name)
}
}
</script>
混入的文件通常是一個js文件:
// mixin.js
export default {
data() {
return {
city: '北京'
}
},
methods: {
showName() {
console.log(this.name)
}
},
mounted() {
console.log('mixin mounted', this.name)
}
}

到此這篇關(guān)于Vue高級特性概念原理詳細(xì)分析的文章就介紹到這了,更多相關(guān)Vue高級特性內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
axios 實現(xiàn)post請求時把對象obj數(shù)據(jù)轉(zhuǎn)為formdata
今天小編就為大家分享一篇axios 實現(xiàn)post請求時把對象obj數(shù)據(jù)轉(zhuǎn)為formdata,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10

