货无忧
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.
 
 
 
 
 

264 lines
6.4 KiB

<!--
* @Author: 刘湘
* @Date: 2021-05-25 16:34:27
* @LastEditTime: 2023-06-06 22:30:16
* @LastEditors: weisheng
* @Description:
* @FilePath: \fant-mini-plus\src\uni_modules\fant-mini-plus\components\hd-toast\hd-toast.vue
* 记得注释
-->
<template>
<hd-transition :show="innerData.visible" :customStyle="`z-index:${innerData.zIndex};position:fixed;`" @after-leave="afterLeave">
<view @click="click" :class="['hd-toast', `hd-toast-${innerData.type}`, `hd-toast--${size}`]" :style="rootStyle">
<image class="img" v-if="innerData.image" :src="innerData.image"></image>
<view :class="['icon', `icon-${innerData.icon}`]" v-else-if="iconName">
<hd-icon :size="size === 'normal' ? '76rpx' : '44rpx'" color="#FFFFFF" :name="iconName"></hd-icon>
</view>
<view class="title">
<mp-html :content="innerData.title" />
</view>
</view>
</hd-transition>
</template>
<script setup lang="ts">
import { computed, ref, watch, inject } from 'vue'
import { CommonUtil, defaultToastOptions, RegUtil, toastDefaultKey, toastDefaultOptionKey } from '../..'
import { ToastOptions } from './types'
interface Props {
// toast是否展示
visible?: boolean
/**
* toast展示时长(ms),值为 0 时,toast 不会消失,默认值1500
*/
duration?: number
/**
* toast提示的内容
*/
title?: string
/**
* toast底色类型
*/
type?: 'white' | 'black'
/**
* toast图标
* - success: 显示成功图标
* - warning: 显示警告图标
* - error: 显示错误图标
* - none: 不显示图标
*/
icon?: 'success' | 'warning' | 'error' | 'none'
// toast自定义图片
image?: string
// 自定义层级,默认值 1000
zIndex?: number
// toast唯一标识
id?: string
}
let props = withDefaults(defineProps<Props>(), {
visible: false,
duration: 1500,
title: '',
type: 'black',
icon: 'none',
image: '',
zIndex: 1000,
id: ''
})
let innerData = ref<Props>({
visible: false,
duration: 1500,
title: '',
type: 'black',
icon: 'none',
image: '',
zIndex: 1000
})
const emit = defineEmits(['update:visible', 'click'])
const toastKey = props.id ? '__TOAST__' + props.id : toastDefaultKey
const toastOptionKey = props.id ? '__TOAST_OPTION__' + props.id : toastDefaultOptionKey
const toastShow = inject(toastKey) || ref<boolean>(false) // 是否展示toast组件
const toastOption = inject(toastOptionKey) || ref<ToastOptions>(defaultToastOptions) // toast选项
// 监听options变化展示
watch(
() => toastOption.value,
(newVal: ToastOptions) => {
reset(newVal)
}
)
// 监听是否visible
watch([() => props.visible, () => toastShow.value], () => {
if (props.visible || toastShow.value) {
show()
} else {
hide()
}
})
/**
* 根节点样式
*/
const rootStyle = computed(() => {
const style: Record<string, string | number> = {
padding: innerData.value.image || iconName.value ? `${uni.upx2px(52)}px ${uni.upx2px(24)}px ` : `${uni.upx2px(32)}px ${uni.upx2px(24)}px `,
'z-index': props.zIndex
}
return CommonUtil.style(style)
})
/**
* toast大小
*/
let size = computed(() => {
if (innerData.value.title && innerData.value.title.length > 8) {
return 'large'
} else {
return 'normal'
}
})
// 图标名称
let iconName = computed(() => {
if (innerData.value.icon === 'success') {
return size.value && size.value === 'large' ? 'ic_toastcheck_fill' : 'ic_tosatcheck_line'
} else if (innerData.value.icon === 'warning') {
return size.value && size.value === 'large' ? 'ic_toastwarn_fill' : 'ic_tosatwarn_line'
} else if (innerData.value.icon === 'error') {
return size.value && size.value === 'large' ? 'ic_toasterror_fill' : 'ic_tosaterror_line'
}
return null
})
// 定时器
let timer = ref<any>(null)
// 打开
function show() {
timer.value && clearTimeout(timer.value)
innerData.value.visible = true
/**
* 消息展示状态变更时触发
* @arg value:Boolean 消息展示状态,建议通过v-model双向绑定输入值,而不是监听此事件的形式
*/
emit('update:visible', true)
if (innerData.value.duration && innerData.value.duration !== Infinity) {
timer.value = setTimeout(() => {
clearTimeout(timer.value)
hide()
}, innerData.value.duration)
}
}
// 关闭
function hide() {
if (innerData.value.visible) {
emit('update:visible', false)
innerData.value.visible = false
toastShow.value = false
timer.value && clearTimeout(timer.value)
}
}
/**
* 重置toast选项值
* @param option toast选项值
*/
function reset(option: ToastOptions) {
if (option) {
innerData.value = {
visible: false,
duration: RegUtil.isDef(option.duration) ? option.duration! : props.duration,
title: RegUtil.isDef(option.title) ? option.title! : props.title,
type: RegUtil.isDef(option.type) ? option.type! : props.type,
icon: RegUtil.isDef(option.icon) ? option.icon! : props.icon,
image: RegUtil.isDef(option.image) ? option.image! : props.image,
zIndex: RegUtil.isDef(option.zIndex) ? option.zIndex! : props.zIndex
}
}
}
// 被点击
function click() {
emit('click')
}
// 动画结束
function afterLeave() {
reset(defaultToastOptions)
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/index.scss';
$types: success, warning, error;
.hd-toast {
position: fixed;
z-index: 10001;
display: inline-block;
width: 240rpx;
box-sizing: border-box;
padding: 52rpx 24rpx;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
border-radius: 16rpx;
.icon,
.img {
display: flex;
align-items: center;
justify-content: center;
position: relative;
left: 50%;
transform: translateX(-50%);
height: 76rpx;
width: 76rpx;
margin-bottom: 24rpx;
}
.title {
line-height: 36rpx;
text-align: center;
font-size: 26rpx;
max-height: 70vh;
overflow: auto;
}
&--large {
padding: 40rpx 24rpx;
width: 420rpx;
// min-height: 192rpx;
.icon,
.img,
image {
height: 44rpx;
width: 44rpx;
margin-bottom: 32rpx;
}
}
&-black {
color: $color-white;
background-color: $color-text-primary;
}
&-white {
color: $color-text-secondary;
background-color: $color-white;
border: 1rpx solid #e5e5e5;
@each $type in $types {
.icon-#{$type} {
::v-deep text {
color: map-get($var-map, $type) !important;
}
}
}
}
}
</style>