弹出对话框在平常开发中应用得十分普遍,不管是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组件,有兴趣的小伙伴给点⭐
部分组件截图