一个基于Vue.js和Element UI框架的自定义对话框组件。这个组件名为biuDialog
,封装了Element UI的el-dialog
组件,并添加了一些自定义的功能和样式。
组件特点
-
自定义标题和底部:组件允许通过插槽(slots)来自定义对话框的标题和底部内容。如果没有提供自定义内容,它会使用默认的标题和底部按钮(取消和确定)。
-
控制显示和隐藏 :通过
visible
属性来控制对话框的显示和隐藏。show
计算属性与visible
属性同步,当show
改变时,会通过$emit
通知父组件。 -
事件回调 :提供了
open
、opened
、close
和closed
事件,以便在对话框打开或关闭时执行特定的逻辑。 -
关闭逻辑 :
beforeClose
方法允许在关闭对话框之前执行一些逻辑,例如确认操作。beforeClose2
方法是一个快捷方式,它在用户点击关闭按钮时触发。 -
样式定制 :通过
customClass
属性可以添加自定义样式。默认情况下,对话框有一个基础样式,可以通过SCSS样式部分进行修改。
组件属性
visible
: 对话框是否可见。title
: 对话框标题。appendToBody
: 对话框是否插入到body元素上。modal
: 是否需要遮罩层。fullscreen
: 是否全屏。destroyOnClose
: 关闭时是否销毁对话框中的元素。width
: 对话框宽度。top
: 对话框距离顶部的距离。customClass
: 自定义类名。showClose
: 是否显示关闭按钮。closeOnClickModal
: 是否可以通过点击遮罩层关闭对话框。beforeClose
: 关闭前的回调函数。
组件方法
open
: 触发open
事件。opened
: 触发opened
事件。close
: 触发close
事件。closed
: 触发closed
事件。cancel
: 触发cancel
事件,通常用于取消操作。submit
: 触发submit
事件,通常用于确认操作。
样式
样式使用了SCSS,并且是作用域化的,这意味着样式只应用于当前组件。对话框的头部和底部有特定的样式,可以通过修改这些样式来改变对话框的外观。
这个组件可以很容易地集成到使用Element UI的Vue.js项目中,为开发者提供了一个灵活且易于定制的对话框解决方案。
<template>
<div class="biu-dialog-box">
<el-dialog
:custom-class="customClass"
:title="$slots.title ? '' : title"
:visible.sync="show"
:width="width"
:top="top"
:append-to-body="appendToBody"
:modal="modal"
:fullscreen="fullscreen"
:destroy-on-close="destroyOnClose"
:modal-append-to-body="modalAppendToBody"
:before-close="beforeClose"
:close-on-click-modal="closeOnClickModal"
:show-close="false"
@open="open"
@opened="opened"
@close="close"
@closed="closed"
>
<!-- 有写弹窗头部则采用输入的 -->
<template v-if="$slots.title">
<span slot="title">
<slot name="title" />
</span>
</template>
<!-- 自定义默认头部 -->
<template v-if="!$slots.title">
<div slot="title" class="biu-default-header-box">
<div class="biu-default-header-title">{{ title }}</div>
<div
class="biu-default-header-close"
@click="beforeClose2"
v-if="showClose"
>
<span class="biu-icon-guanbi2">
<i class="el-icon-circle-close" style="font-size:16px"></i>
</span>
</div>
</div>
</template>
<!-- 弹窗内容区域 -->
<slot />
<!-- 弹窗底部区域 -->
<template v-if="$slots.footer">
<span slot="footer">
<slot name="footer" />
</span>
</template>
<!-- 自定义默认头部 -->
<template v-if="!$slots.footer">
<div slot="footer" class="biu-default-header-box">
<el-button class="btn" @click="cancel">取消</el-button>
<el-button class="btn sure" @click="submit">确定</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
export default {
name: "biuDialog",
props: {
visible: {
type: Boolean,
default: false,
},
title: {
type: String,
default: "提示",
},
appendToBody: {
// Dialog 自身是否插入至 body 元素上。嵌套的 Dialog 必须指定该属性并赋值为 true
type: Boolean,
default: true,
},
modalAppendToBody: {
// 遮罩层是否插入至 body 元素上,若为 false,则遮罩层会插入至 Dialog 的父元素上
type: Boolean,
default: true,
},
modal: {
// 是否需要遮罩层
type: Boolean,
default: true,
},
fullscreen: {
// 是否全屏
type: Boolean,
default: false,
},
destroyOnClose: {
// 关闭时销毁 Dialog 中的元素
type: Boolean,
default: true,
},
width: {
type: String,
default: "30%",
},
top: {
type: String,
default: "15vh",
},
customClass: {
type: String,
default: "biu-dialog",
},
showClose: {
type: Boolean,
default: false,
},
closeOnClickModal: {
type: Boolean,
default: true,
},
beforeClose: {
type: Function,
},
},
computed: {
show: {
get() {
return this.visible;
},
set(val) {
this.$emit("update:visible", val); // visible 改变的时候通知父组件
},
},
},
data() {
return {};
},
methods: {
//点击自定义的关闭按钮
beforeClose2() {
this.beforeClose(() => {
this.show = false;
});
},
open() {
// Dialog 打开的回调
this.$emit("open");
},
opened() {
// Dialog 打开动画结束时的回调
this.$emit("opened");
},
close() {
// Dialog 关闭的回调
this.$emit("close");
},
closed() {
// Dialog 关闭动画结束时的回调
this.$emit("closed");
},
cancel() {
this.$emit("cancel");
},
submit() {
this.$emit("submit");
},
},
};
</script>
<style scoped lang="scss">
:deep(.el-dialog) {
min-width: 320px;
.el-dialog__header {
padding: 0;
color: #d37332;
font-weight: 500;
height: 50px;
display: flex;
flex-direction: column;
justify-content: center;
border-bottom: 2px solid #e9e8e8;
font-size: 14px;
.biu-default-header-box {
padding: 0 20px;
display: flex;
line-height: 20px;
.biu-default-header-title {
flex: 1;
}
.biu-default-header-close {
width: 15px;
height: 15px;
cursor: pointer;
}
}
}
.el-dialog__footer {
padding: 0;
text-align: center;
height: 88px;
border-top: 2px solid #e9e8e8;
display: flex;
justify-content: center;
flex-direction: column;
.btn {
width: 120px;
height: 40px;
background: #e9e8e8;
border-radius: 2px;
}
.sure {
color: #ffffff;
background: #de9a6c;
margin-left: 66px;
}
}
}
</style>
在使用biuDialog
组件时,您可以通过Vue的插槽(slots)机制来自定义对话框的标题和底部。插槽允许您插入自定义的HTML、组件或者任何其他Vue实例,从而实现高度的灵活性和可定制性。
自定义标题
要自定义对话框的标题,您可以在组件实例中使用<slot>
元素,并给它命名(在这个例子中是title
)。例如:
html
<template>
<biu-dialog :visible.sync="dialogVisible" title="我的对话框">
<span slot="title">
<h1 class="custom-title">这是自定义标题</h1>
</span>
<!-- 对话框的其他内容 -->
</biu-dialog>
</template>
在这个例子中,<span slot="title">
定义了一个名为title
的插槽,您可以在其中放置任何您想要的内容。biuDialog
组件会检查是否有任何内容被插入到title
插槽中,如果有,它将使用这些内容作为对话框的标题。
自定义底部
自定义对话框底部的方法与自定义标题类似。您需要在biuDialog
组件中使用<slot>
元素,并为其命名为footer
。例如:
html
<template>
<biu-dialog :visible.sync="dialogVisible" title="我的对话框">
<!-- 对话框的内容 -->
<span slot="footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleConfirm">确认</el-button>
</span>
</biu-dialog>
</template>
在这个例子中,<span slot="footer">
定义了一个名为footer
的插槽,您可以在其中放置任何您想要的按钮或其他元素。当您需要不同的按钮或逻辑时,只需在插槽内容中进行更改即可。
注意事项
- 确保您的自定义内容不会破坏对话框的布局或功能。
- 如果您提供了自定义标题或底部,
biuDialog
组件将不会显示其默认的标题和底部。 - 使用插槽时,您需要了解父组件和子组件之间的数据传递和事件触发机制,以确保您的自定义内容能够正确响应用户的交互。
如果希望弹框内容通过配置显示,而不是硬编码在模板中,可以采用以下方法:
使用组件的props
传递配置
您可以在父组件中定义一些数据,这些数据将作为配置传递给biuDialog
组件。然后,在biuDialog
组件内部使用这些配置来动态渲染内容。
父组件示例
html
<template>
<div>
<!-- 触发弹框的按钮 -->
<el-button @click="openDialog">打开对话框</el-button>
<!-- 使用biuDialog组件 -->
<biu-dialog
:visible.sync="dialogVisible"
:config="dialogConfig"
>
</biu-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false,
dialogConfig: {
title: '配置标题',
content: '这是通过配置显示的内容'
// 可以添加更多配置项,如按钮文本、样式等
}
};
},
methods: {
openDialog() {
this.dialogVisible = true;
}
}
};
</script>
修改biuDialog
组件以接收和使用配置
您需要在biuDialog
组件中添加新的props
来接收配置,并在组件的模板中使用这些配置来渲染内容。
biuDialog
组件修改示例
javascript
export default {
// ...
props: {
// ...
config: {
type: Object,
default: () => ({
title: '默认标题',
content: '默认内容'
})
}
},
// ...
};
然后在模板中使用这些配置:
html
<template>
<!-- ...其他代码... -->
<div v-if="config.title" class="dialog-content">
{{ config.content }}
</div>
<!-- ...其他代码... -->
</template>
在这个例子中,config
对象包含了title
和content
属性,这些属性被用来动态渲染对话框的标题和内容。如果config
对象中的属性不存在,您可以设置默认值或者不渲染相应的内容。
注意事项
- 确保父组件传递的配置对象中的属性名称与子组件
props
中定义的名称相匹配。 - 在
biuDialog
组件中,您可能需要根据配置的不同来决定是否渲染某些元素,或者如何渲染它们。 - 如果配置项较多或者较为复杂,您可能需要在组件内部编写更多的逻辑来处理这些配置。
通过这种方式,可以使弹框内容更加灵活,根据需要轻松更改配置,而无需修改模板代码。
如果弹框内容是一个对象,且该对象包含多个元素,可以将这个对象作为配置传递给biuDialog
组件。然后在组件内部,根据这个对象的结构动态渲染每个元素。
父组件示例
在父组件中,您可以定义一个对象,该对象包含了弹框需要显示的所有元素和配置。然后,通过props
将这个对象传递给biuDialog
组件。
html
<template>
<div>
<!-- 触发弹框的按钮 -->
<el-button @click="openDialog">打开对话框</el-button>
<!-- 使用biuDialog组件 -->
<biu-dialog
:visible.sync="dialogVisible"
:dialog-content-object="contentObject"
>
</biu-dialog>
</div>
</template>
<script>
export default {
data() {
return {
dialogVisible: false,
contentObject: {
title: '详细信息',
elements: [
{ type: 'text', content: '这是一段文本。' },
{ type: 'image', src: 'path/to/image.jpg' },
{ type: 'button', text: '点击我', onClick: this.handleButtonClick }
// 更多元素...
]
},
handleButtonClick() {
// 处理按钮点击事件
console.log('按钮被点击了!');
}
}
},
methods: {
openDialog() {
this.dialogVisible = true;
}
}
};
</script>
修改biuDialog
组件以接收和使用对象配置
在biuDialog
组件中,您需要添加一个新的prop
来接收父组件传递的对象,并在模板中遍历这个对象的elements
数组,根据每个元素的type
来决定如何渲染。
javascript
export default {
// ...
props: {
// ...
dialogContentObject: {
type: Object,
default: () => ({
title: '',
elements: []
})
}
},
// ...
};
在模板中使用这个对象:
html
<template>
<el-dialog
:visible.sync="show"
:custom-class="customClass"
:title="config.title || dialogContentObject.title"
@open="open"
@opened="opened"
@close="close"
@closed="closed"
>
<!-- 遍历元素数组并渲染每个元素 -->
<div v-for="element in dialogContentObject.elements" :key="element.type">
<template v-if="element.type === 'text'">
<p>{{ element.content }}</p>
</template>
<template v-if="element.type === 'image'">
<img :src="element.src" alt="Image" />
</template>
<template v-if="element.type === 'button'">
<el-button @click="element.onClick">{{ element.text }}</el-button>
</template>
<!-- 更多类型的条件渲染... -->
</div>
</el-dialog>
</template>
在这个例子中,dialogContentObject
对象包含了一个title
和一个elements
数组。elements
数组中的每个元素都有一个type
属性,用于指示应该渲染哪种类型的元素(如文本、图片、按钮等)。模板中的v-for
指令用于遍历这些元素,并根据type
属性使用v-if
或v-else-if
来决定渲染哪种模板。
注意事项
- 确保父组件传递的对象结构与子组件中处理该对象的逻辑相匹配。
- 在处理事件(如按钮点击)时,确保事件处理函数能够正确地从父组件传递到子组件,并且能够在子组件中被正确调用。
- 如果元素类型未知或组件需要处理更多类型的元素,您可能需要扩展
v-if
/v-else-if
条件渲染逻辑,以支持更多的元素类型。
这种方法使得弹框内容的渲染完全基于配置,提供了极高的灵活性和可扩展性。您可以根据需要轻松添加或修改配置对象中的元素,而无需更改组件的模板代码。