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.

292 lines
9.3 KiB

7 months ago
<template>
<view class="u-toast">
<u-overlay
:show="isShow"
:custom-style="overlayStyle"
>
<view
class="u-toast__content"
:style="[contentStyle]"
:class="['u-type-' + tmpConfig.type, (tmpConfig.type === 'loading' || tmpConfig.loading) ? 'u-toast__content--loading' : '']"
>
<u-loading-icon
v-if="tmpConfig.type === 'loading'"
mode="circle"
color="rgb(255, 255, 255)"
inactiveColor="rgb(120, 120, 120)"
size="25"
></u-loading-icon>
<u-icon
v-else-if="tmpConfig.type !== 'defalut' && iconName"
:name="iconName"
size="17"
:color="tmpConfig.type"
:customStyle="iconStyle"
></u-icon>
<u-gap
v-if="tmpConfig.type === 'loading' || tmpConfig.loading"
height="12"
bgColor="transparent"
></u-gap>
<text
class="u-toast__content__text"
:class="['u-toast__content__text--' + tmpConfig.type]"
style="max-width: 400rpx;"
>{{ tmpConfig.message }}</text>
</view>
</u-overlay>
</view>
</template>
<script>
/**
* toast 消息提示
* @description 此组件表现形式类似uni的uni.showToastAPI但也有不同的地方
* @tutorial https://www.uviewui.com/components/toast.html
* @property {String | Number} zIndex toast展示时的zIndex值 (默认 10090 )
* @property {Boolean} loading 是否加载中 默认 false
* @property {String | Number} message 显示的文字内容
* @property {String} icon 图标或者绝对路径的图片
* @property {String} type 主题类型 默认 default
* @property {Boolean} show 是否显示该组件 默认 false
* @property {Boolean} overlay 是否显示透明遮罩防止点击穿透 默认 false
* @property {String} position 位置 默认 'center'
* @property {Object} params 跳转的参数
* @property {String | Number} duration 展示时间单位ms 默认 2000
* @property {Boolean} isTab 是否返回的为tab页面 默认 false
* @property {String} url toast消失后是否跳转页面有则跳转优先级高于back参数
* @property {Function} complete 执行完后的回调函数
* @property {Boolean} back 结束toast是否自动返回上一页 默认 false
* @property {Object} customStyle 组件的样式对象形式
* @event {Function} show 显示toast如需一进入页面就显示toast请在onReady生命周期调用
* @example <u-toast ref="uToast" />
*/
export default {
name: 'u-toast',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
data() {
return {
isShow: false,
timer: null, // 定时器
config: {
message: '', // 显示文本
type: '', // 主题类型,primary,success,error,warning,black
duration: 2000, // 显示的时间,毫秒
icon: true, // 显示的图标
position: 'center', // toast出现的位置
complete: null, // 执行完后的回调函数
overlay: false, // 是否防止触摸穿透
loading: false, // 是否加载中状态
},
tmpConfig: {}, // 将用户配置和内置配置合并后的临时配置变量
}
},
computed: {
iconName() {
// 只有不为none,并且type为error|warning|succes|info时候,才显示图标
if(!this.tmpConfig.icon || this.tmpConfig.icon == 'none') {
return '';
}
if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
return uni.$u.type2icon(this.tmpConfig.type)
} else {
return ''
}
},
overlayStyle() {
const style = {
justifyContent: 'center',
alignItems: 'center',
display: 'flex'
}
// 将遮罩设置为100%透明度,避免出现灰色背景
style.backgroundColor = 'rgba(0, 0, 0, 0)'
return style
},
iconStyle() {
const style = {}
// 图标需要一个右边距,以跟右边的文字有隔开的距离
style.marginRight = '4px'
// #ifdef APP-NVUE
// iOSAPP下,图标有1px的向下偏移,这里进行修正
if (uni.$u.os() === 'ios') {
style.marginTop = '-1px'
}
// #endif
return style
},
loadingIconColor() {
let color = 'rgb(255, 255, 255)'
if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
// loading-icon组件内部会对color参数进行一个透明度处理,该方法要求传入的颜色值
// 必须为rgb格式的,所以这里做一个处理
color = uni.$u.hexToRgb(uni.$u.color[this.tmpConfig.type])
}
return color
},
// 内容盒子的样式
contentStyle() {
const windowHeight = uni.$u.sys().windowHeight, style = {}
let value = 0
// 根据top和bottom,对Y轴进行窗体高度的百分比偏移
if(this.tmpConfig.position === 'top') {
value = - windowHeight * 0.25
} else if(this.tmpConfig.position === 'bottom') {
value = windowHeight * 0.25
}
style.transform = `translateY(${value}px)`
return style
}
},
created() {
// 通过主题的形式调用toast,批量生成方法函数
['primary', 'success', 'error', 'warning', 'default', 'loading'].map(item => {
this[item] = message => this.show({
type: item,
message
})
})
},
methods: {
// 显示toast组件,由父组件通过this.$refs.xxx.show(options)形式调用
show(options) {
// 不将结果合并到this.config变量,避免多次调用u-toast,前后的配置造成混乱
this.tmpConfig = uni.$u.deepMerge(this.config, options)
// 清除定时器
this.clearTimer()
this.isShow = true
this.timer = setTimeout(() => {
// 倒计时结束,清除定时器,隐藏toast组件
this.clearTimer()
// 判断是否存在callback方法,如果存在就执行
typeof(this.tmpConfig.complete) === 'function' && this.tmpConfig.complete()
}, this.tmpConfig.duration)
},
// 隐藏toast组件,由父组件通过this.$refs.xxx.hide()形式调用
hide() {
this.clearTimer()
},
clearTimer() {
this.isShow = false
// 清除定时器
clearTimeout(this.timer)
this.timer = null
}
},
beforeDestroy() {
this.clearTimer()
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-toast-color:#fff !default;
$u-toast-border-radius:4px !default;
$u-toast-border-background-color:#585858 !default;
$u-toast-border-font-size:14px !default;
$u-toast-border-padding:12px 20px !default;
$u-toast-loading-border-padding: 20px 20px !default;
$u-toast-content-text-color:#fff !default;
$u-toast-content-text-font-size:15px !default;
$u-toast-u-icon:10rpx !default;
$u-toast-u-type-primary-color:$u-primary !default;
$u-toast-u-type-primary-background-color:#ecf5ff !default;
$u-toast-u-type-primary-border-color:rgb(215, 234, 254) !default;
$u-toast-u-type-primary-border-width:1px !default;
$u-toast-u-type-success-color: $u-success !default;
$u-toast-u-type-success-background-color: #dbf1e1 !default;
$u-toast-u-type-success-border-color: #BEF5C8 !default;
$u-toast-u-type-success-border-width: 1px !default;
$u-toast-u-type-error-color:$u-error !default;
$u-toast-u-type-error-background-color:#fef0f0 !default;
$u-toast-u-type-error-border-color:#fde2e2 !default;
$u-toast-u-type-error-border-width: 1px !default;
$u-toast-u-type-warning-color:$u-warning !default;
$u-toast-u-type-warning-background-color:#fdf6ec !default;
$u-toast-u-type-warning-border-color:#faecd8 !default;
$u-toast-u-type-warning-border-width: 1px !default;
$u-toast-u-type-default-color:#fff !default;
$u-toast-u-type-default-background-color:#585858 !default;
.u-toast {
&__content {
@include flex;
padding: $u-toast-border-padding;
border-radius: $u-toast-border-radius;
background-color: $u-toast-border-background-color;
color: $u-toast-color;
align-items: center;
/* #ifndef APP-NVUE */
max-width: 600rpx;
/* #endif */
position: relative;
&--loading {
flex-direction: column;
padding: $u-toast-loading-border-padding;
}
&__text {
color: $u-toast-content-text-color;
font-size: $u-toast-content-text-font-size;
line-height: $u-toast-content-text-font-size;
&--default {
color: $u-toast-content-text-color;
}
&--error {
color: $u-error;
}
&--primary {
color: $u-primary;
}
&--success {
color: $u-success;
}
&--warning {
color: $u-warning;
}
}
}
}
.u-type-primary {
color: $u-toast-u-type-primary-color;
background-color: $u-toast-u-type-primary-background-color;
border-color: $u-toast-u-type-primary-border-color;
border-width: $u-toast-u-type-primary-border-width;
}
.u-type-success {
color: $u-toast-u-type-success-color;
background-color: $u-toast-u-type-success-background-color;
border-color: $u-toast-u-type-success-border-color;
border-width: 1px;
}
.u-type-error {
color: $u-toast-u-type-error-color;
background-color: $u-toast-u-type-error-background-color;
border-color: $u-toast-u-type-error-border-color;
border-width: $u-toast-u-type-error-border-width;
}
.u-type-warning {
color: $u-toast-u-type-warning-color;
background-color: $u-toast-u-type-warning-background-color;
border-color: $u-toast-u-type-warning-border-color;
border-width: 1px;
}
.u-type-default {
color: $u-toast-u-type-default-color;
background-color: $u-toast-u-type-default-background-color;
}
</style>