After Width: | Height: | Size: 209 B |
After Width: | Height: | Size: 127 B |
After Width: | Height: | Size: 127 B |
After Width: | Height: | Size: 568 B |
After Width: | Height: | Size: 411 B |
After Width: | Height: | Size: 337 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 428 B |
After Width: | Height: | Size: 276 B |
After Width: | Height: | Size: 326 B |
After Width: | Height: | Size: 221 B |
After Width: | Height: | Size: 399 B |
After Width: | Height: | Size: 276 B |
After Width: | Height: | Size: 191 B |
After Width: | Height: | Size: 394 B |
After Width: | Height: | Size: 725 B |
After Width: | Height: | Size: 349 B |
After Width: | Height: | Size: 613 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 385 B |
After Width: | Height: | Size: 393 B |
After Width: | Height: | Size: 195 B |
After Width: | Height: | Size: 390 B |
After Width: | Height: | Size: 294 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 389 B |
After Width: | Height: | Size: 885 B |
After Width: | Height: | Size: 109 B |
After Width: | Height: | Size: 116 B |
After Width: | Height: | Size: 336 B |
After Width: | Height: | Size: 398 B |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 635 B |
After Width: | Height: | Size: 413 B |
After Width: | Height: | Size: 165 B |
After Width: | Height: | Size: 148 B |
After Width: | Height: | Size: 532 B |
After Width: | Height: | Size: 599 B |
After Width: | Height: | Size: 321 B |
After Width: | Height: | Size: 453 B |
After Width: | Height: | Size: 369 B |
After Width: | Height: | Size: 240 B |
After Width: | Height: | Size: 190 B |
After Width: | Height: | Size: 217 B |
After Width: | Height: | Size: 207 B |
After Width: | Height: | Size: 216 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 334 B |
After Width: | Height: | Size: 168 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 319 B |
After Width: | Height: | Size: 299 B |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 345 B |
After Width: | Height: | Size: 336 B |
After Width: | Height: | Size: 242 B |
After Width: | Height: | Size: 170 B |
After Width: | Height: | Size: 188 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 281 B |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 166 KiB |
After Width: | Height: | Size: 164 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 178 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 236 KiB |
After Width: | Height: | Size: 235 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 239 KiB |
After Width: | Height: | Size: 242 KiB |
After Width: | Height: | Size: 246 KiB |
After Width: | Height: | Size: 248 KiB |
After Width: | Height: | Size: 248 KiB |
After Width: | Height: | Size: 197 KiB |
After Width: | Height: | Size: 245 KiB |
After Width: | Height: | Size: 246 KiB |
After Width: | Height: | Size: 334 KiB |
After Width: | Height: | Size: 340 KiB |
After Width: | Height: | Size: 327 KiB |
After Width: | Height: | Size: 250 KiB |
After Width: | Height: | Size: 815 KiB |
After Width: | Height: | Size: 331 KiB |
After Width: | Height: | Size: 330 KiB |
After Width: | Height: | Size: 252 KiB |
After Width: | Height: | Size: 253 KiB |
After Width: | Height: | Size: 248 KiB |
After Width: | Height: | Size: 253 KiB |
@ -0,0 +1,171 @@ |
|||||
|
import { EditorComponent, EDITOR_COMPONENT } from '../../editor' |
||||
|
import './dialog.css' |
||||
|
|
||||
|
export interface IDialogData { |
||||
|
type: string |
||||
|
label?: string |
||||
|
name: string |
||||
|
value?: string |
||||
|
options?: { label: string; value: string }[] |
||||
|
placeholder?: string |
||||
|
width?: number |
||||
|
height?: number |
||||
|
required?: boolean |
||||
|
} |
||||
|
|
||||
|
export interface IDialogConfirm { |
||||
|
name: string |
||||
|
value: string |
||||
|
} |
||||
|
|
||||
|
export interface IDialogOptions { |
||||
|
onClose?: () => void |
||||
|
onCancel?: () => void |
||||
|
onConfirm?: (payload: IDialogConfirm[]) => void |
||||
|
title: string |
||||
|
data: IDialogData[] |
||||
|
} |
||||
|
|
||||
|
export class Dialog { |
||||
|
private options: IDialogOptions |
||||
|
private mask: HTMLDivElement | null |
||||
|
private container: HTMLDivElement | null |
||||
|
private inputList: ( |
||||
|
| HTMLInputElement |
||||
|
| HTMLTextAreaElement |
||||
|
| HTMLSelectElement |
||||
|
)[] |
||||
|
|
||||
|
constructor(options: IDialogOptions) { |
||||
|
this.options = options |
||||
|
this.mask = null |
||||
|
this.container = null |
||||
|
this.inputList = [] |
||||
|
this._render() |
||||
|
} |
||||
|
|
||||
|
private _render() { |
||||
|
const { title, data, onClose, onCancel, onConfirm } = this.options |
||||
|
// 渲染遮罩层
|
||||
|
const mask = document.createElement('div') |
||||
|
mask.classList.add('dialog-mask') |
||||
|
mask.setAttribute(EDITOR_COMPONENT, EditorComponent.COMPONENT) |
||||
|
document.body.append(mask) |
||||
|
// 渲染容器
|
||||
|
const container = document.createElement('div') |
||||
|
container.classList.add('dialog-container') |
||||
|
container.setAttribute(EDITOR_COMPONENT, EditorComponent.COMPONENT) |
||||
|
// 弹窗
|
||||
|
const dialogContainer = document.createElement('div') |
||||
|
dialogContainer.classList.add('dialog') |
||||
|
container.append(dialogContainer) |
||||
|
// 标题容器
|
||||
|
const titleContainer = document.createElement('div') |
||||
|
titleContainer.classList.add('dialog-title') |
||||
|
// 标题&关闭按钮
|
||||
|
const titleSpan = document.createElement('span') |
||||
|
titleSpan.append(document.createTextNode(title)) |
||||
|
const titleClose = document.createElement('i') |
||||
|
titleClose.onclick = () => { |
||||
|
if (onClose) { |
||||
|
onClose() |
||||
|
} |
||||
|
this._dispose() |
||||
|
} |
||||
|
titleContainer.append(titleSpan) |
||||
|
titleContainer.append(titleClose) |
||||
|
dialogContainer.append(titleContainer) |
||||
|
// 选项容器
|
||||
|
const optionContainer = document.createElement('div') |
||||
|
optionContainer.classList.add('dialog-option') |
||||
|
// 选项
|
||||
|
for (let i = 0; i < data.length; i++) { |
||||
|
const option = data[i] |
||||
|
const optionItemContainer = document.createElement('div') |
||||
|
optionItemContainer.classList.add('dialog-option__item') |
||||
|
// 选项名称
|
||||
|
if (option.label) { |
||||
|
const optionName = document.createElement('span') |
||||
|
optionName.append(document.createTextNode(option.label)) |
||||
|
optionItemContainer.append(optionName) |
||||
|
if (option.required) { |
||||
|
optionName.classList.add('dialog-option__item--require') |
||||
|
} |
||||
|
} |
||||
|
// 选项输入框
|
||||
|
let optionInput: |
||||
|
| HTMLInputElement |
||||
|
| HTMLTextAreaElement |
||||
|
| HTMLSelectElement |
||||
|
if (option.type === 'select') { |
||||
|
optionInput = document.createElement('select') |
||||
|
option.options?.forEach(item => { |
||||
|
const optionItem = document.createElement('option') |
||||
|
optionItem.value = item.value |
||||
|
optionItem.label = item.label |
||||
|
optionInput.append(optionItem) |
||||
|
}) |
||||
|
} else if (option.type === 'textarea') { |
||||
|
optionInput = document.createElement('textarea') |
||||
|
} else { |
||||
|
optionInput = document.createElement('input') |
||||
|
optionInput.type = option.type |
||||
|
} |
||||
|
if (option.width) { |
||||
|
optionInput.style.width = `${option.width}px` |
||||
|
} |
||||
|
if (option.height) { |
||||
|
optionInput.style.height = `${option.height}px` |
||||
|
} |
||||
|
optionInput.name = option.name |
||||
|
optionInput.value = option.value || '' |
||||
|
if (!(optionInput instanceof HTMLSelectElement)) { |
||||
|
optionInput.placeholder = option.placeholder || '' |
||||
|
} |
||||
|
optionItemContainer.append(optionInput) |
||||
|
optionContainer.append(optionItemContainer) |
||||
|
this.inputList.push(optionInput) |
||||
|
} |
||||
|
dialogContainer.append(optionContainer) |
||||
|
// 按钮容器
|
||||
|
const menuContainer = document.createElement('div') |
||||
|
menuContainer.classList.add('dialog-menu') |
||||
|
// 取消按钮
|
||||
|
const cancelBtn = document.createElement('button') |
||||
|
cancelBtn.classList.add('dialog-menu__cancel') |
||||
|
cancelBtn.append(document.createTextNode('取消')) |
||||
|
cancelBtn.type = 'button' |
||||
|
cancelBtn.onclick = () => { |
||||
|
if (onCancel) { |
||||
|
onCancel() |
||||
|
} |
||||
|
this._dispose() |
||||
|
} |
||||
|
menuContainer.append(cancelBtn) |
||||
|
// 确认按钮
|
||||
|
const confirmBtn = document.createElement('button') |
||||
|
confirmBtn.append(document.createTextNode('确定')) |
||||
|
confirmBtn.type = 'submit' |
||||
|
confirmBtn.onclick = () => { |
||||
|
if (onConfirm) { |
||||
|
const payload = this.inputList.map<IDialogConfirm>(input => ({ |
||||
|
name: input.name, |
||||
|
value: input.value |
||||
|
})) |
||||
|
onConfirm(payload) |
||||
|
} |
||||
|
this._dispose() |
||||
|
} |
||||
|
menuContainer.append(confirmBtn) |
||||
|
dialogContainer.append(menuContainer) |
||||
|
// 渲染
|
||||
|
document.body.append(container) |
||||
|
this.container = container |
||||
|
this.mask = mask |
||||
|
} |
||||
|
|
||||
|
private _dispose() { |
||||
|
this.mask?.remove() |
||||
|
this.container?.remove() |
||||
|
} |
||||
|
} |
@ -0,0 +1,131 @@ |
|||||
|
.dialog-mask { |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
opacity: .5; |
||||
|
background: #000000; |
||||
|
z-index: 99; |
||||
|
} |
||||
|
|
||||
|
.dialog-container { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
left: 0; |
||||
|
overflow: auto; |
||||
|
z-index: 999; |
||||
|
margin: 0; |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.dialog { |
||||
|
position: absolute; |
||||
|
padding: 0 30px 30px; |
||||
|
background: #ffffff; |
||||
|
box-shadow: 0 2px 12px 0 rgb(56 56 56 / 20%); |
||||
|
border: 1px solid #e2e6ed; |
||||
|
border-radius: 2px; |
||||
|
} |
||||
|
|
||||
|
.dialog-title { |
||||
|
position: relative; |
||||
|
border-bottom: 1px solid #e2e6ed; |
||||
|
margin-bottom: 30px; |
||||
|
height: 60px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.dialog-title i { |
||||
|
width: 16px; |
||||
|
height: 16px; |
||||
|
cursor: pointer; |
||||
|
display: inline-block; |
||||
|
background: url(../../assets/images/close.svg); |
||||
|
} |
||||
|
|
||||
|
.dialog-option__item { |
||||
|
margin-bottom: 18px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.dialog-option__item span { |
||||
|
margin-right: 12px; |
||||
|
font-size: 14px; |
||||
|
color: #3d4757; |
||||
|
position: relative; |
||||
|
} |
||||
|
|
||||
|
.dialog-option__item input, |
||||
|
.dialog-option__item textarea, |
||||
|
.dialog-option__item select { |
||||
|
width: 276px; |
||||
|
height: 30px; |
||||
|
border-radius: 2px; |
||||
|
border: 1px solid #d3d3d3; |
||||
|
min-height: 30px; |
||||
|
padding: 5px; |
||||
|
box-sizing: border-box; |
||||
|
outline: none; |
||||
|
appearance: none; |
||||
|
user-select: none; |
||||
|
font-family: inherit; |
||||
|
} |
||||
|
|
||||
|
.dialog-option__item input:focus, |
||||
|
.dialog-option__item textarea:focus { |
||||
|
border-color: #4991f2; |
||||
|
} |
||||
|
|
||||
|
.dialog-option__item--require::before { |
||||
|
content: "*"; |
||||
|
color: #f56c6c; |
||||
|
margin-right: 4px; |
||||
|
position: absolute; |
||||
|
left: -8px; |
||||
|
} |
||||
|
|
||||
|
.dialog-menu { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: flex-end; |
||||
|
} |
||||
|
|
||||
|
.dialog-menu button { |
||||
|
position: relative; |
||||
|
display: inline-block; |
||||
|
border: 1px solid #e2e6ed; |
||||
|
border-radius: 2px; |
||||
|
background: #ffffff; |
||||
|
line-height: 22px; |
||||
|
padding: 0 16px; |
||||
|
white-space: nowrap; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
|
||||
|
.dialog-menu button:hover { |
||||
|
background: rgba(25, 55, 88, .04); |
||||
|
} |
||||
|
|
||||
|
.dialog-menu__cancel { |
||||
|
margin-right: 16px; |
||||
|
} |
||||
|
|
||||
|
.dialog-menu button[type='submit'] { |
||||
|
color: #ffffff; |
||||
|
background: #4991f2; |
||||
|
border-color: #4991f2; |
||||
|
} |
||||
|
|
||||
|
.dialog-menu button[type='submit']:hover { |
||||
|
background: #5b9cf3; |
||||
|
border-color: #5b9cf3; |
||||
|
} |