You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

292 lines
7.4 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view>
<wd-popup
transition="zoom-in"
v-model="show"
:close-on-click-modal="closeOnClickModal"
:lazy-render="lazyRender"
custom-class="wd-message-box"
@click-modal="toggleModal('modal')"
:z-index="zIndex"
:duration="200"
>
<view :class="rootClass">
<!--内容部分-->
<view :class="bodyClass">
<!--title-->
<view v-if="title" class="wd-message-box__title">
{{ title }}
</view>
<!--其它类型-->
<view class="wd-message-box__content">
<!--prompt类型-->
<block v-if="type === 'prompt'">
<!--输入框-->
<wd-input v-model="inputValue" :type="inputType" size="large" :placeholder="inputPlaceholder || '请输入'" @input="inputValChange" />
<!--错误提示-->
<view v-if="showErr" class="wd-message-box__input-error">
{{ inputError || '输入的数据不合法' }}
</view>
</block>
<!--使用插槽-->
<slot v-if="useSlot"></slot>
<!--使用文本-->
<block v-else>{{ msg }}</block>
</view>
</view>
<!--action按钮组合-->
<view :class="`wd-message-box__actions ${showCancelButton ? 'wd-message-box__flex' : 'wd-message-box__block'}`">
<wd-button type="info" block v-if="showCancelButton" custom-style="margin-right: 16px;" @click="toggleModal('cancel')">
{{ cancelButtonText || '取消' }}
</wd-button>
<wd-button block @click="toggleModal('confirm')">
{{ confirmButtonText || '确定' }}
</wd-button>
</view>
</view>
</wd-popup>
</view>
</template>
<script lang="ts">
export default {
name: 'wd-message-box',
options: {
virtualHost: true,
addGlobalClass: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, inject, ref, watch } from 'vue'
import type { MessageOptions, MessageType } from './types'
import { defaultOptions, messageDefaultOptionKey } from '.'
import { isDef } from '../common/util'
interface Props {
useSlot?: boolean
selector?: string
customClass?: string
}
const props = withDefaults(defineProps<Props>(), {
useSlot: false,
customClass: '',
selector: ''
})
const rootClass = computed(() => {
return `wd-message-box__container ${props.customClass}`
})
const bodyClass = computed(() => {
return `wd-message-box__body ${!title.value ? 'is-no-title' : ''} ${type.value === 'prompt' ? 'is-prompt' : ''}`
})
const messageOptionKey = props.selector ? messageDefaultOptionKey + props.selector : messageDefaultOptionKey
const messageOption = inject(messageOptionKey, ref<MessageOptions>(defaultOptions)) // message选项
/**
* 消息文案
*/
const msg = ref<string>('')
// eslint-disable-next-line @typescript-eslint/ban-types
let onConfirm: Function | null = null
// eslint-disable-next-line @typescript-eslint/ban-types
let onCancel: Function | null = null
const show = ref<boolean>(false)
/**
* 标题
*/
const title = ref<string>('')
/**
* 是否展示取消按钮
*/
const showCancelButton = ref<boolean>(false)
/**
* 是否支持点击蒙层进行关闭点击蒙层回调传入的action为'modal'
*/
const closeOnClickModal = ref<boolean>(true)
/**
* 确定按钮文案
*/
const confirmButtonText = ref<string>('')
/**
* 取消按钮文案
*/
const cancelButtonText = ref<string>('')
/**
* 弹框类型
*/
const type = ref<MessageType>('alert')
/**
* 当type为prompt时输入框类型
*/
const inputType = ref<string>('text')
/**
* 当type为prompt时输入框初始值
*/
const inputValue = ref<string | number>('')
/**
* 当type为prompt时输入框placeholder
*/
const inputPlaceholder = ref<string>('')
/**
* 当type为prompt时输入框正则校验点击确定按钮时进行校验
*/
const inputPattern = ref<RegExp>()
/**
* 当type为prompt时输入框校验函数点击确定按钮时进行校验
*/
// eslint-disable-next-line @typescript-eslint/ban-types
let inputValidate: Function | null = null
/**
* 当type为prompt时输入框检验不通过时的错误提示文案
*/
const inputError = ref<string>('')
const showErr = ref<boolean>(false)
/**
* 弹窗层级
*/
const zIndex = ref<number>(99)
/**
* 弹层内容懒渲染,触发展示时才渲染内容
*/
const lazyRender = ref<boolean>(true)
// 监听options变化展示
watch(
() => messageOption.value,
(newVal: MessageOptions) => {
reset(newVal)
},
{
deep: true,
immediate: true
}
)
watch(
() => show.value,
(newValue) => {
resetErr(newValue)
},
{
deep: true,
immediate: true
}
)
/**
* @description 关闭消息框的统一主调 handle
* @param {'cancel' | 'confirm'} action
*/
function toggleModal(action: 'confirm' | 'cancel' | 'modal') {
// closeOnClickModal为false此时点击蒙层没任何效果
if (action === 'modal' && !closeOnClickModal.value) {
return
}
// prompt类型的弹窗 文案没有通过校验,点击了确定按钮没有任何效果
if (type.value === 'prompt' && action === 'confirm' && !validate()) {
return
}
show.value = false
switch (action) {
case 'confirm':
onConfirm &&
onConfirm({
action: action,
value: inputValue.value
})
break
case 'cancel':
onCancel &&
onCancel({
action: action
})
break
default:
onCancel &&
onCancel({
action: 'modal'
})
break
}
}
/**
* @description 如果存在校验规则行为,则进行判断校验是否通过规则。默认不存在校验直接铜鼓。
* @return {Boolean} 是否通过校验
*/
function validate() {
if (inputPattern.value && !inputPattern.value.test(String(inputValue.value))) {
showErr.value = true
return false
}
if (typeof inputValidate === 'function') {
const validateResult = inputValidate(inputValue)
if (!validateResult) {
showErr.value = true
return false
}
}
showErr.value = false
return true
}
/**
* @description show关闭时销毁错误提示
* @param val
*/
function resetErr(val) {
if (val === false) {
showErr.value = false
}
}
function inputValChange(value: string | number) {
if (value === '') {
showErr.value = false
return
}
inputValue.value = value
}
/**
* 重置message选项值
* @param option message选项值
*/
function reset(option: MessageOptions) {
if (option) {
title.value = isDef(option.title) ? option.title : title.value
showCancelButton.value = isDef(option.showCancelButton) ? option.showCancelButton : showCancelButton.value
show.value = option.show!
closeOnClickModal.value = option.closeOnClickModal!
confirmButtonText.value = option.confirmButtonText!
cancelButtonText.value = option.cancelButtonText!
msg.value = option.msg!
type.value = option.type!
inputType.value = option.inputType!
inputValue.value = option.inputValue!
inputPlaceholder.value = option.inputPlaceholder!
inputPattern.value = option.inputPattern!
inputValidate = option.inputValidate!
onConfirm = (option as any).onConfirm
onCancel = (option as any).onCancel
inputError.value = option.inputError!
showErr.value = option.showErr!
zIndex.value = option.zIndex!
lazyRender.value = option.lazyRender!
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>