SunlightDialog
基于 Element Plus Dialog 封装的增强版对话框组件,支持全屏切换、可拖拽、自定义高度、灵活的底部按钮配置等功能。
组件特性
- ✨ 支持全屏切换功能
- 🖱️ 支持拖拽功能
- 📏 支持自定义内容高度
- 🎨 灵活的底部按钮配置
- 🔄 支持双向绑定显示/隐藏
- 📌 支持自定义标题和底部插槽
基本使用
基础对话框
最简单的对话框使用方式,只需要提供标题和内容。
vue
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">打开对话框</el-button>
<SunlightDialog
v-model:visible="dialogVisible"
dialog-title="基本对话框"
content-height="400"
@on-confirm="handleConfirm"
@on-cancel="handleCancel"
>
<div class="dialog-content">
<p>这是一个基本的 SunlightDialog 对话框示例。</p>
<p>该组件基于 Element Plus Dialog 封装,提供了更多增强功能:</p>
<ul>
<li>支持全屏切换</li>
<li>支持拖拽功能</li>
<li>可自定义内容高度</li>
<li>灵活的底部按钮配置</li>
</ul>
<p>您可以通过点击右上角的全屏图标切换全屏模式,或者通过拖拽对话框标题栏移动对话框位置。</p>
</div>
</SunlightDialog>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { SunlightDialog } from 'sunlight-ui';
import { ElMessage } from 'element-plus';
// 对话框显示状态
const dialogVisible = ref(false);
// 处理确认按钮点击
const handleConfirm = () => {
ElMessage.success('点击了确认按钮');
dialogVisible.value = false;
};
// 处理取消按钮点击
const handleCancel = () => {
ElMessage.info('点击了取消按钮');
};
</script>
<style scoped>
.dialog-content {
padding: 20px;
line-height: 1.8;
}
.dialog-content ul {
margin: 10px 0;
padding-left: 20px;
}
.dialog-content li {
margin-bottom: 5px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
隐藏源代码
配置说明
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| v-model:visible | 对话框显示状态 | boolean | false |
| dialogTitle | 对话框标题 | string | '对话框' |
| contentHeight | 内容区域高度 | number | string | 400 |
| withFooter | 是否显示底部按钮 | boolean | true |
| confirmBtnText | 确认按钮文本 | string | '确认' |
| cancelBtnText | 取消按钮文本 | string | '取消' |
自定义表单组件
在对话框中集成复杂的表单组件,实现数据的录入和编辑功能。
vue
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">打开带表单的对话框</el-button>
<SunlightDialog
v-model:visible="dialogVisible"
dialog-title="自定义表单组件"
content-height="500"
@on-confirm="handleConfirm"
@on-cancel="handleCancel"
>
<el-form :model="formData" label-width="100px" :rules="rules" ref="formRef">
<el-form-item label="姓名" prop="name">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="年龄" prop="age">
<el-input-number v-model="formData.age" :min="1" :max="120" placeholder="请输入年龄" />
</el-form-item>
<el-form-item label="性别" prop="gender">
<el-radio-group v-model="formData.gender">
<el-radio label="male">男</el-radio>
<el-radio label="female">女</el-radio>
<el-radio label="other">其他</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" type="email" />
</el-form-item>
<el-form-item label="部门" prop="department">
<el-select v-model="formData.department" placeholder="请选择部门">
<el-option label="技术部" value="tech" />
<el-option label="市场部" value="market" />
<el-option label="销售部" value="sales" />
<el-option label="人事部" value="hr" />
</el-select>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="formData.remark" type="textarea" :rows="4" placeholder="请输入备注" />
</el-form-item>
</el-form>
</SunlightDialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { SunlightDialog } from 'sunlight-ui';
import { ElMessage } from 'element-plus';
// 对话框显示状态
const dialogVisible = ref(false);
// 表单引用
const formRef = ref();
// 表单数据
const formData = reactive({
name: '',
age: null,
gender: 'male',
email: '',
department: '',
remark: ''
});
// 表单验证规则
const rules = reactive({
name: [
{ required: true, message: '请输入姓名', trigger: 'blur' },
{ min: 2, max: 10, message: '姓名长度在 2 到 10 个字符', trigger: 'blur' }
],
age: [
{ required: true, message: '请输入年龄', trigger: 'blur' },
{ type: 'number', message: '年龄必须为数字值', trigger: 'blur' }
],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
department: [
{ required: true, message: '请选择部门', trigger: 'change' }
]
});
// 处理确认按钮点击
const handleConfirm = async () => {
if (!formRef.value) return;
try {
await formRef.value.validate();
ElMessage.success('表单验证通过,点击了确认按钮');
console.log('表单数据:', formData);
dialogVisible.value = false;
} catch (error) {
ElMessage.error('表单验证失败,请检查输入');
}
};
// 处理取消按钮点击
const handleCancel = () => {
ElMessage.info('点击了取消按钮');
// 重置表单
if (formRef.value) {
formRef.value.resetFields();
}
};
</script>
<style scoped>
/* 可以在这里添加自定义样式 */
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
隐藏源代码
配置说明
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| formOptions | 表单配置项 | Record<string, any> | {} |
| rules | 表单验证规则 | Record<string, any[]> | {} |
自定义表单 Label
通过插槽自定义表单标签的样式、内容和布局。
vue
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">打开自定义标签对话框</el-button>
<SunlightDialog
v-model:visible="dialogVisible"
dialog-title="自定义表单 Label"
content-height="450"
@on-confirm="handleConfirm"
@on-cancel="handleCancel"
>
<el-form :model="formData" label-width="120px" class="custom-label-form">
<!-- 自定义样式标签 -->
<el-form-item label="姓名" prop="name" class="custom-label-item">
<el-input v-model="formData.name" placeholder="请输入姓名" />
</el-form-item>
<!-- 带图标标签 -->
<el-form-item prop="email">
<template #label>
<span class="label-with-icon">
<el-icon><Message /></el-icon>
<span>邮箱</span>
</span>
</template>
<el-input v-model="formData.email" placeholder="请输入邮箱" type="email" />
</el-form-item>
<!-- 带必填标记的自定义标签 -->
<el-form-item prop="phone">
<template #label>
<span class="custom-required-label">
手机号
<span class="required-mark">*</span>
</span>
</template>
<el-input v-model="formData.phone" placeholder="请输入手机号" />
</el-form-item>
<!-- 多行标签 -->
<el-form-item prop="address">
<template #label>
<div class="multi-line-label">
<span>详细地址</span>
<small>(请填写完整地址,包括省市区街道)</small>
</div>
</template>
<el-input v-model="formData.address" type="textarea" :rows="3" placeholder="请输入详细地址" />
</el-form-item>
<!-- 自定义颜色标签 -->
<el-form-item prop="status">
<template #label>
<span class="color-label">状态</span>
</template>
<el-select v-model="formData.status" placeholder="请选择状态">
<el-option label="启用" value="active" />
<el-option label="禁用" value="disabled" />
</el-select>
</el-form-item>
</el-form>
</SunlightDialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import { SunlightDialog } from 'sunlight-ui';
import { ElMessage } from 'element-plus';
import { Message } from '@element-plus/icons-vue';
// 对话框显示状态
const dialogVisible = ref(false);
// 表单数据
const formData = reactive({
name: '',
email: '',
phone: '',
address: '',
status: 'active'
});
// 处理确认按钮点击
const handleConfirm = () => {
ElMessage.success('点击了确认按钮');
console.log('表单数据:', formData);
dialogVisible.value = false;
};
// 处理取消按钮点击
const handleCancel = () => {
ElMessage.info('点击了取消按钮');
};
</script>
<style scoped>
.custom-label-form {
padding: 10px 0;
}
/* 自定义样式标签 */
.custom-label-item :deep(.el-form-item__label) {
font-weight: bold;
color: #67C23A;
font-size: 15px;
}
/* 带图标标签 */
.label-with-icon {
display: flex;
align-items: center;
gap: 6px;
font-weight: 500;
}
.label-with-icon .el-icon {
color: #409EFF;
}
/* 带必填标记的自定义标签 */
.custom-required-label {
display: flex;
align-items: center;
gap: 4px;
}
.required-mark {
color: #F56C6C;
font-size: 14px;
margin-right: 4px;
}
/* 多行标签 */
.multi-line-label {
display: flex;
flex-direction: column;
gap: 2px;
}
.multi-line-label small {
font-size: 11px;
color: #909399;
font-weight: normal;
}
/* 自定义颜色标签 */
.color-label {
color: #E6A23C;
font-weight: bold;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
隐藏源代码
配置说明
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| labelWidth | 标签宽度 | string | number | '80px' |
| labelPosition | 标签位置 | 'left' | 'right' | 'top' | 'right' |
自定义底部
通过插槽自定义对话框的底部按钮区域,支持多按钮布局和自定义样式。
vue
<template>
<div>
<el-button type="primary" @click="dialogVisible = true">打开自定义底部对话框</el-button>
<SunlightDialog
v-model:visible="dialogVisible"
dialog-title="自定义底部"
content-height="300"
@on-confirm="handleConfirm"
@on-cancel="handleCancel"
>
<!-- 对话框内容 -->
<div class="dialog-content">
<p>这是一个自定义底部的对话框示例,您可以通过插槽自定义底部的按钮和布局。</p>
<p>底部区域可以包含多个按钮、不同样式的按钮,或者其他自定义内容。</p>
</div>
<!-- 底部上方的额外内容 -->
<template #footer-top>
<div class="footer-top-content">
<el-divider />
<div class="additional-info">
<el-icon><InfoFilled /></el-icon>
<span>点击"确认"将保存当前设置,点击"取消"将关闭对话框。</span>
</div>
</div>
</template>
<!-- 自定义底部按钮 -->
<template #footer="{ handleConfirmClick, handleCancelClick }">
<div class="custom-footer">
<!-- 左侧按钮 -->
<div class="footer-left">
<el-button type="info" @click="handleReset">重置</el-button>
<el-button type="warning" @click="handlePreview">预览</el-button>
</div>
<!-- 右侧按钮 -->
<div class="footer-right">
<el-button @click="handleCancelClick">取消</el-button>
<el-button type="primary" :loading="isLoading" @click="handleConfirmClick">
<el-icon v-if="isLoading"><Loading /></el-icon>
<span>确认</span>
</el-button>
<el-button type="success" @click="handleSaveAndContinue">保存并继续</el-button>
</div>
</div>
</template>
</SunlightDialog>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { SunlightDialog } from 'sunlight-ui';
import { ElMessage } from 'element-plus';
import { InfoFilled, Loading } from '@element-plus/icons-vue';
// 对话框显示状态
const dialogVisible = ref(false);
// 加载状态
const isLoading = ref(false);
// 处理确认按钮点击
const handleConfirm = () => {
isLoading.value = true;
// 模拟异步操作
setTimeout(() => {
isLoading.value = false;
ElMessage.success('点击了确认按钮');
dialogVisible.value = false;
}, 1500);
};
// 处理取消按钮点击
const handleCancel = () => {
ElMessage.info('点击了取消按钮');
};
// 处理重置按钮点击
const handleReset = () => {
ElMessage.warning('点击了重置按钮');
};
// 处理预览按钮点击
const handlePreview = () => {
ElMessage.info('点击了预览按钮');
};
// 处理保存并继续按钮点击
const handleSaveAndContinue = () => {
ElMessage.success('点击了保存并继续按钮');
};
</script>
<style scoped>
.dialog-content {
padding: 20px;
line-height: 1.8;
}
/* 底部上方内容 */
.footer-top-content {
margin: 10px 0;
}
.additional-info {
display: flex;
align-items: center;
gap: 8px;
color: #909399;
font-size: 14px;
margin-top: 10px;
}
/* 自定义底部样式 */
.custom-footer {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 10px 0;
}
.footer-left,
.footer-right {
display: flex;
gap: 10px;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
隐藏源代码
配置说明
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| footerButtonAlign | 底部按钮对齐方式 | 'left' | 'center' | 'right' | 'right' |
事件说明
| 事件名 | 说明 | 参数 |
|---|---|---|
| update:visible | 对话框显示状态变化事件 | value: boolean |
| toggle-fullscreen | 全屏状态切换事件 | value: boolean |
| on-confirm | 确认按钮点击事件 | - |
| on-cancel | 取消按钮点击事件 | - |
插槽说明
| 插槽名 | 说明 | 参数 |
|---|---|---|
| default | 对话框内容区域 | - |
| header | 对话框头部区域 | headerScope |
| header-title | 对话框标题区域 | - |
| fullscreen-toggle | 全屏切换图标区域 | { isFullscreenMode, handleFullscreenToggle } |
| footer | 对话框底部按钮区域 | { handleConfirmClick, handleCancelClick } |
| footer-top | 底部按钮上方的插槽 | - |
方法说明
| 方法名 | 说明 | 参数 |
|---|---|---|
| showDialog | 显示对话框 | - |
| hideDialog | 隐藏对话框 | - |
| handleConfirmClick | 触发确认事件 | - |
| handleCancelClick | 触发取消事件 | - |
| handleFullscreenToggle | 切换全屏状态 | - |