292 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
		
		
			
		
	
	
			292 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Vue
		
	
	
	
|  | <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> |