夏眠不覺曉,處處蚊子咬,夜來鍵盤聲,發落知多少? 每天都在寫代碼,雖然手底下馬不停蹄的敲,但是該來的加班還是會來的,如何能更快的完成手頭的工作,提高自己的開發效率,今天小編給大家帶來了這幾個Vue小技巧,終於可以在六點像小鹿一樣奔跑著下班了。 先贊後看,艷遇不斷,哈哈哈哈 學會使用$attrs 與 ...
夏眠不覺曉,處處蚊子咬,夜來鍵盤聲,發落知多少?
每天都在寫代碼,雖然手底下馬不停蹄的敲,但是該來的加班還是會來的,如何能更快的完成手頭的工作,提高自己的開發效率,今天小編給大家帶來了這幾個Vue小技巧,終於可以在六點像小鹿一樣奔跑著下班了。 先贊後看,艷遇不斷,哈哈哈哈
學會使用
$attrs
與$listeners
,二次包裝組件就靠它了
前幾天產品經理給我甩過來一份管理系統的設計原型,我打開看了看,雖然內心是拒絕的,但是為了活著,還是要做的。小編看了看原型,發現系統中的大部分彈框右下角都是確定和取消兩個按鈕。如果使用element-ui提供的Dialog
,那麼每一個彈框都要手動加按鈕,不但代碼量增多,而且後面如果按鈕UI,需求發生變化,改動量也比較大。
如果可以將Dialog
進行二次封裝,將按鈕封裝到組件內部,就可以不用重覆去寫了。說乾就乾。
定義基本彈框代碼
<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 一起討論交流技術進步吧!
通過上面的代碼,我們已經將按鈕封裝到組件內部了,效果如下圖所示:
<!--外部使用方式 confirm cancel 是自定義的事件 opened是包裝el-dialog的事件,通過$listeners傳入到el-dialog裡面-->
<custom-dialog :visible.sync="visibleDialog" @opened="$_handleOpened" @confirm="$_handleConfirm" @cancel="$_handleCancel">這是一段內容</custom-dialog>
複製代碼
效果圖
但上面的代碼存在一個問題,無法將Dialog
自身的屬性和事件暴露到外部(雖然可以通過props
及$emit
一個一個添加,但是很麻煩),這時候就可以使用$attrs
與$listeners
使用$attrs
與$listeners
$attrs
: 當組件在調用時傳入的屬性沒有在props
裡面定義時,傳入的屬性將被綁定到$attrs
屬性內(class
與style
除外,他們會掛載到組件最外層元素上)。並可通過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
的場景
- 當我們路由頁面比較多的時候,可能會將路由文件拆分成多個,然後再通過
import
引入到index.js
路由主入口文件中 - 當使用svg symbol時候,需要將所有的svg圖片導入到系統中(建議使用svg-sprite-loader)
- 開發了一系列基礎組件,然後把所有組件都導入到
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
。
.sync
與v-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
,更高效的實現組件內容的復用
mixins
是Vue
提供的一種混合機制,用來更高效的實現組件內容的復用。怎麼去理解混入呢,我覺得和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
中,一個混入對象可以包含任意組件選項,但是對於不同的組件選項,會有不同的合併策略。
-
data
對於data
,在混入時會進行遞歸合併,如果兩個屬性發生衝突,則以組件自身為主,如上例中的chart
屬性 -
生命周期鉤子函數
對於生命周期鉤子函數,混入時會將同名鉤子函數加入到一個數組中,然後在調用時依次執行。混入對象裡面的鉤子函數會優先於組件的鉤子函數執行。如果一個組件混入了多個對象,對於混入對象裡面的同名鉤子函數,將按照數組順序依次執行,如下代碼:
const mixin1 = {
created() {
console.log('我是第一個輸出的')
}
}
const mixin2 = {
created() {
console.log('我是第二個輸出的')
}
}
export default {
mixins: [mixin1, mixin2],
created() {
console.log('我是第三個輸出的')
}
}
複製代碼
- 其他選項 對於值為對象的選項,如
methods
,components
,filter
,directives
,props
等等,將被合併為同一個對象。兩個對象鍵名衝突時,取組件對象的鍵值對。
全局混入
混入也可以進行全局註冊。一旦使用全局混入,那麼混入的選項將在所有的組件內生效,如下代碼所示:
Vue.mixin({
methods: {
/**
* 將埋點方法通過全局混入添加到每個組件內部
*
* 建議將埋點方法綁定到Vue的原型鏈上面,如: Vue.prototype.$track = () => {}
* */
track(message) {
console.log(message)
}
}
})
複製代碼
請謹慎使用全局混入,因為它會影響每個單獨創建的 Vue 實例 (包括第三方組件)。大多數情況下,只應當應用於自定義選項,
最後我想說:真正想成為一名前端架構師,要跟一群架構師交流才能高效的成長,我的架構師扣扣裙 519293536 一起討論交流技術進步吧!
本文的文字及圖片來源於網路加上自己的想法,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理