一份氧、需求。
最近在開(kāi)發(fā)一個(gè)新系統(tǒng)弯屈,有很多功能以及表單需要處理半火,為了偷懶,想著封裝一個(gè)組件統(tǒng)一處理下相關(guān)邏輯季俩,這樣下來(lái)钮糖,每個(gè)功能只需寫(xiě)一個(gè)列表查詢(xún)的組件和一個(gè)表單組件,省時(shí)省心。
最終效果:
二店归、需要實(shí)現(xiàn)的點(diǎn):
1阎抒、 增加、修改消痛、查看三個(gè)功能都在這里進(jìn)行處理
2且叁、每個(gè)功能只需要寫(xiě)好表單以及對(duì)應(yīng)事件,用該組件統(tǒng)一處理外部樣式以及觸發(fā)子組件中的表單事件(這里的表單作為子組件)
3秩伞、因?yàn)橛凶髠?cè)邊欄的緣故逞带,還需要?jiǎng)討B(tài)調(diào)整寬度
三、具體實(shí)現(xiàn)
<!--基于element封裝的抽屜組件纱新,具體api見(jiàn):https://element.eleme.io/#/zh-CN/component/drawer-->
<template>
<div>
<el-drawer ref="drawer"
append-to-body
:size="drawer.width"
:before-close="beforeClose"
:visible="drawer.show"
:direction="direction"
:destroy-on-close="destroy"
:wrapperClosable="wrapperClosable"
@open="getNewWidth"
@close="closeHander">
<!-- 標(biāo)題部分 -->
<template slot="title">
<p>{{ titleText }}</p>
</template>
<!-- 主要內(nèi)容 -->
<slot name="main"></slot>
<div class="drawer__footer">
<Button size="large"
icon="md-close"
@click="CloseDrawer">{{
showSubmitBtn ? "取消" : "關(guān)閉"
}}</Button>
<Button v-if="showSubmitBtn"
size="large"
type="primary"
@click="submit"
icon="md-checkbox-outline"
:loading="loading">{{ loading ? "提交中 ..." : "確 定" }}</Button>
</div>
</el-drawer>
</div>
</template>
<script>
export default {
name: 'JcDrawer',
props: {
//模式:1新增 2修改 3查看
mode: {
default: 1,
type: Number,
},
//是否顯示
show: {
default: false,
},
//標(biāo)題
title: {
type: String,
},
//打開(kāi)方向
direction: {
default: 'rtl',
type: String,
},
//控制是否在關(guān)閉 Drawer 之后將子元素全部銷(xiāo)毀
destroy: {
default: true,
type: Boolean,
},
//點(diǎn)擊遮罩層是否可以關(guān)閉 Drawer
wrapperClosable: {
default: false,
type: Boolean,
},
//是否顯示提交按鈕(有的界面無(wú)需提交)
showSubmitBtn: {
default: true,
type: Boolean,
},
},
data() {
return {
isAuto: false, // 是否自動(dòng)關(guān)閉
Bus: this.$BusFactory(this),
loading: false,
drawer: {
width: 0,
show: this.show,
mode: this.mode,
},
}
},
mounted() {
//初始化完成時(shí)添加一個(gè)事件用于監(jiān)聽(tīng)屏幕大小變化展氓,自適應(yīng)調(diào)整寬度
window.onresize = () => {
return (() => {
this.getNewWidth()
})()
}
},
watch: {
//監(jiān)聽(tīng)父組件的值控制是否顯示
show: {
immediate: true,
deep: true,
handler(newvalue, oldvalue) {
this.drawer.show = newvalue
},
},
mode: {
immediate: true,
handler(newvalue, oldvalue) {
this.drawer.mode = newvalue
},
},
},
computed: {
/**
* @description 標(biāo)題
*/
titleText() {
if (this.drawer.mode === 1) return `添加${this.title}信息`
if (this.drawer.mode === 2) return `修改${this.title}信息`
if (this.drawer.mode === 3) return `查看${this.title}信息`
},
},
methods: {
/**
* @description 關(guān)閉之后的事件
*/
closeHander() {
//取消自動(dòng)關(guān)閉
this.isAuto = false
},
/**
* @description 關(guān)閉窗口
*/
CloseDrawer() {
if (this.showSubmitBtn) {
this.isAuto = false
} else {
this.isAuto = true
}
this.$refs.drawer.closeDrawer()
},
/**
* @description 關(guān)閉抽屜的事件
* @param {function} done 關(guān)閉的回調(diào)
*/
beforeClose(done) {
if (!this.isAuto && this.showSubmitBtn) {
this.$confirm('確定要關(guān)閉嗎?', '提示', {
confirmButtonText: '確定',
cancelButtonText: '取消',
type: 'warning',
}).then((_) => {
this.$emit('close')
done()
})
} else {
this.$emit('close')
done()
}
},
//提交事件
submit(callback) {
var that = this
that.loading = true
if (this.drawer.mode == 1) {
//使用事件總線(xiàn)的方式觸發(fā)表單組件中的事件
this.Bus.$emit('Add', function (res) {
if (res.success) {
that
.$confirm('添加成功脸爱!', '提示', {
confirmButtonText: '確定',
showCancelButton: false,
type: 'success',
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
})
.then(() => {
//點(diǎn)擊確認(rèn)之后直接退出并銷(xiāo)毀表單
that.isAuto = true
that.$refs.drawer.closeDrawer()
})
}
})
}
if (this.drawer.mode == 2) {
this.Bus.$emit('Edit', function (res) {
if (res.success) {
that
.$confirm('修改成功遇汞!', '提示', {
confirmButtonText: '確定',
showCancelButton: false,
type: 'success',
closeOnClickModal: false,
closeOnPressEscape: false,
showClose: false,
})
.then(() => {
that.isAuto = true
that.$refs.drawer.closeDrawer()
})
}
})
}
if (this.drawer.mode == 3) {
this.Bus.$emit('Detail', function () {
that.isAuto = true
that.$refs.drawer.closeDrawer()
})
that.loading = false
}
},
/**
* @description 設(shè)置主界面的寬度
*/
getNewWidth() {
//組件寬度=當(dāng)前屏幕寬度-側(cè)邊欄寬度
this.drawer.width =
document.body.clientWidth -
(parseInt(document.getElementById('left_nav')?.style?.width) || 0)
},
},
}
</script>
<style scoped>
.drawer__footer {
width: 100%;
border-top: 1px solid #e8eaec;
position: absolute;
bottom: 0;
padding: 10px;
display: flex;
justify-content: center;
background-color: white;
z-index: 99;
}
.drawer__footer button {
margin: 0 10px;
}
</style>
使用(列表查詢(xún)組件):
<!--列表組件-->
<template>
<!--...列表展示內(nèi)容-->
<jc-drawer :show="formShow"
@close="formShow = false"
:title="title"
:mode="mode">
<!-- 使用插槽插入表單 -->
<template slot="main">
<role-form :roleId="roleId"
@getList="getList"
:mode="mode"></role-form>
</template>
</jc-drawer>
</template>
<script>
import jcDrawer from '@/components/jc-cpn/jc-drawer.vue'
import RoleForm from './form'
export default {
components: { jcDrawer, RoleForm },
name: 'role',
data() {
return {
roleId: null,
mode: 1,
title: '角色',
formShow: false,
}
},
methods: {
// 添加角色
roleAdd() {
this.mode = 1
this.formShow = true
},
//編輯角色
roleEdit() {
this.mode = 2
this.roleId = 點(diǎn)擊編輯按鈕時(shí)行的id
this.formShow = true
},
//查看角色
roleDetail() {
this.mode = 3
this.roleId = 點(diǎn)擊查看按鈕時(shí)行的id
this.formShow = true
},
},
}
</script>
表單組件:
<!-- 角色的form表單 -->
<template>
<div>
<!-- 表單元素 -->
</div>
</template>
<script>
export default {
name: 'RoleForm',
props: {
roleId: {
type: Number,
default: null,
},
mode: {
type: Number,
default: 1,
},
},
data() {
return {
// 事件總線(xiàn)實(shí)例。詳情見(jiàn):https://zhuanlan.zhihu.com/p/32029461
Bus: this.$BusFactory(this),
loading: false,
}
},
watch: {
//監(jiān)聽(tīng)父組件的值控制是否顯示
roleId: {
immediate: true,
deep: true,
handler(newvalue, oldvalue) {
if (this.mode == 2) {
//回填數(shù)據(jù)
this.setCurrentData()
}
},
},
},
mounted() {
//采用事件總線(xiàn)的方式綁定drawer組件中定義的方法簿废,采用事件回調(diào)的方式通知drawer此次事件的完成情況空入,在drawer中統(tǒng)一處理
//新增方法
this.Bus.$on('Add', (callback) => {
this.RoleAdd(callback)
})
//新增方法
this.Bus.$on('Edit', (callback) => {
this.RoleEdit(callback)
})
},
methods: {
/**
* @description 角色添加
* @param {function} callback 回調(diào)函數(shù),請(qǐng)求完成后用于通知抽屜組件完成狀態(tài)
*/
RoleAdd(callback) {
callback(...res)
},
/**
* @description 角色修改
* @param {function} callback 回調(diào)函數(shù)族檬,請(qǐng)求完成后用于通知抽屜組件完成狀態(tài)
*/
RoleEdit(name, callback) {
callback(...res)
},
},
}
</script>
總結(jié):完成這樣一套邏輯之后歪赢,對(duì)應(yīng)功能節(jié)點(diǎn)只需要完成如圖表單組件和列表查詢(xún)組件,而且表單中只需處理數(shù)據(jù)单料,提示或者報(bào)錯(cuò)都放到drawer組件中進(jìn)行處理轨淌,極大程度上保護(hù)了自己的頭發(fā)。
另:有關(guān)事件總線(xiàn)不明白的地方可參考:Vue自動(dòng)銷(xiāo)毀的vue event Bus看尼。