彈出對話框在平常開發中應用得十分普遍,不管是Web網頁,仍是App,又或者是桌面應用,均可以使用對話框實現一種較高體驗性的人機交互,瀏覽ElementUi
,咱們能夠看到在其組件庫中,關於彈出的組件有不少:對話框、彈出框、文字提示、氣泡確認框···vue
關於Ui庫開發,我的按照ElementUi
的組件種類,以Pc端爲核心,建立了一套【適配VUE + LESS】的開源UI庫項目,若是你們感興趣,歡迎來GIT上踩踩git
附件:github
本文將帶來的是摸一個ElementUi
對話框,從零到一讓你們明白一個合格的組件是如何打造的bash
關於組件,能夠分爲業務組件
和通用組件
app
UI
組件,無具體功能實現實現一個合格的組件,該如何思考? 思考功能 → 提取業務功能與基本功能 → 實現基本功能,定義業務功能接口
less
根據ElementUi
對話框的功能屬性進行篩選,咱們實現如下需求:ide
slot
slot
由用戶自定義index.vue
:組件文件index.less
:樣式表view01.vue
:測試組件文件index.vue
組件文件❗ Ps:函數
$slots.footer
- 用於判斷父組件中所使用的slot是否包括具名爲footer的插槽this.$emit('update:visible', false)
- 該用法須要父組件配合,在綁定visible
時使用sync
修飾符,實現子組件修改父組件值handleClose
- 該方法當父組件有傳遞beforeClose且爲function時,而後傳遞hide()
做爲參數並執行,這個用法實如今關閉以前進行額外操做,父組件的beforeClose
函數能夠接受一個參數,用於主動關閉彈窗<template>
<div class='cai-dialog-wrapper' ref='dialog-wrapper' v-show='visibleDialog' @click.self='handleWrapperClick'>
<transition name="dialog-fade">
<div ref='dialog'
:class="['cai-dialog',{ 'cai-dialog-dark':dark },customClass]"
:style='dialogSize'
v-if='dialogRender'
>
<!-- 對話框頭部 -->
<div class='cai-dialog-header'>
<!-- 對話框標題,可被替換 -->
<slot name='title'>
<span class='cai-dialog__title'>{{ title }}</span>
</slot>
<!-- 關閉對話框按鈕 -->
<button
type='button'
class='cai-dialog__headerbtn'
aria-label='Close'
v-if='displayClose'
@click='handleClose'>
<i class='cai-icon-close'></i>
</button>
</div>
<!-- 對話框主體 -->
<div class='cai-dialog-body'>
<slot></slot>
</div>
<!-- 對話框底部 -->
<div class='cai-dialog-footer' v-if='$slots.footer'>
<slot name='footer'></slot>
</div>
</div>
</transition>
</div>
</template>
<script>
export default {
name:'CaiDialog',
data(){
return{
visibleDialog:false,
dialogRender:false,
dialogSize:{} // body寬高用於設置居中
}
},
props:{
visible:{
type: Boolean,
default: false
},
title:{
type: String,
default: ''
},
// 關閉彈窗前的回調(接收一個參數 done())
beforeClose: Function,
// 是否須要遮罩層
modal:{
type: Boolean,
default: true
},
// 是否在 Dialog 出現時將 body 滾動鎖定
lockScroll: {
type: Boolean,
default: true
},
// 是否能夠經過點擊 modal 關閉 Dialog
closeOnClickModal: {
type: Boolean,
default: false
},
// 是否顯示右上角關閉按鈕
displayClose:{
type: Boolean,
default: true
},
// 最大寬高
width: String,
height: String,
// 主題顏色 - 高亮(默認) | 夜間
dark:{
type:Boolean,
default:false
},
// 自定義類
customClass: {
type:String,
default:''
}
},
watch:{
visible(newVal){
if(newVal){
this.visibleDialog = true
this.dialogRender = true
// 依據props修改樣式
this.changeDialogStyle()
this.$emit('open')
}else{
this.visibleDialog = false
this.dialogRender = false
document.body.style['overflow'] = 'auto'
this.$emit('close')
}
}
},
methods:{
handleWrapperClick(){
if(!this.closeOnClickModal) return
this.handleClose()
},
// 處理關閉對話框,若存在beforeClose則調用
handleClose(){
if(typeof this.beforeClose === 'function') {
this.beforeClose(this.hide)
}else{
this.hide()
}
},
hide(){
this.$emit('update:visible', false);
},
// 根據Props值修改Dialog樣式
changeDialogStyle(){
// lockScroll - 實現底層禁止滾動
if(this.lockScroll) document.body.style['overflow'] = 'hidden'
var that = this
this.$nextTick(() => {
var dialogWrapperStyle = that.$refs['dialog-wrapper'].style
var dialogStyle = that.$refs.dialog.style
if(that.width) dialogStyle.width = that.width + 'px'
if(that.height) dialogStyle.height = that.height + 'px'
// 實現無遮罩層
if(!that.modal) dialogWrapperStyle.background = 'transparent'
})
}
}
}
</script>
<style lang='less' scoped>
@import './index.less';
@import '../../CaiIcon/component/index.less'; // Icon樣式表,可忽略
</style>
複製代碼
index.less
樣式表.cai-dialog-wrapper{
position: fixed;
top:0;
bottom:0;
right: 0;
left: 0;
overflow: auto;
background: rgba(0,0,0,0.6);
z-index:1999;
// 默認樣式
.cai-dialog{
position:absolute;
border:1px solid rgba(247, 241, 240);
border-radius:5px;
color:#303952;
padding:10px;
left:50%;
top:50%;
transform:translate(-50%, -50%);
display:flex;
flex-direction: column;
justify-content: space-between;
background: rgba(247, 241, 240);
min-width:200px;
min-height:100px;
overflow: auto;
.cai-dialog-header{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom:10px;
font-size:14px;
.cai-dialog__title{
font-weight: 600;
}
.cai-dialog__headerbtn{
background: transparent;
border-color: transparent;
padding:0;
outline:none;
.cai-icon-close{
color:#303952;
cursor:pointer;
transition: all .1s linear;
&:hover{
color:#ff3f34;
}
}
}
}
.cai-dialog-body{
flex:1;
}
}
// 夜間模式
.cai-dialog-dark{
border-color:#3d3d3d;
background: #3d3d3d;
color:#fff;
.cai-dialog-header{
.cai-dialog__headerbtn{
.cai-icon-close{
color:#fff;
cursor:pointer;
transition: all .1s linear;
&:hover{
color:#ef5777;
}
}
}
}
}
// 進入/離開 動畫
.dialog-fade-enter-active, .dialog-fade-leave-active {
transition: all .3s linear;
}
.dialog-fade-enter {
opacity: 0;
top:48%;
}
}
複製代碼
view01.vue
測試組件文件<!--
visible - 控制顯示
title - 彈窗標題
beforeClose - 彈窗關閉前回調
modal - 是否須要遮罩層
lockScroll - 是否在 Dialog 出現時將 body 滾動鎖定
closeOnClickModal - 是否能夠經過點擊 modal 關閉 Dialog
displayClose - 是否顯示右上角關閉按鈕
dark - 主題顏色 - 高亮(默認) | 夜間
customClass - 自定義類
@open - Dialog 打開的回調
@close - Dialog 關閉的回調
slot {
footer - 底部
不具名 - 內容
}
-->
<div style='width:310px;padding:20px;border:1px solid #DDDDDD;display:flex;flex-wrap:wrap;'>
<cai-button @click='openDialog1'>高亮對話框</cai-button>
<cai-dialog :visible.sync='showDialog1' closeOnClickModal width='400' height='200' title='I am Light' :before-close='handleDialogClose' @open='DialogOpen' @close='DialogClose'>
I am a Dialog
<span slot="footer" style='display:flex;justify-content:flex-end;'>
<cai-button @click="showDialog1 = false">取 消</cai-button>
<cai-button @click="showDialog1 = false">確 定</cai-button>
</span>
</cai-dialog>
<cai-divider></cai-divider>
<cai-button @click='openDialog2'>夜間對話框</cai-button>
<cai-dialog :visible.sync='showDialog2' dark :displayClose='false' :lockScroll='false' :before-close='handleDialogClose'>
<!-- 經過slot自定義頭部 -->
<span slot="title">
I am Dark
</span>
I am a Dialog
<span slot="footer" style='display:flex;justify-content:flex-end;'>
<cai-button @click="showDialog2 = false">取 消</cai-button>
<cai-button @click="showDialog2 = false">確 定</cai-button>
</span>
</cai-dialog>
</div>
複製代碼
data(){
return{
// Dialog
showDialog1:false,
showDialog2:false
}
}
methods(){
openDialog1(){
this.showDialog1 = true
},
openDialog2(){
this.showDialog2 = true
},
DialogOpen(){
console.log('DialogOpen')
},
DialogClose(){
console.log('DialogOpen')
},
handleDialogClose(done){
console.log('彈窗被關閉')
done()
}
}
複製代碼
組件開源地址post
該開源git是一個開源UI庫項目,目前開發近20款適配Vue
的UI組件,有興趣的小夥伴給點⭐
部分組件截圖