国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解vue高級(jí)特性

瀏覽:64日期:2023-01-14 14:14:40

Vue為我們提供了很多高級(jí)特性,學(xué)習(xí)和掌握它們有助于提高你的代碼水平。

一、watch進(jìn)階

從我們剛開(kāi)始學(xué)習(xí)Vue的時(shí)候,對(duì)于偵聽(tīng)屬性,都是簡(jiǎn)單地如下面一般使用:

watch:{a(){ //doSomething}}

實(shí)際上,Vue對(duì)watch提供了很多進(jìn)階用法。

handler函數(shù)

以對(duì)象和handler函數(shù)的方式來(lái)定義一個(gè)監(jiān)聽(tīng)屬性,handler就是處理監(jiān)聽(tīng)變動(dòng)時(shí)的函數(shù):

watch:{a:{handler:’doSomething’}},methods:{doSomething(){//當(dāng) a 發(fā)生變化的時(shí)候,做些處理}}

handler有啥用?是多此一舉么?用途主要有兩點(diǎn):

1 將處理邏輯抽象出去了,以method的方式被復(fù)用

2 給定義下面兩個(gè)重要屬性留出了編寫(xiě)位置

deep屬性

不知道你注意到了沒(méi)有?

當(dāng)watch的是一個(gè)Object類型的數(shù)據(jù),如果這個(gè)對(duì)象內(nèi)部的某個(gè)值發(fā)生了改變,并不會(huì)觸發(fā)watch動(dòng)作!

也就是說(shuō),watch默認(rèn)情況下,不監(jiān)測(cè)內(nèi)部嵌套數(shù)據(jù)的變動(dòng)。但是很多情況下,我們是需要監(jiān)測(cè)的!

為解決這一問(wèn)題,就要使用deep屬性:

watch:{obj:{handler:’doSomething’,deep:true}},methods:{doSomething(){//當(dāng) obj 發(fā)生變化的時(shí)候,做些處理}}

deep屬性默認(rèn)為false,也就是我們常用的watch模式。

immediate屬性

watch 的handler函數(shù)通常情況下只有在監(jiān)聽(tīng)的屬性發(fā)生改變時(shí)才會(huì)觸發(fā)。

但有些時(shí)候,我們希望在組件創(chuàng)建后,或者說(shuō)watch被聲明和綁定的時(shí)候,立刻執(zhí)行一次handler函數(shù),這就需要使用immediate屬性了,它默認(rèn)為false,改為true后,就會(huì)立刻執(zhí)行handler。

watch:{obj:{handler:’doSomething’,deep:true,immediate:true}},methods:{doSomething(){//當(dāng) obj 發(fā)生變化的時(shí)候,做些處理}}

同時(shí)執(zhí)行多個(gè)方法

使用數(shù)組可以設(shè)置多項(xiàng),形式包括字符串、函數(shù)、對(duì)象

watch: { // 你可以傳入回調(diào)數(shù)組,它們會(huì)被逐一調(diào)用 a: [ ’handle1’, function handle2 (val, oldVal) { /* ... */ }, { handler: function handle3 (val, oldVal) { /* ... */ }, /* ... */ } ], }

二、$event的不同表現(xiàn)

$event 是事件對(duì)象的特殊變量,在兩種場(chǎng)景下,它有不同的意義,代表不同的對(duì)象。

1 在原生事件中表示事件本身。可以通過(guò)$event.target獲得事件所在的DOM對(duì)象,再通過(guò)value進(jìn)一步獲取具體的值。

<template> <div> <input type='text' @input='inputHandler(’hello’, $event)' /> </div></template>export default { methods: { inputHandler(msg, e) { console.log(e.target.value) } }}

2 而在父子組件通過(guò)自定義事件進(jìn)行通信時(shí),表示從子組件中傳遞出來(lái)的參數(shù)值

看下面的例子:

//blog-post組件的模板<button v-on:click='$emit(’enlarge-text’, 0.1)'> Enlarge text</button>

在父級(jí)組件監(jiān)聽(tīng)這個(gè)事件的時(shí)候,可以通過(guò) $event 訪問(wèn)到blog-post子組件傳遞出來(lái)的0.1這個(gè)值:

<blog-post ... v-on:enlarge-text='postFontSize += $event'></blog-post>

此時(shí),$event的值就是0.1,而不是前面的事件對(duì)象。

三、異步更新隊(duì)列

1 Vue 在更新 DOM 時(shí)是異步執(zhí)行的。

2 只要偵聽(tīng)到數(shù)據(jù)變化,Vue 將開(kāi)啟一個(gè)隊(duì)列,并緩沖在同一事件循環(huán)中發(fā)生的所有數(shù)據(jù)變更。

3 如果同一個(gè) watcher 被多次觸發(fā),只會(huì)被推入到隊(duì)列中一次。

這種在緩沖時(shí)去除重復(fù)數(shù)據(jù)對(duì)于避免不必要的計(jì)算和 DOM 操作是非常重要的。然后,在下一個(gè)的事件循環(huán)“tick”中,Vue 刷新隊(duì)列并執(zhí)行實(shí)際 (已去重的) 工作。Vue 在內(nèi)部對(duì)異步隊(duì)列嘗試使用原生的 Promise.then、MutationObserver 和 setImmediate,如果執(zhí)行環(huán)境不支持,則會(huì)采用 setTimeout(fn, 0) 代替。

例如,當(dāng)你設(shè)置 vm.someData = ’new value’,該組件不會(huì)立即重新渲染。當(dāng)刷新隊(duì)列時(shí),組件會(huì)在下一個(gè)事件循環(huán)“tick”中更新。

多數(shù)情況我們不需要關(guān)心這個(gè)過(guò)程,但是如果你想基于更新后的 DOM 狀態(tài)來(lái)做點(diǎn)什么,這就可能會(huì)有些棘手。

雖然 Vue.js 通常鼓勵(lì)開(kāi)發(fā)人員使用“數(shù)據(jù)驅(qū)動(dòng)”的方式思考,避免直接接觸 DOM,但是有時(shí)我們必須要這么做。為了在數(shù)據(jù)變化之后等待 Vue 完成更新 DOM,可以在數(shù)據(jù)變化之后立即使用 Vue.nextTick(callback)。

這樣回調(diào)函數(shù)將在 DOM 更新完成后被調(diào)用。例如:

<div id='example'>{{message}}</div>var vm = new Vue({ el: ’#example’, data: { message: ’123’ }})vm.message = ’new message’ // 更改數(shù)據(jù)vm.$el.textContent === ’new message’ // falseVue.nextTick(function () { vm.$el.textContent === ’new message’ // true})

在組件內(nèi)使用 vm.$nextTick() 實(shí)例方法特別方便,因?yàn)樗恍枰?Vue,并且回調(diào)函數(shù)中的 this 將自動(dòng)綁定到當(dāng)前的 Vue 實(shí)例上:

因?yàn)?$nextTick() 返回一個(gè) Promise 對(duì)象,所以你可以使用新的 ES2017 async/await 語(yǔ)法完成相同的事情:

methods: { updateMessage: async function () { this.message = ’已更新’ //在這里可以看出,message并沒(méi)有立刻被執(zhí)行 //要理解頁(yè)面刷新和代碼執(zhí)行速度的差別 //通常我們?cè)陧?yè)面上立刻就能看到結(jié)果,那是因?yàn)橐惠嗞?duì)列執(zhí)行其實(shí)很快,感覺(jué)不出DOM刷新的過(guò)程和所耗費(fèi)的時(shí)間 //但對(duì)于代碼的執(zhí)行,屬于即刻級(jí)別,DOM沒(méi)更新就是沒(méi)更新,就是會(huì)有問(wèn)題 console.log(this.$el.textContent) // => ’未更新’ await this.$nextTick() console.log(this.$el.textContent) // => ’已更新’ }}

通俗的解釋:

1 Vue的DOM刷新機(jī)制是個(gè)異步隊(duì)列,并不是你想象中的立刻、馬上、即時(shí)更新!

2 這個(gè)異步隊(duì)列是一輪一輪的執(zhí)行并刷新

3 上面帶來(lái)的問(wèn)題是,一些依賴DOM更新完畢才能進(jìn)行的操作(比如對(duì)新增加的DOM元素進(jìn)行事件綁定),無(wú)法立刻執(zhí)行,必須等待一輪隊(duì)列執(zhí)行完畢

4 最容易碰到上面問(wèn)題的地方:created生命周期鉤子函數(shù)中對(duì)DOM進(jìn)行操作

5 解決辦法:使用this.nextTick(回調(diào)函數(shù))方法,將對(duì)DOM的操作作為它的回調(diào)函數(shù)使用。

四、函數(shù)式組件

因?yàn)閭鹘y(tǒng)編寫(xiě)模板的能力不足,我們引入了渲染函數(shù)createElement。我們又希望獲得更多的靈活度,于是引入了JSX。最后,我們發(fā)現(xiàn)有些簡(jiǎn)單的模板可以更簡(jiǎn)單更小巧的實(shí)現(xiàn),于是引入了函數(shù)式組件。Vue總是試圖為每一種場(chǎng)景提供不同的能力。

有這么一類組件,它的特點(diǎn)是:

1 比較簡(jiǎn)單

2 沒(méi)有管理任何狀態(tài),也就是說(shuō)無(wú)狀態(tài),沒(méi)有響應(yīng)式數(shù)據(jù)

3 沒(méi)有監(jiān)聽(tīng)任何傳遞給它的狀態(tài)

4 沒(méi)有寫(xiě)生命周期方法

5 本質(zhì)上只是一個(gè)接收一些prop的函數(shù)

6 沒(méi)有實(shí)例,沒(méi)有this上下文

那么這個(gè)組件可以定義為函數(shù)式組件。與普通組件相比,函數(shù)式組件是無(wú)狀態(tài)的,無(wú)法實(shí)例化,沒(méi)有任何的生命周期和方法,適合只依賴于外部數(shù)據(jù)的變化而變化的組件,因其輕量,渲染性能會(huì)有所提高。

創(chuàng)建函數(shù)式組件

以定義全局組件的方式

Vue.component(’my-component’, { functional: true, // Props 是可選的 props: { // ... }, // 為了彌補(bǔ)缺少的實(shí)例 // 提供第二個(gè)參數(shù)作為上下文 render: function (createElement, context) { // ... }})

注意其中的functional: true,

在 Vue 2.3.0 或以上的版本中,你可以省略 props 選項(xiàng),所有組件上的 attribute 都會(huì)被自動(dòng)隱式解析為 prop。

當(dāng)使用函數(shù)式組件時(shí),該引用將會(huì)是 HTMLElement,因?yàn)樗麄兪菬o(wú)狀態(tài)的也是無(wú)實(shí)例的。

對(duì)于單文件組件,創(chuàng)建函數(shù)式組件的方式是在模板標(biāo)簽內(nèi),添加functional屬性

<template functional>...</template><script>...</script><style>...</style>

最重要的context參數(shù)

因?yàn)闊o(wú)狀態(tài),沒(méi)有this上下文,所以函數(shù)式組件需要的一切都是通過(guò) context 參數(shù)來(lái)傳遞,它是一個(gè)包括如下字段的對(duì)象:

props:提供所有 prop 的對(duì)象

children:VNode 子節(jié)點(diǎn)的數(shù)組

slots:一個(gè)函數(shù),返回了包含所有插槽的對(duì)象

scopedSlots:(2.6.0+) 一個(gè)暴露傳入的作用域插槽的對(duì)象。也以函數(shù)形式暴露普通插槽。

data:傳遞給組件的整個(gè)數(shù)據(jù)對(duì)象,作為 createElement 的第二個(gè)參數(shù)傳入組件

parent:對(duì)父組件的引用

listeners:(2.3.0+) 一個(gè)包含了所有父組件為當(dāng)前組件注冊(cè)的事件監(jiān)聽(tīng)器的對(duì)象。這是 data.on 的一個(gè)別名。

injections:(2.3.0+) 如果使用了 inject 選項(xiàng),則該對(duì)象包含了應(yīng)當(dāng)被注入的 property。

應(yīng)用場(chǎng)景

函數(shù)式組件的一個(gè)典型應(yīng)用場(chǎng)景是作為包裝組件,比如當(dāng)你碰到下面需求時(shí):

程序化地在多個(gè)組件中選擇一個(gè)來(lái)代為渲染;

在將 children、props、data 傳遞給子組件之前操作它們。

下面是一個(gè) smart-list 組件的例子,它能根據(jù)傳入 prop 的值來(lái)代為渲染更具體的組件:

var EmptyList = { /* ... */ }var TableList = { /* ... */ }var OrderedList = { /* ... */ }var UnorderedList = { /* ... */ }Vue.component(’smart-list’, { functional: true, props: { items: { type: Array, required: true }, isOrdered: Boolean }, render: function (createElement, context) { function appropriateListComponent () { var items = context.props.items if (items.length === 0) return EmptyList if (typeof items[0] === ’object’) return TableList if (context.props.isOrdered) return OrderedList return UnorderedList } return createElement( appropriateListComponent(), context.data, context.children ) }})

五、監(jiān)聽(tīng)子組件的生命周期

假如我們有父組件Parent和子組件Child,如果在父組件中需要監(jiān)聽(tīng)子組件的mounted這個(gè)生命周期函數(shù),并做一些邏輯處理,常規(guī)寫(xiě)法可能如下:

// Parent.vue<Child @mounted='doSth' />//Child.vuemounted(){ this.$emit(’mounted’);}

但是,Vue給我們提供了一種更簡(jiǎn)便的方法,子組件無(wú)需做任何處理,只需要在父組件引用子組件時(shí)使用@hook事件來(lái)監(jiān)聽(tīng)即可,代碼如下:

// Parent.vue<Child @hook:mounted='doSth' /> methods:{ doSth(){ //some codes here }}

核心是@hook:mounted='doSth'的寫(xiě)法!

當(dāng)然這里不僅僅可以監(jiān)聽(tīng)mounted,其他生命周期都可以監(jiān)聽(tīng),例如created、updated等。

六、樣式穿透

我們知道,在單文件組件的style中使用 scoped 屬性后,父組件的樣式將不會(huì)滲透到子組件中。

不過(guò)一個(gè)子組件的根節(jié)點(diǎn)會(huì)同時(shí)受其父組件的 scoped CSS 和子組件的 scoped CSS 的影響。這樣設(shè)計(jì)是為了讓父組件可以從布局的角度出發(fā),調(diào)整其子組件根元素的樣式。

如果你希望父組件的 scoped 樣式中的一個(gè)選擇器能夠作用得“更深”,例如影響子組件,可以使用深度選擇器: >>> 操作符。

<style scoped>.a >>> .b { /* ... */ }</style>

上述代碼將會(huì)編譯成:

.a[data-v-f3f3eg9] .b { /* ... */ }

但是,有些像 Sass 之類的預(yù)處理器無(wú)法正確解析 >>>。這種情況下你可以使用 /deep/ 或 ::v-deep 操作符,這兩者都是 >>> 的別名,實(shí)現(xiàn)同樣的功能。

我們都知道,通過(guò) v-html 創(chuàng)建的 DOM 內(nèi)容不受 scoped 樣式影響,可以通過(guò)深度作用選擇器>>>來(lái)為他們?cè)O(shè)置樣式。

七、路由的props屬性

一般在組件內(nèi)使用路由參數(shù),大多數(shù)人會(huì)這樣做:

export default { methods: { getParamsId() { return this.$route.params.id } }}

當(dāng)你隨便用用,臨時(shí)湊手,這沒(méi)什么問(wèn)題,畢竟解決了需求。

可我們要隨時(shí)謹(jǐn)記:組件是用來(lái)復(fù)用的!組件應(yīng)該有高度的封閉性!

在組件中使用 $route 會(huì)使它與路由系統(tǒng)形成高度耦合,從而使組件只能在使用了路由功能的項(xiàng)目?jī)?nèi),或某些特定的 URL 上使用,限制了其靈活性。

試想一下,如果你的組件被人拿去復(fù)用了,但是那個(gè)人并沒(méi)有使用路由系統(tǒng),而是通過(guò)別的方式傳遞id參數(shù),那么他該怎么辦?

正確的做法是通過(guò) props 解耦!

首先,為組件定義一個(gè)叫做id的prop:

export default { props: [’id’], methods: { getParamsId() { return this.id } }}

如果組件沒(méi)有對(duì)應(yīng)路由,那么這個(gè)id也可以通過(guò)父組件向子組件傳值的方式使用。

如果使用了路由,可以通過(guò)路由的prop屬性,傳遞id的值:

const router = new VueRouter({ routes: [{ path: ’/user/:id’, component: User, props: true }]})

將路由的 props 屬性設(shè)置為 true 后,組件內(nèi)可通過(guò) props 接收到 params 參數(shù)

另外,你還可以通過(guò)函數(shù)模式來(lái)返回 props

const router = new VueRouter({ routes: [{ path: ’/user/:id’, component: User, props: (route) => ({ id: route.query.id }) }]})

其實(shí),上面的技巧,在VueRouter的官檔都有說(shuō)明。

八、異步組件

在大型應(yīng)用中,我們可能需要將應(yīng)用分割成小一些的代碼塊,并且只在需要的時(shí)候才從服務(wù)器加載一個(gè)模塊。

為了簡(jiǎn)化,Vue 允許你以一個(gè)工廠函數(shù)的方式定義你的組件,這個(gè)工廠函數(shù)會(huì)異步解析你的組件定義。Vue 只有在這個(gè)組件需要被渲染的時(shí)候才會(huì)觸發(fā)該工廠函數(shù),且會(huì)把結(jié)果緩存起來(lái)供未來(lái)重渲染。例如:

Vue.component(’async-example’, function (resolve, reject) { setTimeout(function () { // 向 `resolve` 回調(diào)傳遞組件定義 resolve({ template: ’<div>I am async!</div>’ }) }, 1000)})

如你所見(jiàn),這個(gè)工廠函數(shù)會(huì)收到一個(gè) resolve 回調(diào),這個(gè)回調(diào)函數(shù)會(huì)在你從服務(wù)器得到組件定義的時(shí)候被調(diào)用。

你也可以調(diào)用 reject(reason) 來(lái)表示加載失敗。這里的 setTimeout 是為了演示用的,如何獲取組件取決于你自己。

一個(gè)推薦的做法是將異步組件和 webpack 的 code-splitting 功能一起配合使用:

Vue.component(’async-webpack-example’, function (resolve) { // 這個(gè)特殊的 `require` 語(yǔ)法將會(huì)告訴 webpack // 自動(dòng)將你的構(gòu)建代碼切割成多個(gè)包,這些包 // 會(huì)通過(guò) Ajax 請(qǐng)求加載 require([’./my-async-component’], resolve)})

你也可以在工廠函數(shù)中返回一個(gè) Promise,所以把 webpack 2 和 ES2015 語(yǔ)法加在一起,我們可以寫(xiě)成這樣:

Vue.component( ’async-webpack-example’, // 這個(gè) `import` 函數(shù)會(huì)返回一個(gè) `Promise` 對(duì)象。 () => import(’./my-async-component’))

當(dāng)使用局部注冊(cè)組件的時(shí)候,你也可以直接提供一個(gè)返回 Promise 的函數(shù):

new Vue({ // ... components: { ’my-component’: () => import(’./my-async-component’) }})

如果你想實(shí)現(xiàn)異步加載組件的功能,提高首屏顯示速度,那么可以使用上面例子中的定義組件的方法,也就是:箭頭函數(shù)+import語(yǔ)句!

處理加載狀態(tài)

2.3.0+ 新增

異步組件的工廠函數(shù)也可以返回一個(gè)如下格式的對(duì)象,用來(lái)靈活定制異步加載過(guò)程:

const AsyncComponent = () => ({ // 需要加載的組件 (應(yīng)該是一個(gè) `Promise` 對(duì)象) component: import(’./MyComponent.vue’), // 異步組件加載時(shí)使用的組件 loading: LoadingComponent, // 加載失敗時(shí)使用的組件 error: ErrorComponent, // 展示加載時(shí)組件的延時(shí)時(shí)間。默認(rèn)值是 200 (毫秒) delay: 200, // 如果提供了超時(shí)時(shí)間且組件加載也超時(shí)了, // 則使用加載失敗時(shí)使用的組件。默認(rèn)值是:`Infinity` timeout: 3000})

注意如果你希望在 Vue Router 的路由組件中使用上述語(yǔ)法的話,必須使用 Vue Router 2.4.0+ 版本。

九、批量導(dǎo)入組件

很多時(shí)候我們會(huì)編寫(xiě)一些類似輸入框或按鈕之類的基礎(chǔ)組件,它們是相對(duì)通用的組件,稱為基礎(chǔ)組件,它們會(huì)在更大一些的組件中被頻繁的用到。

這很容易導(dǎo)致大的組件里有一個(gè)很長(zhǎng)的導(dǎo)入基礎(chǔ)組件的語(yǔ)句列表,例如:

import BaseButton from ’./BaseButton.vue’import BaseIcon from ’./BaseIcon.vue’import BaseInput from ’./BaseInput.vue’//更多導(dǎo)入export default { components: { BaseButton, BaseIcon, BaseInput }}

當(dāng)你的基礎(chǔ)組件很多的時(shí)候,這個(gè)過(guò)程將非常重復(fù)、麻煩和無(wú)聊。

require.context()

如果你恰好使用了 webpack (或在內(nèi)部使用了 webpack 的 Vue CLI 3+),那么就可以使用 require.context 方法批量導(dǎo)入這些組件,然后將它們注冊(cè)為全局組件,這樣就可以在任何地方直接使用它們了,再也不用為導(dǎo)入的事情煩惱了!

下面是一個(gè)示例代碼:

import Vue from ’vue’import upperFirst from ’lodash/upperFirst’import camelCase from ’lodash/camelCase’const requireComponent = require.context( // 其組件目錄的相對(duì)路徑 ’./components’, // 是否查詢其子目錄 false, // 匹配基礎(chǔ)組件文件名的正則表達(dá)式 /Base[A-Z]w+.(vue|js)$/)requireComponent.keys().forEach(fileName => { // 獲取組件的配置,也就是具體內(nèi)容,具體定義,組件的本身代碼 const componentConfig = requireComponent(fileName) // 獲取組件的 PascalCase 命名,用來(lái)規(guī)范化組件名 const componentName = upperFirst( camelCase( // 獲取和目錄深度無(wú)關(guān)的文件名 fileName .split(’/’) .pop() .replace(/.w+$/, ’’) ) ) // 全局注冊(cè)組件 Vue.component( componentName, // 如果這個(gè)組件選項(xiàng)是通過(guò) `export default` 導(dǎo)出的, // 那么就會(huì)優(yōu)先使用 `.default`, // 否則回退到使用模塊的根。 componentConfig.default || componentConfig )})

以上就是詳解vue高級(jí)特性的詳細(xì)內(nèi)容,更多關(guān)于vue高級(jí)特性的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 日本高清一本二本三本如色坊 | 国产亚洲精品国产 | 欧美性videofree精品 | 国外精品视频在线观看免费 | 成人a在线 | 美女全黄视频 | 亚洲欧美不卡中文字幕 | 成人在线午夜 | 91香焦国产线观看看免费 | 国产精品免费_区二区三区观看 | 日韩欧美综合在线二区三区 | 欧美亚洲国产成人高清在线 | 欧美一级永久免费毛片在线 | 国产丝袜美女一区二区三区 | 亚洲第一欧美 | 亚洲精品一区二区手机在线 | 91大神在线精品视频一区 | 久久最新 | 男人的天堂2018 | 国产精品福利午夜h视频 | 欧美毛片大全 | 综合 91在线精品 | 美女很黄很黄免费 | 精品一区二区三区的国产在线观看 | 国产高清精品自在久久 | 久久国产精品视频一区 | 131美女爱做免费毛片 | 日韩精品午夜视频一区二区三区 | 午夜国产精品不卡在线观看 | 亚洲性在线 | 国产成人综合95精品视频免费 | 在线视频日本 | 国产不卡在线视频 | 精品国产_亚洲人成在线高清 | 国产亚洲欧美另类久久久 | 91久久精品青青草原伊人 | 欧美性视频一区二区三区 | 亚洲日本va午夜中文字幕一区 | 国产精品久久久久网站 | 日韩欧美亚洲综合久久99e | 成人怡红院视频在线观看 |