u-notify.vue 5.86 KB
Newer Older
潘永坪's avatar
潘永坪 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
<template>
	<u-transition
		mode="slide-down"
		:customStyle="containerStyle"
		:show="open"
	>
		<view
			class="u-notify"
			:class="[`u-notify--${tmpConfig.type}`]"
			:style="[backgroundColor, $u.addStyle(customStyle)]"
		>
			<u-status-bar v-if="tmpConfig.safeAreaInsetTop"></u-status-bar>
			<view class="u-notify__warpper">
				<slot name="icon">
					<u-icon
						v-if="['success', 'warning', 'error'].includes(tmpConfig.type)"
						:name="tmpConfig.icon"
						:color="tmpConfig.color"
						:size="1.3 * tmpConfig.fontSize"
						:customStyle="{marginRight: '4px'}"
					></u-icon>
				</slot>
				<text
					class="u-notify__warpper__text"
					:style="{
						fontSize: $u.addUnit(tmpConfig.fontSize),
						color: tmpConfig.color
					}"
				>{{ tmpConfig.message }}</text>
			</view>
		</view>
	</u-transition>
</template>

<script>
	import props from './props.js';
	/**
	 * notify 顶部提示
	 * @description 该组件一般用于页面顶部向下滑出一个提示,尔后自动收起的场景
	 * @tutorial
	 * @property {String | Number}	top					到顶部的距离 ( 默认 0 )
	 * @property {String}			type				主题,primary,success,warning,error ( 默认 'primary' )
	 * @property {String}			color				字体颜色 ( 默认 '#ffffff' )
	 * @property {String}			bgColor				背景颜色
	 * @property {String}			message				展示的文字内容
	 * @property {String | Number}	duration			展示时长,为0时不消失,单位ms ( 默认 3000 )
	 * @property {String | Number}	fontSize			字体大小 ( 默认 15 )
	 * @property {Boolean}			safeAreaInsetTop	是否留出顶部安全距离(状态栏高度) ( 默认 false )
	 * @property {Object}			customStyle			组件的样式,对象形式
	 * @event {Function}	open	开启组件时调用的函数
	 * @event {Function}	close	关闭组件式调用的函数
	 * @example <u-notify message="Hi uView"></u-notify>
	 */
	export default {
		name: 'u-notify',
		mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
		data() {
			return {
				// 是否展示组件
				open: false,
				timer: null,
				config: {
					// 到顶部的距离
					top: uni.$u.props.notify.top,
					// type主题,primary,success,warning,error
					type: uni.$u.props.notify.type,
					// 字体颜色
					color: uni.$u.props.notify.color,
					// 背景颜色
					bgColor: uni.$u.props.notify.bgColor,
					// 展示的文字内容
					message: uni.$u.props.notify.message,
					// 展示时长,为0时不消失,单位ms
					duration: uni.$u.props.notify.duration,
					// 字体大小
					fontSize: uni.$u.props.notify.fontSize,
					// 是否留出顶部安全距离(状态栏高度)
					safeAreaInsetTop: uni.$u.props.notify.safeAreaInsetTop
				},
				// 合并后的配置,避免多次调用组件后,可能会复用之前使用的配置参数
				tmpConfig: {}
			}
		},
		computed: {
			containerStyle() {
				let top = 0
				if (this.tmpConfig.top === 0) {
					// #ifdef H5
					// H5端,导航栏为普通元素,需要将组件移动到导航栏的下边沿
					// H5的导航栏高度为44px
					top = 44
					// #endif
				}
				const style = {
					top: uni.$u.addUnit(this.tmpConfig.top === 0 ? top : this.tmpConfig.top),
					// 因为组件底层为u-transition组件,必须将其设置为fixed定位
					// 让其出现在导航栏底部
					position: 'fixed',
					left: 0,
					right: 0,
					zIndex: 10076
				}
				return style
			},
			// 组件背景颜色
			backgroundColor() {
				const style = {}
				if (this.tmpConfig.bgColor) {
					style.backgroundColor = this.tmpConfig.bgColor
				}
				return style
			},
			// 默认主题下的图标
			icon() {
				let icon
				if (this.tmpConfig.type === 'success') {
					icon = 'checkmark-circle'
				} else if (this.tmpConfig.type === 'error') {
					icon = 'close-circle'
				} else if (this.tmpConfig.type === 'warning') {
					icon = 'error-circle'
				}
				return icon
			}
		},
		created() {
			// 通过主题的形式调用toast,批量生成方法函数
			['primary', 'success', 'error', 'warning'].map(item => {
				this[item] = message => this.show({
					type: item,
					message
				})
			})
		},
		methods: {
			show(options) {
				// 不将结果合并到this.config变量,避免多次调用u-toast,前后的配置造成混乱
				this.tmpConfig = uni.$u.deepMerge(this.config, options)
				// 任何定时器初始化之前,都要执行清除操作,否则可能会造成混乱
				this.clearTimer()
				this.open = true
				if (this.tmpConfig.duration > 0) {
					this.timer = setTimeout(() => {
						this.open = false
						// 倒计时结束,清除定时器,隐藏toast组件
						this.clearTimer()
						// 判断是否存在callback方法,如果存在就执行
						typeof(this.tmpConfig.complete) === 'function' && this.tmpConfig.complete()
					}, this.tmpConfig.duration)
				}
			},
			// 关闭notify
			close() {
				this.clearTimer()
			},
			clearTimer() {
				this.open = false
				// 清除定时器
				clearTimeout(this.timer)
				this.timer = null
			}
		},
		beforeDestroy() {
			this.clearTimer()
		}
	}
</script>

<style lang="scss" scoped>
	@import "../../libs/css/components.scss";

	$u-notify-padding: 8px 10px !default;
	$u-notify-text-font-size: 15px !default;
	$u-notify-primary-bgColor: $u-primary !default;
	$u-notify-success-bgColor: $u-success !default;
	$u-notify-error-bgColor: $u-error !default;
	$u-notify-warning-bgColor: $u-warning !default;


	.u-notify {
		padding: $u-notify-padding;

		&__warpper {
			@include flex;
			align-items: center;
			text-align: center;
			justify-content: center;

			&__text {
				font-size: $u-notify-text-font-size;
				text-align: center;
			}
		}

		&--primary {
			background-color: $u-notify-primary-bgColor;
		}

		&--success {
			background-color: $u-notify-success-bgColor;
		}

		&--error {
			background-color: $u-notify-error-bgColor;
		}

		&--warning {
			background-color: $u-notify-warning-bgColor;
		}
	}
</style>