48 lines
1.5 KiB
Vue
48 lines
1.5 KiB
Vue
<script setup lang="ts">
|
|
import { onUnmounted, watch } from 'vue'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
open: boolean
|
|
title: string
|
|
message: string
|
|
confirmText?: string
|
|
cancelText?: string
|
|
danger?: boolean
|
|
}>(), { confirmText: '确认', cancelText: '取消', danger: false })
|
|
|
|
const emit = defineEmits<{ (e: 'cancel'): void; (e: 'confirm'): void }>()
|
|
|
|
function onKey(e: KeyboardEvent) {
|
|
if (!props.open) return
|
|
if (e.key === 'Escape') emit('cancel')
|
|
}
|
|
watch(() => props.open, v => {
|
|
if (v) window.addEventListener('keydown', onKey)
|
|
else window.removeEventListener('keydown', onKey)
|
|
})
|
|
onUnmounted(() => window.removeEventListener('keydown', onKey))
|
|
</script>
|
|
|
|
<template>
|
|
<teleport to="body">
|
|
<transition name="modal">
|
|
<div v-if="open" class="mask" @click.self="emit('cancel')">
|
|
<div class="dialog" role="dialog" :aria-label="title">
|
|
<div class="dialog-title">{{ title }}</div>
|
|
<div class="dialog-msg">{{ message }}</div>
|
|
<div class="dialog-btns">
|
|
<button class="btn btn-sm" @click="emit('cancel')">{{ cancelText }}</button>
|
|
<button class="btn btn-sm" :class="danger ? 'btn-danger-solid' : 'btn-primary'" @click="emit('confirm')">{{ confirmText }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</teleport>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.dialog { width: 380px; }
|
|
.dialog-msg { margin-top: 8px; color: var(--text-2); font-size: 13px; line-height: 1.7; word-break: break-all; }
|
|
.dialog-btns { margin-top: 20px; }
|
|
</style>
|