zhangmeng
2024-04-19 e3ba120cb766a17e098e58d11c39ffc600a3070c
commit | author | age
e3ba12 1 <template>
Z 2     <view class="u-toast">
3         <u-overlay
4             :show="isShow"
5             :custom-style="overlayStyle"
6         >
7             <view
8                 class="u-toast__content"
9                 :style="[contentStyle]"
10                 :class="['u-type-' + tmpConfig.type, (tmpConfig.type === 'loading' || tmpConfig.loading) ?  'u-toast__content--loading' : '']"
11             >
12                 <u-loading-icon
13                     v-if="tmpConfig.type === 'loading'"
14                     mode="circle"
15                     color="rgb(255, 255, 255)"
16                     inactiveColor="rgb(120, 120, 120)"
17                     size="25"
18                 ></u-loading-icon>
19                 <u-icon
20                     v-else-if="tmpConfig.type !== 'defalut' && iconName"
21                     :name="iconName"
22                     size="17"
23                     :color="tmpConfig.type"
24                     :customStyle="iconStyle"
25                 ></u-icon>
26                 <u-gap
27                     v-if="tmpConfig.type === 'loading' || tmpConfig.loading"
28                     height="12"
29                     bgColor="transparent"
30                 ></u-gap>
31                 <text
32                     class="u-toast__content__text"
33                     :class="['u-toast__content__text--' + tmpConfig.type]"
34                     style="max-width: 400rpx;"
35                 >{{ tmpConfig.message }}</text>
36             </view>
37         </u-overlay>
38     </view>
39 </template>
40
41 <script>
42     /**
43      * toast 消息提示
44      * @description 此组件表现形式类似uni的uni.showToastAPI,但也有不同的地方。
45      * @tutorial https://www.uviewui.com/components/toast.html
46      * @property {String | Number}    zIndex        toast展示时的zIndex值 (默认 10090 )
47      * @property {Boolean}            loading        是否加载中 (默认 false )
48      * @property {String | Number}    message        显示的文字内容
49      * @property {String}            icon        图标,或者绝对路径的图片
50      * @property {String}            type        主题类型 (默认 default)
51      * @property {Boolean}            show        是否显示该组件 (默认 false)
52      * @property {Boolean}            overlay        是否显示透明遮罩,防止点击穿透 (默认 false )
53      * @property {String}            position    位置 (默认 'center' )
54      * @property {Object}            params        跳转的参数 
55      * @property {String | Number}  duration    展示时间,单位ms (默认 2000 )
56      * @property {Boolean}            isTab        是否返回的为tab页面 (默认 false )
57      * @property {String}            url            toast消失后是否跳转页面,有则跳转,优先级高于back参数 
58      * @property {Function}            complete    执行完后的回调函数 
59      * @property {Boolean}            back        结束toast是否自动返回上一页 (默认 false )
60      * @property {Object}            customStyle    组件的样式,对象形式
61      * @event {Function} show 显示toast,如需一进入页面就显示toast,请在onReady生命周期调用
62      * @example <u-toast ref="uToast" />
63      */
64     export default {
65         name: 'u-toast',
66         mixins: [uni.$u.mpMixin, uni.$u.mixin],
67         data() {
68             return {
69                 isShow: false,
70                 timer: null, // 定时器
71                 config: {
72                     message: '', // 显示文本
73                     type: '', // 主题类型,primary,success,error,warning,black
74                     duration: 2000, // 显示的时间,毫秒
75                     icon: true, // 显示的图标
76                     position: 'center', // toast出现的位置
77                     complete: null, // 执行完后的回调函数
78                     overlay: false, // 是否防止触摸穿透
79                     loading: false, // 是否加载中状态
80                 },
81                 tmpConfig: {}, // 将用户配置和内置配置合并后的临时配置变量
82             }
83         },
84         computed: {
85             iconName() {
86                 // 只有不为none,并且type为error|warning|succes|info时候,才显示图标
87                 if(!this.tmpConfig.icon || this.tmpConfig.icon == 'none') {
88                     return '';
89                 }
90                 if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
91                     return uni.$u.type2icon(this.tmpConfig.type)
92                 } else {
93                     return ''
94                 }
95             },
96             overlayStyle() {
97                 const style = {
98                     justifyContent: 'center',
99                     alignItems: 'center',
100                     display: 'flex'
101                 }
102                 // 将遮罩设置为100%透明度,避免出现灰色背景
103                 style.backgroundColor = 'rgba(0, 0, 0, 0)'
104                 return style
105             },
106             iconStyle() {
107                 const style = {}
108                 // 图标需要一个右边距,以跟右边的文字有隔开的距离
109                 style.marginRight = '4px'
110                 // #ifdef APP-NVUE
111                 // iOSAPP下,图标有1px的向下偏移,这里进行修正
112                 if (uni.$u.os() === 'ios') {
113                     style.marginTop = '-1px'
114                 }
115                 // #endif
116                 return style
117             },
118             loadingIconColor() {
119                 let color = 'rgb(255, 255, 255)'
120                 if (['error', 'warning', 'success', 'primary'].includes(this.tmpConfig.type)) {
121                     // loading-icon组件内部会对color参数进行一个透明度处理,该方法要求传入的颜色值
122                     // 必须为rgb格式的,所以这里做一个处理
123                     color = uni.$u.hexToRgb(uni.$u.color[this.tmpConfig.type])
124                 }
125                 return color
126             },
127             // 内容盒子的样式
128             contentStyle() {
129                 const windowHeight = uni.$u.sys().windowHeight, style = {}
130                 let value = 0
131                 // 根据top和bottom,对Y轴进行窗体高度的百分比偏移
132                 if(this.tmpConfig.position === 'top') {
133                     value = - windowHeight * 0.25
134                 } else if(this.tmpConfig.position === 'bottom') {
135                     value = windowHeight * 0.25
136                 }
137                 style.transform = `translateY(${value}px)`
138                 return style
139             }
140         },
141         created() {
142             // 通过主题的形式调用toast,批量生成方法函数
143             ['primary', 'success', 'error', 'warning', 'default', 'loading'].map(item => {
144                 this[item] = message => this.show({
145                     type: item,
146                     message
147                 })
148             })
149         },
150         methods: {
151             // 显示toast组件,由父组件通过this.$refs.xxx.show(options)形式调用
152             show(options) {
153                 // 不将结果合并到this.config变量,避免多次调用u-toast,前后的配置造成混乱
154                 this.tmpConfig = uni.$u.deepMerge(this.config, options)
155                 // 清除定时器
156                 this.clearTimer()
157                 this.isShow = true
158                 this.timer = setTimeout(() => {
159                     // 倒计时结束,清除定时器,隐藏toast组件
160                     this.clearTimer()
161                     // 判断是否存在callback方法,如果存在就执行
162                     typeof(this.tmpConfig.complete) === 'function' && this.tmpConfig.complete()
163                 }, this.tmpConfig.duration)
164             },
165             // 隐藏toast组件,由父组件通过this.$refs.xxx.hide()形式调用
166             hide() {
167                 this.clearTimer()
168             },
169             clearTimer() {
170                 this.isShow = false
171                 // 清除定时器
172                 clearTimeout(this.timer)
173                 this.timer = null
174             }
175         },
176         beforeDestroy() {
177             this.clearTimer()
178         }
179     }
180 </script>
181
182 <style lang="scss" scoped>
183     @import "../../libs/css/components.scss";
184
185     $u-toast-color:#fff !default;
186     $u-toast-border-radius:4px !default;
187     $u-toast-border-background-color:#585858 !default;
188     $u-toast-border-font-size:14px !default;
189     $u-toast-border-padding:12px 20px !default;
190     $u-toast-loading-border-padding: 20px 20px !default;
191     $u-toast-content-text-color:#fff !default;
192     $u-toast-content-text-font-size:15px !default;
193     $u-toast-u-icon:10rpx !default;
194     $u-toast-u-type-primary-color:$u-primary !default;
195     $u-toast-u-type-primary-background-color:#ecf5ff !default;
196     $u-toast-u-type-primary-border-color:rgb(215, 234, 254) !default;
197     $u-toast-u-type-primary-border-width:1px !default;
198     $u-toast-u-type-success-color: $u-success !default;
199     $u-toast-u-type-success-background-color: #dbf1e1 !default;
200     $u-toast-u-type-success-border-color: #BEF5C8 !default;
201     $u-toast-u-type-success-border-width: 1px !default;
202     $u-toast-u-type-error-color:$u-error !default;
203     $u-toast-u-type-error-background-color:#fef0f0 !default;
204     $u-toast-u-type-error-border-color:#fde2e2 !default;
205     $u-toast-u-type-error-border-width: 1px !default;
206     $u-toast-u-type-warning-color:$u-warning !default;
207     $u-toast-u-type-warning-background-color:#fdf6ec !default;
208     $u-toast-u-type-warning-border-color:#faecd8 !default;
209     $u-toast-u-type-warning-border-width: 1px !default;
210     $u-toast-u-type-default-color:#fff !default;
211     $u-toast-u-type-default-background-color:#585858 !default;
212
213     .u-toast {
214         &__content {
215             @include flex;
216             padding: $u-toast-border-padding;
217             border-radius: $u-toast-border-radius;
218             background-color: $u-toast-border-background-color;
219             color: $u-toast-color;
220             align-items: center;
221             /* #ifndef APP-NVUE */
222             max-width: 600rpx;
223             /* #endif */
224             position: relative;
225
226             &--loading {
227                 flex-direction: column;
228                 padding: $u-toast-loading-border-padding;
229             }
230
231             &__text {
232                 color: $u-toast-content-text-color;
233                 font-size: $u-toast-content-text-font-size;
234                 line-height: $u-toast-content-text-font-size;
235
236                 &--default {
237                     color: $u-toast-content-text-color;
238                 }
239
240                 &--error {
241                     color: $u-error;
242                 }
243
244                 &--primary {
245                     color: $u-primary;
246                 }
247
248                 &--success {
249                     color: $u-success;
250                 }
251
252                 &--warning {
253                     color: $u-warning;
254                 }
255             }
256         }
257     }
258
259     .u-type-primary {
260         color: $u-toast-u-type-primary-color;
261         background-color: $u-toast-u-type-primary-background-color;
262         border-color: $u-toast-u-type-primary-border-color;
263         border-width: $u-toast-u-type-primary-border-width;
264     }
265
266     .u-type-success {
267         color: $u-toast-u-type-success-color;
268         background-color: $u-toast-u-type-success-background-color;
269         border-color: $u-toast-u-type-success-border-color;
270         border-width: 1px;
271     }
272
273     .u-type-error {
274         color: $u-toast-u-type-error-color;
275         background-color: $u-toast-u-type-error-background-color;
276         border-color: $u-toast-u-type-error-border-color;
277         border-width: $u-toast-u-type-error-border-width;
278     }
279
280     .u-type-warning {
281         color: $u-toast-u-type-warning-color;
282         background-color: $u-toast-u-type-warning-background-color;
283         border-color: $u-toast-u-type-warning-border-color;
284         border-width: 1px;
285     }
286
287     .u-type-default {
288         color: $u-toast-u-type-default-color;
289         background-color: $u-toast-u-type-default-background-color;
290     }
291 </style>