综合办公系统
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

uv-toast.vue 11KB

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