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.

155 lines
4.5 KiB
Vue

<template>
<wd-transition name="fade" :show="show" :custom-style="transitionStyle">
<view :class="rootClass">
<!--iconName优先级更高-->
<wd-loading v-if="iconName === 'loading'" :type="loadingType" :color="loadingColor" custom-class="wd-toast__icon" :customStyle="loadingStyle" />
<view
class="wd-toast__iconWrap wd-toast__icon"
v-else-if="iconName === 'success' || iconName === 'warning' || iconName === 'info' || iconName === 'error'"
:style="`width:${iconSize}px; height:${iconSize}px`"
>
<view class="wd-toast__iconBox">
<view class="wd-toast__iconSvg" :style="`background-image: url(${svgStr}); width:${iconSize}px; height:${iconSize}px`"></view>
</view>
</view>
<view v-else-if="customIcon" class="wd-toast__icon custom-icon-class" />
<!--文本-->
<view v-if="msg" class="wd-toast__msg">{{ msg }}</view>
</view>
</wd-transition>
</template>
<script lang="ts">
export default {
name: 'wd-toast',
options: {
addGlobalClass: true,
virtualHost: true,
styleIsolation: 'shared'
}
}
</script>
<script lang="ts" setup>
import { computed, inject, onBeforeMount, ref, watch } from 'vue'
import base64 from '../common/base64'
import { defaultOptions, toastDefaultOptionKey, toastIcon } from '.'
import type { ToastLoadingType, ToastOptions } from './type'
import { isDef, objToStyle } from '../common/util'
interface Props {
customIconClass?: string
customClass?: string
selector?: string
}
const props = withDefaults(defineProps<Props>(), {
customIconClass: '',
customClass: '',
selector: ''
})
const iconName = ref<string>('') // 图标类型
const customIcon = ref<boolean>(false)
const msg = ref<string>('') // 消息内容
const position = ref<string>('middle')
const show = ref<boolean>(false)
const zIndex = ref<number>(100)
const loadingType = ref<ToastLoadingType>('outline')
const loadingColor = ref<string>('#4D80F0')
const iconSize = ref<number>(42)
const svgStr = ref<string>('') // 图标
const toastOptionKey = props.selector ? toastDefaultOptionKey + props.selector : toastDefaultOptionKey
const toastOption = inject(toastOptionKey, ref<ToastOptions>(defaultOptions)) // toast选项
// 监听options变化展示
watch(
() => toastOption.value,
(newVal: ToastOptions) => {
reset(newVal)
},
{
deep: true,
immediate: true
}
)
// 监听options变化展示
watch(
() => iconName.value,
() => {
buildSvg()
},
{
deep: true,
immediate: true
}
)
/**
* 动画自定义样式
*/
const transitionStyle = computed(() => {
const style: Record<string, string | number> = {
'z-index': zIndex.value,
position: 'fixed',
top: '50%',
left: 0,
width: '100%',
transform: 'translate(0, -50%)',
'text-align': 'center'
}
return objToStyle(style)
})
/**
* 加载自定义样式
*/
const loadingStyle = computed(() => {
const style: Record<string, string | number> = {
display: 'inline-block',
'margin-right': '16px'
}
return objToStyle(style)
})
const rootClass = computed(() => {
return `wd-toast ${props.customClass} wd-toast--${position.value} ${
(iconName.value !== 'loading' || msg.value) && (iconName.value || customIcon.value) ? 'wd-toast--with-icon' : ''
} ${iconName.value === 'loading' && !msg.value ? 'wd-toast--loading' : ''}`
})
onBeforeMount(() => {
buildSvg()
})
function buildSvg() {
if (iconName.value !== 'success' && iconName.value !== 'warning' && iconName.value !== 'info' && iconName.value !== 'error') return
const iconSvg = toastIcon[iconName.value]()
const iconSvgStr = `"data:image/svg+xml;base64,${base64(iconSvg)}"`
svgStr.value = iconSvgStr
}
/**
* 重置toast选项值
* @param option toast选项值
*/
function reset(option: ToastOptions) {
if (option) {
iconName.value = isDef(option.iconName!) ? option.iconName! : iconName.value
customIcon.value = isDef(option.customIcon!) ? option.customIcon! : customIcon.value
msg.value = isDef(option.msg!) ? option.msg! : msg.value
position.value = isDef(option.position!) ? option.position! : position.value
show.value = isDef(option.show!) ? option.show! : show.value
zIndex.value = isDef(option.zIndex!) ? option.zIndex! : zIndex.value
loadingType.value = isDef(option.loadingType!) ? option.loadingType! : loadingType.value
loadingColor.value = isDef(option.loadingColor!) ? option.loadingColor! : loadingColor.value
iconSize.value = isDef(option.iconSize!) ? option.iconSize! : iconSize.value
}
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>