學會這些Vue小技巧,能夠早點下班和女神約會了!

夏眠不覺曉,到處蚊子咬,夜來鍵盤聲,發落知多少?javascript

天天都在寫代碼,雖然手底下快馬加鞭的敲,可是該來的加班仍是會來的,如何能更快的完成手頭的工做,提升本身的開發效率,今天小編給你們帶來了這幾個Vue小技巧,終於能夠在六點像小鹿同樣奔跑着下班了。 先贊後看,豔遇不斷,哈哈哈哈html

學會使用$attrs 與 $listeners,二次包裝組件就靠它了

前幾天產品經理給我甩過來一份管理系統的設計原型,我打開看了看,雖然心裏是拒絕的,可是爲了活着,仍是要作的。小編看了看原型,發現系統中的大部分彈框右下角都是肯定和取消兩個按鈕。若是使用element-ui提供的Dialog,那麼每個彈框都要手動加按鈕,不但代碼量增多,並且後面若是按鈕UI,需求發生變化,改動量也比較大。前端

 

 

若是能夠將Dialog進行二次封裝,將按鈕封裝到組件內部,就能夠不用重複去寫了。說幹就幹。java

定義基本彈框代碼

<template> <el-dialog :visible.sync="visibleDialog"> <!--內容區域的默認插槽--> <slot></slot> <!--使用彈框的footer插槽添加按鈕--> <template #footer> <!--對外繼續暴露footer插槽,有個別彈框按鈕須要自定義--> <slot name="footer"> <!--將取消與肯定按鈕集成到內部--> <span> <el-button @click="$_handleCancel">取 消</el-button> <el-button type="primary" @click="$_handleConfirm"> 確 定 </el-button> </span> </slot> </template> </el-dialog> </template> <script> export default { props: { // 對外暴露visible屬性,用於顯示隱藏彈框 visible: { type: Boolean, default: false } }, computed: { // 經過計算屬性,對.sync進行轉換,外部也能夠直接使用visible.sync visibleDialog: { get() { return this.visible; }, set() { this.$emit("update:visible"); } } }, methods: { // 對外拋出cancel事件 $_handleCancel() { this.$emit("cancel"); }, // 對外拋出 confirm事件 $_handleConfirm() { this.$emit("confirm"); } } }; </script>真正想成爲一名前端架構師,要跟一羣架構師交流才能高效的成長,
個人架構師扣扣裙 519293536 一塊兒討論交流技術進步吧!

經過上面的代碼,咱們已經將按鈕封裝到組件內部了,效果以下圖所示:webpack

<!--外部使用方式 confirm cancel 是自定義的事件 opened是包裝el-dialog的事件,經過$listeners傳入到el-dialog裏面--> <custom-dialog :visible.sync="visibleDialog" @opened="$_handleOpened" @confirm="$_handleConfirm" @cancel="$_handleCancel">這是一段內容</custom-dialog> 複製代碼

效果圖web

 

但上面的代碼存在一個問題,沒法將Dialog自身的屬性和事件暴露到外部(雖然能夠經過props$emit一個一個添加,可是很麻煩),這時候就可使用$attrs$listenerselement-ui

使用$attrs$listeners

$attrs: 當組件在調用時傳入的屬性沒有在props裏面定義時,傳入的屬性將被綁定到$attrs屬性內(classstyle除外,他們會掛載到組件最外層元素上)。並可經過v-bind="$attrs"傳入到內部組件中數組

$listeners: 當組件被調用時,外部監聽的這個組件的全部事件均可以經過$listeners獲取到。並可經過v-on="$listeners"傳入到內部組件中。網絡

修改彈框代碼架構

<!---使用了v-bind與v-on監聽屬性與事件--> <template> <el-dialog :visible.sync="visibleDialog" v-bind="$attrs" v-on="$listeners"> <!--其餘代碼不變--> </el-dialog> </template> <script> export default { //默認狀況下父做用域的不被認做 props 的 attribute 綁定 (attribute bindings) //將會「回退」且做爲普通的 HTML attribute 應用在子組件的根元素上。 //經過設置 inheritAttrs 到 false,這些默認行爲將會被去掉 inheritAttrs: false } </script> <!---外部使用方式--> <custom-dialog :visible.sync="visibleDialog" title="測試彈框" @opened="$_handleOpened" > 這是一段內容 </custom-dialog> 複製代碼

對於$attrs,咱們也可使用$props來代替,實現代碼以下

<template> <el-dialog :visible.sync="visibleDialog" v-bind="$props" v-on="$listeners"> <!--其餘代碼不變--> </el-dialog> </template> <script> import { Dialog } from 'element-ui' export default { props: { // 將Dialog的props經過擴展運算符展開到props屬性裏面 ...Dialog.props } } </script> 複製代碼

但上面的代碼存在必定的缺陷,有些組件存在非props的屬性,好比對於一些封裝的表單組件,咱們可能須要給組件傳入原生屬性,但實際原生屬性並無在組件的props上面定義,這時候,若是經過上面的方式去包裝組件,那麼這些原生組件將沒法傳遞到內部組件裏面。

感謝@陌上兮月的提醒

使用require.context實現前端工程自動化

require.context是一個webpack提供的Api,經過執行require.context函數獲取一個特定的上下文,主要是用於實現自動化導入模塊。

何時用? 當一個js裏面須要手動引入過多的其餘文件夾裏面的文件時,就可使用。

在Vue項目開發過程當中,咱們可能會遇到這些可能會用到require.context的場景

  1. 當咱們路由頁面比較多的時候,可能會將路由文件拆分紅多個,而後再經過import引入到index.js路由主入口文件中
  2. 當使用svg symbol時候,須要將全部的svg圖片導入到系統中(建議使用svg-sprite-loader)
  3. 開發了一系列基礎組件,而後把全部組件都導入到index.js中,而後再放入一個數組中,經過遍歷數組將全部組件進行安裝。

對於上述的幾個場景,若是咱們須要導入的文件比較少的狀況下,經過import一個一個去導入還能夠接受,但對於量比較大的狀況,就變成了純體力活,並且每次修改增長都須要在主入口文件內進行調整。這時候咱們就能夠經過require.context去簡化這個過程。

如今以上述第三條爲例,來講明require.context的用法

常規用法

 

組件經過常規方式安裝

 

 

組件經過常規方式安裝

 

require.context基本語法

 

 

經過require.context安裝Vue組件

 

 

自定義v-model,原來這麼簡單

在用Vue開發前端時,不論使用原生仍是封裝好的UI庫,對於表單組件,通常都會使用到v-model。雖然v-model是一個語法糖,可是吃到嘴裏挺甜的啊。學會自定義v-model,仍是頗有必要的。

基本用法

一個組件上的v-model默認是經過在組件上面定義一個名爲value的props,同時對外暴露一個名爲input的事件。

源碼:

使用方式:

 

 

 

自定義屬性與事件

一般狀況下,使用value屬性與input事件沒有問題,可是有時候有些組件會將value屬性或input事件用於不一樣的目的,好比對於單選框、複選框等類型的表單組件的value屬性就有其餘用處,參考(developer.mozilla.org/en-US/docs/…)。或者但願屬性名稱或事件名稱與實際行爲更貼切,好比active,checked等屬性名。

 

 

使用.sync,更優雅的實現數據雙向綁定

Vue中,props屬性是單向數據傳輸的,父級的prop的更新會向下流動到子組件中,可是反過來不行。但是有些狀況,咱們須要對prop進行「雙向綁定」。上文中,咱們提到了使用v-model實現雙向綁定。但有時候咱們但願一個組件能夠實現多個數據的「雙向綁定」,而v-model一個組件只能有一個(Vue3.0能夠有多個),這時候就須要使用到.sync

.syncv-model的異同

相同點:

  • 二者的本質都是語法糖,目的都是實現組件與外部數據的雙向綁定
  • 兩個都是經過屬性+事件來實現的

不一樣點(我的觀點,若有不對,麻煩下方評論指出,謝謝):

  • 一個組件只能定義一個v-model,但能夠定義多個.sync
  • v-model.sync對於的事件名稱不一樣,v-model默認事件爲input,能夠經過配置model來修改,.sync事件名稱固定爲update:屬性名

自定義.sync

在開發業務時,有時候須要使用一個遮罩層來阻止用戶的行爲(更多會使用遮罩層+loading動畫),下面經過自定義.sync來實現一個遮罩層

 

 

<!--調用方式--> <template> <custom-overlay :visible.sync="visible" /> </template> <script> export default { data() { return { visible: false } } } </script> 複製代碼

動態組件,讓頁面渲染更靈活

前兩天產品經理來了新的需求了,告訴我,須要根據用戶的權限不一樣,頁面上要顯示不一樣的內容,而後我就哼哧哼哧的將不一樣權限對應的組件寫了出來,而後再經過v-if來判斷要顯示哪一個組件,就有了下面的代碼

 

 

可是看到上面代碼的那一長串v-if,v-else-if,我感受個人代碼潔癖症要犯了,不行,這樣code review過不了關,我連本身這一關都過不了,這時候就改動態組件發揮做用了。

<template> <div class="info"> <component :is="roleComponent" v-if="roleComponent" /> </div> </template> <script> import AdminInfo from './admin-info' import BookkeeperInfo from './bookkeeper-info' import HrInfo from './hr-info' import UserInfo from './user-info' export default { components: { AdminInfo, BookkeeperInfo, HrInfo, UserInfo }, data() { return { roleComponents: { admin: AdminInfo, bookkeeper: BookkeeperInfo, hr: HrInfo, user: UserInfo }, role: 'user', roleComponent: undefined } }, created() { const { role, roleComponents } = this this.roleComponent = roleComponents[role] } } </script> 複製代碼

mixins,更高效的實現組件內容的複用

mixinsVue提供的一種混合機制,用來更高效的實現組件內容的複用。怎麼去理解混入呢,我以爲和Object.assign,但實際與Object.assign又有所不一樣。

基本示例

在開發echarts圖表組件時,須要在窗口尺寸發生變化時,重置圖表的大小,此時若是在每一個組件裏面都去實現一段監聽代碼,代碼重複太多了,此時就可使用混入來解決這個問題

// 混入代碼 resize-mixins.js import { debounce } from 'lodash' const resizeChartMethod = '$__resizeChartMethod' export default { data() { // 在組件內部將圖表init的引用映射到chart屬性上 return { chart: null } }, created() { window.addEventListener('resize', this[resizeChartMethod]) }, beforeDestroy() { window.removeEventListener('reisze', this[resizeChartMethod]) }, methods: { // 經過lodash的防抖函數來控制resize的頻率 [resizeChartMethod]: debounce(function() { if (this.chart) { this.chart.resize() } }, 100) } } 複製代碼
<!--圖表組件代碼--> <template> <div class="chart"></div> </template> <script> import echartMixins from './echarts-mixins' export default { // mixins屬性用於導入混入,是一個數組,數組能夠傳入多個混入對象 mixins: [echartMixins], data() { return { chart: null } }, created() { this.chart = echarts.init(this.$el) } } </script> 複製代碼

不一樣位置的混入規則

Vue中,一個混入對象能夠包含任意組件選項,可是對於不一樣的組件選項,會有不一樣的合併策略。

  1. data 對於data,在混入時會進行遞歸合併,若是兩個屬性發生衝突,則以組件自身爲主,如上例中的chart屬性

  2. 生命週期鉤子函數

對於生命週期鉤子函數,混入時會將同名鉤子函數加入到一個數組中,而後在調用時依次執行。混入對象裏面的鉤子函數會優先於組件的鉤子函數執行。若是一個組件混入了多個對象,對於混入對象裏面的同名鉤子函數,將按照數組順序依次執行,以下代碼:

const mixin1 = { created() { console.log('我是第一個輸出的') } } const mixin2 = { created() { console.log('我是第二個輸出的') } } export default { mixins: [mixin1, mixin2], created() { console.log('我是第三個輸出的') } } 複製代碼
  1. 其餘選項 對於值爲對象的選項,如methods,components,filter,directives,props等等,將被合併爲同一個對象。兩個對象鍵名衝突時,取組件對象的鍵值對。

全局混入

混入也能夠進行全局註冊。一旦使用全局混入,那麼混入的選項將在全部的組件內生效,以下代碼所示:

Vue.mixin({
  methods: { /** * 將埋點方法經過全局混入添加到每一個組件內部 * * 建議將埋點方法綁定到Vue的原型鏈上面,如: Vue.prototype.$track = () => {} * */ track(message) { console.log(message) } } }) 複製代碼

請謹慎使用全局混入,由於它會影響每一個單首創建的 Vue 實例 (包括第三方組件)。大多數狀況下,只應當應用於自定義選項,

最後我想說:真正想成爲一名前端架構師,要跟一羣架構師交流才能高效的成長,個人架構師扣扣裙 519293536 一塊兒討論交流技術進步吧!

本文的文字及圖片來源於網絡加上本身的想法,僅供學習、交流使用,不具備任何商業用途,版權歸原做者全部,若有問題請及時聯繫咱們以做處理

相關文章
相關標籤/搜索