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

245 lines
6.8 KiB

<template>
<view class="hd-modal" v-if="visiable">
<hd-transition key="1" name="fade" :customStyle="maskStyle" :duration="duration" :show="showTrans" />
<hd-transition key="2" name="zoom-in" :customStyle="transStyle" :duration="duration" :show="showTrans">
<view class="hd-modal-main" @touchmove.stop.prevent="">
<view class="modal">
<!-- 标题 -->
<slot name="title">
<view class="modal-title" v-show="title">{{ title }}</view>
</slot>
<!-- 内容区 -->
<slot name="content">
<view :class="{ 'modal-content': true, 'modal-content--notitle': !title }">
<mp-html :content="content" />
</view>
</slot>
<!-- 操作按钮 -->
<slot name="operation" @click.stop.prevent>
<view class="modal-footer">
<view class="modal-footer-operation" v-if="showCancel" :style="{ color: cancelColor }" @click="clickBtn('cancel')">
{{ cancelText }}
</view>
<view class="modal-footer-operation" :style="{ color: confirmColor }" @click="clickBtn('confirm')">{{ confirmText }}</view>
</view>
</slot>
</view>
</view>
</hd-transition>
</view>
</template>
<script lang="ts" setup>
import { ref, computed, nextTick, inject, watch } from 'vue'
import { RegUtil, CommonUtil, defaultModalOptions, modalDefaultKey, modalDefaultOptionKey } from '../../index'
import { ModalOptions } from './types'
interface Props {
// Modal唯一标识
id?: string
}
const props = withDefaults(defineProps<Props>(), {
id: ''
})
const visiable = ref<boolean>(false) // 是否展示modal
const showTrans = ref<boolean>(false) // 是否展示过渡动画
const duration = ref<number>(200) // 动画时间
const title = ref<string>('提示') // 提示文字
const content = ref<string>('') // 弹出框内容
const showCancel = ref<boolean>(true) // 是否展示取消按钮
const cancelText = ref<string>('取消') // 取消按钮文字
const cancelColor = ref<string>('282C34') // 取消按钮颜色
const confirmText = ref<string>('确定') // 确定按钮文字
const confirmColor = ref<string>('1C64FD') // 确定按钮的颜色
// eslint-disable-next-line @typescript-eslint/ban-types
const success = ref<Function | null>(null) // 成功的回调
const modalKey = props.id ? '__MODAL__' + props.id : modalDefaultKey
const modalOptionKey = props.id ? '__MODAL_OPTION__' + props.id : modalDefaultOptionKey
const modalShow = inject(modalKey) || ref<boolean>(false) // 函数式调用是否展示modal组件
const modalOption = inject(modalOptionKey) || ref<ModalOptions>(defaultModalOptions) // modal选项
// 监听options变化展示
watch(
() => modalOption.value,
(newVal: ModalOptions) => {
reset(newVal)
}
)
// 监听函数式调用showModal的调用
watch(
() => modalShow.value,
(newVal) => {
if (newVal) {
show()
}
}
)
// 遮罩样式
const maskStyle = computed(() => {
const styles = {
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)'
}
return CommonUtil.style(styles)
})
// 内容样式
const transStyle = computed(() => {
const styles = {
position: 'fixed',
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column',
/* #endif */
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center'
}
return CommonUtil.style(styles)
})
// 打开
function show() {
visiable.value = true
nextTick(() => {
showTrans.value = true
})
}
// 关闭
function hide() {
showTrans.value = false
const timer = setTimeout(() => {
clearTimeout(timer)
visiable.value = false
modalShow.value = false
reset({
title: '提示',
content: '',
showCancel: true,
cancelText: '取消',
cancelColor: '#282C34',
confirmText: '确定',
confirmColor: '#1C64FD',
success: null
})
}, duration.value)
}
/**
* 重置参数
*/
function reset(option) {
if (option) {
title.value = RegUtil.isDef(option.title) ? option.title : title.value
content.value = RegUtil.isDef(option.content) ? option.content : content.value
showCancel.value = RegUtil.isDef(option.showCancel) ? option.showCancel : showCancel.value
cancelText.value = RegUtil.isDef(option.cancelText) ? option.cancelText : cancelText.value
cancelColor.value = RegUtil.isDef(option.cancelColor) ? option.cancelColor : cancelColor.value
confirmText.value = RegUtil.isDef(option.confirmText) ? option.confirmText : cancelText.value
confirmColor.value = RegUtil.isDef(option.confirmColor) ? option.confirmColor : confirmColor.value
success.value = RegUtil.isDef(option.success) ? option.success : success.value
}
}
function clickBtn(res) {
hide()
if (success.value) {
const resObj = {
cancel: false,
confirm: false
}
res == 'confirm' ? (resObj.confirm = true) : (resObj.cancel = true)
nextTick(() => {
success.value && success.value(resObj)
})
}
}
</script>
<style lang="scss">
.hd-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 10000;
&-main {
width: 100%;
height: 100%;
position: relative;
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
.modal {
flex: none;
width: 70%;
// min-height:200upx;
background: #fff;
border-radius: 10upx;
box-sizing: border-box;
padding-top: 44rpx;
&-title {
color: #282c34;
height: 52rpx;
text-align: center;
font-weight: 500;
font-size: 36rpx;
font-family: PingFangSC-Medium, PingFang SC;
color: $color-text-primary;
line-height: 52rpx;
}
&-content {
max-height: 60vh;
overflow-y: auto;
word-wrap: break-word;
overflow-x: hidden;
padding: 16rpx 40rpx 32rpx 40rpx;
text-align: center;
font-size: 30rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: $color-text-thirdly;
line-height: 44rpx;
}
&--notitle {
padding-top: 0;
font-size: 36rpx;
color: $color-text-primary;
line-height: 52rpx;
}
&-footer {
display: flex;
&-operation {
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 50%;
font-size: 36rpx;
text-align: center;
flex: auto;
height: 100rpx;
color: $color-text-thirdly;
border-top: 1rpx solid #e5e5e5;
border-right: 1rpx solid #e5e5e5;
&:last-child {
border-right: none;
}
}
}
}
}
}
</style>