詳解Vue文檔中幾個(gè)易忽視部分的剖析
針對(duì)Vue文檔中部分大家可能不會(huì)去研讀的內(nèi)容,我做了個(gè)小總結(jié),作為有經(jīng)驗(yàn)者的快餐,不是特別適合初學(xué)者,可能有不妥之處,希望大家多提建議。
節(jié)省代碼量的mixin
mixin概念:組件級(jí)可復(fù)用邏輯,包括數(shù)據(jù)變量/生命周期鉤子/公共方法,從而在混入的組件中可以直接使用,不用重復(fù)寫冗余邏輯(類似繼承)
使用方法:
在某一公共文件夾pub下創(chuàng)建mixin文件夾,其下創(chuàng)建mixinTest.js
const mixinTest = { created() { console.log(`components ${this.name} created`) }, methods: { hello() { console.log('mixin method hello') } } } export default mixinTest
在組件中引用剛才的公共混入文件并使用
import mixinTest from '../pub/mixin/mixinTest.js' export default { data() { return { name: 'hello' } }, mixins: [mixinTest], methods: { useMixin() { this.hello() } } }
ps: 若是使用Vue.mixin()這個(gè)方法,則會(huì)影響之后創(chuàng)建的所有Vue示例,慎用!
注意mixin的幾個(gè)特性:
- 混入的數(shù)據(jù)變量是淺合并,沖突時(shí)以組件內(nèi)的數(shù)據(jù)優(yōu)先(對(duì)象里面的自定義變量)
- 混入的生命周期函數(shù)內(nèi)的邏輯會(huì)與組件內(nèi)定義的生命周期函數(shù)邏輯進(jìn)行合并,并且先執(zhí)行(created/mounted/destroy)
- 混入的值為對(duì)象的選項(xiàng),會(huì)混合成一個(gè)對(duì)象,沖突后也是以組件內(nèi)鍵名優(yōu)先(data/method/components/directives)
slot內(nèi)容分發(fā)
slot概念引入:Vue跟React在寫法上的不同就在于組件與子組件內(nèi)部元素的組織上,在組件里面沒有children元素供我們?cè)L問和展現(xiàn)(暫不考慮render函數(shù)),取而代之的API是slot
使用場(chǎng)景定義:
- 自定義的子組件里面有嵌套的HTML或者其他自定義的標(biāo)簽組件
- 這個(gè)自定義的子組件是寫在父組件里面,嵌套的東西也放在父組件里面
- 通過在子組件的模板里面使用<slot></slot>標(biāo)簽,從而達(dá)到渲染寫在父組件里的嵌套標(biāo)簽的效果
- 本質(zhì)是把父組件放在子組件里的內(nèi)容,插到了子組件的位置,多個(gè)標(biāo)簽也會(huì)一起被插入
<template> <div id="app"> <self-component> <!--self-component表示自定義的組件--> <span>12345</span> <!--父組件里的嵌套標(biāo)簽--> </self-component> </div> </template> <script> export default { components: [selfComponent] } </script> <!--self-component的組件模板--> <template> <div> <button><slot></slot></button> </div> </template> <script> export default { // 只有子組件的模板里面有slot標(biāo)簽,才能取到寫在自定義組件里面的標(biāo)簽的渲染引用 } </script>
slot特性的進(jìn)階兩點(diǎn):
slot插入內(nèi)容的編譯作用域:被分發(fā)的內(nèi)容的作用域,根據(jù)其所在模板決定
- 具體內(nèi)容寫的位置,決定了編譯的作用域(大部分情況都是在父組件作用域下)
- 2.1.0+新增作用域插槽,從而可以把子組件的屬性暴露給父組件中寫在子組件內(nèi)的內(nèi)容使用
- 子組件中的slot標(biāo)簽可以直接寫自定義屬性,然后父組件寫在slot中的標(biāo)簽加上slot-scope屬性
<!-- 父組件模板 --> <child :items="items"> <!-- 作用域插槽也可以是具名的 --> <li slot="item" slot-scope="props" class="my-fancy-item">{{ props.text }}</li> </child> <!-- 子組件模板 --> <ul> <slot name="item" v-for="item in items" :text="item.text"> <!-- 這里寫當(dāng)父組件引用子組件但沒寫內(nèi)部?jī)?nèi)容時(shí)展示的東東 --> </slot> </ul>
slot的name屬性來指定標(biāo)簽插入的位置,也就是文檔里面的具名插槽(這個(gè)官方文檔說的明白)
- 在子組件的模板里面寫的slot有個(gè)name屬性(<slot name="foo"></slot>)
- 在父組件中寫子組件里面的插槽內(nèi)容,指明slot屬性(<p slot="foo">123</p>)
- 父組件的內(nèi)容就會(huì)對(duì)應(yīng)slot==name放到正確的位置
- 沒有指明slot屬性的就會(huì)默認(rèn)放到匿名插槽的位置上
動(dòng)態(tài)組件
動(dòng)態(tài)組件這個(gè)特性,很多人寫的Vue項(xiàng)目也不少,但也沒用到過這個(gè),有必要多說幾句
動(dòng)態(tài)組件適用情況:
- 單頁應(yīng)用,部分組件的切換不涉及路由,只是頁面有一塊區(qū)域的組件要變更
- 變更的組件參數(shù)定義上是一致的,比如都是對(duì)話框,要傳一個(gè)對(duì)象進(jìn)去,但對(duì)象里面的數(shù)據(jù)結(jié)構(gòu)不同
- 通過使用component的is屬性,避免在template中的冗余組件代碼,避免多個(gè)v-if模板代碼更加整潔
使用的方法(借鑒文檔):
<keep-alive> <component v-bind:is="currentView"> <!-- 組件在 vm.currentview (對(duì)應(yīng)組件名稱)變化時(shí)改變! --> <!-- 非活動(dòng)組件將被緩存!可以保留它的狀態(tài)或避免重新渲染 --> </component> </keep-alive>
注意點(diǎn):
- 動(dòng)態(tài)切換的組件都要引入到父組件中,渲染是動(dòng)態(tài)的,但引入不是。
- <keep-alive>包裹動(dòng)態(tài)組件時(shí),會(huì)緩存不活動(dòng)的組件實(shí)例,提高性能,避免重復(fù)渲染(keep-alive不會(huì)渲染額外DOM結(jié)構(gòu))
- <keep-alive>有include和exclude這兩個(gè)屬性,用于指定緩存和不緩存的組件(傳入字符串/數(shù)組/正則)
- 另一種避免重新渲染的方法是為標(biāo)簽增加屬性v-once,用于緩存大量的靜態(tài)內(nèi)容,避免重復(fù)渲染。
ps:<keep-alive>不會(huì)在函數(shù)式組件中正常工作,因?yàn)樗鼈儧]有緩存實(shí)例。
動(dòng)畫與過渡
其實(shí)很多前端工程師第一次用Vue的動(dòng)畫和過渡都是通過庫組件來做到的,所以對(duì)這塊沒怎么深挖,各種過渡特效和按鈕動(dòng)畫就跑起來了,現(xiàn)在就看下文檔,補(bǔ)補(bǔ)課
前端實(shí)現(xiàn)動(dòng)畫的基本方法分為三種種:css3的過渡和keyframe/javascript操縱dom/使用webgl或者canvas來獨(dú)立實(shí)現(xiàn),其中第三種是作為展示動(dòng)畫,與交互結(jié)合較少,而Vue作為一個(gè)框架,其支持動(dòng)畫基是從前兩種入手的,從官方文檔提到的四種支持就可以看出這一點(diǎn)。不過官方文檔是從DOM過渡和狀態(tài)過渡兩個(gè)方面來講解,前者是DOM的消失和出現(xiàn)的動(dòng)畫等屬性的變化,后者是頁面上某些值的變化。
DOM屬性的改變
若是單個(gè)元素/組件的顯隱,在組件外面包裹一層<transition></transition>,而后選擇是css過渡還是javascript過渡
CSS過渡:
- vue提供了六個(gè)樣式后綴,本質(zhì)是在dom過渡的過程中動(dòng)態(tài)地添加和刪除對(duì)應(yīng)的className。(-[enter|leave]-?[active|to]?)
- 如果用css庫來輔助開發(fā),可以在transiton這個(gè)標(biāo)簽上定義自定義過渡類名,也是六個(gè)屬性。([enter|leave]-?[active|to]?-class)
- 常見的一種效果是元素首次渲染的動(dòng)畫,如懶加載圖片飛入,這個(gè)時(shí)候要在transiton標(biāo)簽上加上appear,另有三個(gè)屬性可指定(appear-?[to|active]?-class)
<!-- 每種CSS動(dòng)畫庫對(duì)應(yīng)的class命名規(guī)則可能不同,所以根據(jù)不同庫要自己寫,以animate.css為例 --> <transition name="custom-classes-transition" enter-active-class="animated tada" leave-active-class="animated bounceOutRight" :duration="{ enter: 500, leave: 800 }" >...</transition> <!-- duration屬性可以傳一個(gè)對(duì)象,定制進(jìn)入和移出的持續(xù)時(shí)間-->
JS過渡:
- 因?yàn)楝F(xiàn)在很多動(dòng)畫庫需要工程師調(diào)用庫提供的函數(shù),把dom元素傳入進(jìn)行處理,這個(gè)時(shí)候需要這種方式
- 通過在transiton這個(gè)標(biāo)簽上添加監(jiān)聽事件,共8個(gè)([before|after]?-?[enter|leave]-?[cancelled]?)
- 監(jiān)聽事件的回調(diào)函數(shù)的第一個(gè)參數(shù)都是el,為過渡的dom元素,在enter和leave這兩個(gè)還會(huì)傳入done作為第二個(gè)參數(shù)
- 元素首次渲染的動(dòng)畫,可以指定的監(jiān)聽事件有4個(gè)([before|after]?-?appear和appear-cancelled)
<template> <transition v-bind:css="false" v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:leave="leave" v-on:leave-cancelled="leaveCancelled"> <!-- 對(duì)于僅使用 JavaScript 過渡的元素添加 v-bind:css="false",Vue 會(huì)跳過 CSS 的檢測(cè) --> </transition> </template> <script> methods: { // 以Velocity庫為例 beforeEnter: function (el) {/*...*/}, // 此回調(diào)函數(shù)是可選項(xiàng)的設(shè)置 enter: function (el, done) { // Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 }) done() //回調(diào)函數(shù) done 是必須的。否則,它們會(huì)被同步調(diào)用。 }, leave: function (el, done) { // Velocity(el, { translateX: '15px', rotateZ: '50deg' }, { duration: 600 }) done() }, leaveCancelled: function (el) {/*...*/} } </script>
多元素過渡其實(shí)就是一句話:照常使用v-if/v-else的同時(shí)對(duì)同一種標(biāo)簽加上key來標(biāo)識(shí)
Vue對(duì)于這種多元素動(dòng)畫有隊(duì)列上的處理,這就是transiton這個(gè)標(biāo)簽上的mode屬性,通過指定(in-out|out-in)模式,實(shí)現(xiàn)消失和出現(xiàn)動(dòng)畫的隊(duì)列效果,讓動(dòng)畫更加自然。
<transition name="fade" mode="out-in"> <!-- ... the buttons ... --> </transition>
多組件過渡也是一句話:用上一節(jié)提到的動(dòng)態(tài)組件,即可完成。
針對(duì)列表過渡,其本質(zhì)仍是多個(gè)元素的同時(shí)過渡,不過列表大部分是通過數(shù)組動(dòng)態(tài)渲染的,因此有獨(dú)特的地方,不過整體的動(dòng)畫思路不變。具體有以下幾點(diǎn)
- 使用transitoin-group這個(gè)組件,其需要渲染為一個(gè)真實(shí)元素,可以通過tag這個(gè)屬性來指定。
- 列表的每個(gè)元素需要提供key屬性
- 使用CSS過渡的話,要考慮到列表內(nèi)容變化過程中,存在相關(guān)元素的定位改變,如果要讓定位是平滑過渡的動(dòng)畫,要另外一個(gè)v-move屬性。 這個(gè)屬性是通過設(shè)置一個(gè)css類的樣式,來將創(chuàng)建元素在定位變化時(shí)的過渡,Vue內(nèi)部是通過FLIP實(shí)現(xiàn)了一個(gè)動(dòng)畫隊(duì)列,只要注意一點(diǎn)就是過渡元素不能設(shè)置為display:inline,這里需要文檔上的代碼做一個(gè)簡(jiǎn)短的demo:(其實(shí)通過在li上設(shè)置過渡transition屬性也可以實(shí)現(xiàn)v-move的效果)
<template> <button v-on:click="shuffle">Shuffle</button> <transition-group name="flip-list" tag="ul"> <li v-for="item in items" v-bind:key="item">{{ item }}</li> </transition-group> </template> <script> import _ from 'lodash'; export default { data() { return { items: [1,2,3,4,5,6,7,8,9] } }, methods: { shuffle: function () { this.items = _.shuffle(this.items) } } } </script> <style lang="css"> .flip-list-move { transition: transform 1s; } </style>
數(shù)值和屬性動(dòng)態(tài)變化
這一部分的動(dòng)畫主要是針對(duì)數(shù)據(jù)元素本身的特效,比如數(shù)字的增減,顏色的過渡過程控制,svg動(dòng)畫的實(shí)現(xiàn)等,其本質(zhì)都是數(shù)字/文本的變化。 我自己總結(jié)就是:通過利用Vue的響應(yīng)式系統(tǒng),把數(shù)字的變化通過外部庫把DOM上對(duì)應(yīng)數(shù)值的變化做出連續(xù)的效果,如1->100是個(gè)數(shù)字遞增的連續(xù)過程,黑色->紅色的過程。官方文檔主要是用幾個(gè)示例代碼來說明,其本質(zhì)步驟如下:
- 在頁面上通過input的雙向綁定修改某一變量a,還有一個(gè)處理dom上的過渡效果的變量b
- 這個(gè)數(shù)據(jù)被watcher綁定(watch對(duì)象中某個(gè)屬性是這個(gè)變量a),觸發(fā)邏輯
- 在watcher里面的邏輯就是通過外部過渡庫,指定初始值b和最終值a,是把b的值最后改為a
- DOM上綁定的變量就是b,如果某些復(fù)雜情況可能是基于b的計(jì)算屬性,從而把b的變化過程展現(xiàn)出來
上面這個(gè)思路走一遍下來就完成了一個(gè)單元級(jí)別的動(dòng)畫效果,這種類似的流程其實(shí)是很常見的需求,所以有必要把這個(gè)過程封裝成一個(gè)組件,只暴露要過渡的值作為入口,每次改變這個(gè)值都是一個(gè)動(dòng)畫過渡效果。組件封裝需要在上面四個(gè)步驟的基礎(chǔ)上添加mounted生命周期規(guī)定初始值即可,同時(shí)原來的兩個(gè)值a/b在組件里面作為一個(gè)值,可以用watch對(duì)象中的newValue和oldValue作為區(qū)分。 至于最后的SVG,其本質(zhì)也是數(shù)字的過渡,只不過里面涉及的狀態(tài)變量更多,代碼更長(zhǎng)而已,不過純前端頁面這種需求倒還是不多的,不過作為愛好倒可以鼓搗一些好玩的小demo,不過肯定需要設(shè)計(jì)師的參與,要不那些參數(shù)可不好調(diào)出來吶。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue項(xiàng)目接入高德地圖點(diǎn)擊地圖獲取經(jīng)緯度以及省市區(qū)功能
這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目接入高德地圖點(diǎn)擊地圖獲取經(jīng)緯度以及省市區(qū)功能的相關(guān)資料,開發(fā)中我們需要地圖定位,就是用戶輸入位置,自動(dòng)定位獲取經(jīng)緯度,需要的朋友可以參考下2023-08-08element日期組件實(shí)現(xiàn)只能選擇小時(shí)或分鐘
本文主要介紹了element日期組件實(shí)現(xiàn)只能選擇小時(shí)或分鐘,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01el-form組件使用resetFields重置失效的問題解決
用el-form寫了包含三個(gè)字段的表單,使用resetFields方法進(jìn)行重置,發(fā)現(xiàn)點(diǎn)擊重置或要清空校驗(yàn)時(shí)是失效的,所以本文給大家介紹了el-form組件使用resetFields重置失效的問題解決,需要的朋友可以參考下2023-12-12vue中使用 pako.js 解密 gzip加密字符串的方法
這篇文章主要介紹了vue項(xiàng)目中 使用 pako.js 解密 gzip加密字符串 的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-06-06Electron實(shí)現(xiàn)靜默打印小票的流程詳解
很多情況下程序中使用的打印都是用戶無感知的,并且想要靈活的控制打印內(nèi)容,往往需要借助打印機(jī)給我們提供的api再進(jìn)行開發(fā),這種開發(fā)方式非常繁瑣,并且開發(fā)難度較大,本文給大家介紹了Electron實(shí)現(xiàn)靜默打印小票的流程,感興趣的朋友可以參考下2024-06-06UniApp中實(shí)現(xiàn)類似錨點(diǎn)定位滾動(dòng)效果
一個(gè)uniapp小程序的項(xiàng)目,我們需要實(shí)現(xiàn)一個(gè)非常實(shí)用的功能——類似于錨點(diǎn)定位的交互效果,即在首頁中有多個(gè)tab(分類標(biāo)簽),每個(gè)tab對(duì)應(yīng)著不同的模塊,當(dāng)用戶點(diǎn)擊某個(gè)分類的tab時(shí),需要流暢地滾動(dòng)到對(duì)應(yīng)的內(nèi)容位置,提供更好的用戶體驗(yàn),2023-10-10