Browse Source

fix: CR第二期-toast组件优化

张宇 5 years ago
parent
commit
566a082d88
4 changed files with 388 additions and 190 deletions
  1. 73 68
      src/packages/toast/_toast.js
  2. 148 30
      src/packages/toast/demo.vue
  3. 99 65
      src/packages/toast/doc.md
  4. 68 27
      src/packages/toast/toast.vue

+ 73 - 68
src/packages/toast/_toast.js

@@ -1,9 +1,34 @@
-import Vue from 'vue';
-import settings from './toast.vue';
+import Vue from "vue";
+import settings from "./toast.vue";
 
 let ToastConstructor = Vue.extend(settings);
 let instance;
 let instanceArr = [];
+let defaultOptionsMap = {};
+const defaultOptions = {
+  msg: "",
+  visible: false,
+  duration: 2000, //显示时间(毫秒)
+  timer: null,
+  center: true,
+  type: "",
+  customClass: "",
+  bottom: 30,
+  size: "base",
+  icon: null,
+  textAlignCenter: true,
+  loadingRotate: true,
+  bgColor: "rgba(36, 36, 36, 0.8)",
+  onClose: null,
+  textTimer: null,
+  cover: false, //透明遮罩层
+  coverColor: "rgba(0, 0, 0, 0)",
+  timeStamp: null,
+  closeOnClickOverlay: false
+};
+let currentOptions = {
+  ...defaultOptions
+};
 
 function _showToast() {
   instance.vm = instance.$mount();
@@ -15,93 +40,73 @@ function _showToast() {
 
 function _getInstance(obj) {
   let opt = {
-        id:new Date().getTime(),
-        msg: "",
-        visible: false,
-        duration: 2000, //显示时间(毫秒)
-        timer: null,
-        center: true,
-        type: "",
-        customClass: "",
-        bottom: 30,
-        size:"base",
-        icon:null,
-        textAlignCenter: true,
-        loadingRotate:true,
-        bgColor: "rgba(36, 36, 36, 0.8)",
-        onClose:null,
-        textTimer: null,
-        cover:false,  //透明遮罩层
-        timeStamp:null
-      };
-  
-  opt = Object.assign(opt, obj);
+    id: new Date().getTime(),
+    ...currentOptions,
+    ...defaultOptionsMap[obj.type],
+    ...obj
+  };
 
   //有相同id者共用一个实例,否则新增实例
-  if (opt['id'] && instanceArr[opt['id']]) {
-    instance = instanceArr[opt['id']];
+  if (opt["id"] && instanceArr[opt["id"]]) {
+    instance = instanceArr[opt["id"]];
     instance.hide(true);
     instance = Object.assign(instance, opt);
   } else {
     instance = new ToastConstructor({
       data: Object.assign(opt, obj)
     });
-    opt['id'] && (instanceArr[opt['id']] = instance);
+    opt["id"] && (instanceArr[opt["id"]] = instance);
   }
 
   _showToast();
   return instance;
 }
 
+function errorMsg(msg) {
+  if (!msg) {
+    console.warn("[NutUI Toast]: msg不能为空");
+    return;
+  }
+}
+
 let Toast = {
-  text(msg, obj) {
-    if (!msg) {
-      console.warn('[NutUI Toast]: msg不能为空');
-      return;
-    }
-    obj = obj || {};
-    obj.msg = msg;
-    return _getInstance(obj);
+  text(msg, obj = {}) {
+    errorMsg(msg);
+    return _getInstance({ ...obj, msg, type: "text" });
   },
-  success(msg, obj) {
-    if (!msg) {
-      console.warn('[NutUI Toast]: msg不能为空');
-      return;
-    }
-    obj = obj || {};
-    obj.msg = msg;
-    obj.type = 'success';
-    return _getInstance(obj);
+  success(msg, obj = {}) {
+    errorMsg(msg);
+    return _getInstance({ ...obj, msg, type: "success" });
   },
-  fail(msg, obj) {
-    if (!msg) {
-      console.warn('[NutUI Toast]: msg不能为空');
-      return;
-    }
-    obj = obj || {};
-    obj.msg = msg;
-    obj.type = 'fail';
+  fail(msg, obj = {}) {
+    errorMsg(msg);
+    return _getInstance({ ...obj, msg, type: "fail" });
+  },
+  warn(msg, obj = {}) {
+    errorMsg(msg);
+    return _getInstance({ ...obj, msg, type: "warn" });
+  },
+  loading(msg, obj = {}) {
+    obj = { ...obj, id: obj.id || "loading", msg, type: "loading" };
+    obj.cover = typeof obj.cover !== "undefined" ? obj.cover : true; //loading类型默认打开遮罩层
+    obj.duration = obj.duration || 0; //loading类型默认不自动关闭
     return _getInstance(obj);
   },
-  warn(msg, obj) {
-    if (!msg) {
-      console.warn('[NutUI Toast]: msg不能为空');
-      return;
+  setDefaultOptions(type, options) {
+    if (typeof type === "string") {
+      defaultOptionsMap[type] = options;
+    } else {
+      Object.assign(currentOptions, type);
     }
-    obj = obj || {};
-    obj.msg = msg;
-    obj.type = 'warn';
-    return _getInstance(obj);
   },
-  loading(msg,obj) {
-    obj = obj || {};
-    obj.id = obj.id || 'loading';
-    obj.msg = msg;
-    obj.type = 'loading';
-    obj.cover = typeof(obj.cover)!=='undefined'?obj.cover:true; //loading类型默认打开遮罩层
-    obj.duration = obj.duration || 0;
-    return _getInstance(obj);
+  resetDefaultOptions(type) {
+    if (typeof type === "string") {
+      defaultOptionsMap[type] = null;
+    } else {
+      currentOptions = { ...defaultOptions };
+      defaultOptionsMap = {};
+    }
   }
 };
 
-export default Toast;
+export default Toast;

File diff suppressed because it is too large
+ 148 - 30
src/packages/toast/demo.vue


+ 99 - 65
src/packages/toast/doc.md

@@ -3,7 +3,7 @@
 轻提示。
 
 ## 基本用法
-
+文字提示
 ```javascript
 export default {
   mounted() {
@@ -12,25 +12,6 @@ export default {
 }
 ```
 
-## 高级用法
-
-第二个参数是一个对象,可以传入一些高级配置。
-
-```javascript
-export default {
-  mounted() {
-    this.$toast.text('提示信息',{
-        duration: 4000, //展示时长
-        center: true, //是否居中展示,值为false时展示在页面底部
-        bottom: 40, //展示在页面底部时,距底部的距离(px)
-        textAlignCenter:true //多行文本是否居中展示,值为false时单行居中,多行居左
-    });
-  }
-}
-```
-
-## 带ICON
-
 成功提示
 
 ```javascript
@@ -64,22 +45,48 @@ export default {
 ## 加载提示
 
 ```javascript
-//Loading类型,默认不会自动消失,带透明遮罩
-this.loading = this.$toast.loading();
-
-//手动关闭上面的Loading
-this.loading.hide();
+// 带文案,显示透明遮罩层(默认),自动消失
+this.$toast.loading('加载中...',{ 
+    duration:3000
+});
 
-//带文字,自动消失,不要遮罩
+//带文案,显示半透明遮罩层,自动消失,点击遮罩层后消失
 this.$toast.loading('加载中...',{ 
     duration:3000,
-    cover:false
+    coverColor: "rgba(0,0,0,0.5)",
+    closeOnClickOverlay: true
 });
+
+//不会自动消失(默认),不带遮罩层
+this.loading = this.$toast.loading({
+    cover: false
+});
+
+//手动关闭上面的Loading
+this.loading.hide();
 ```
 
+## 自定义样式
+
+```javascript
+//自定义背景颜色/透明度
+this.$toast.text('自定义背景颜色/透明度',{
+    bgColor:'rgba(50, 50, 50, 0.9)'
+});
+
+//自定义class
+this.$toast.text('自定义class',{
+    customClass:'my-class'
+});
+
+//自定义Icon
+this.$toast.text('自定义Icon',{
+    icon:"https://img13.360buyimg.com/imagetools/jfs/t1/98294/28/14470/22072/5e65ba08E865683aa/ded7441bdd098511.png"
+});
+```
 ## 共享实例
 
-Toast的id如果相同,将共享一个实例。如果不设置id,多个Toast将拥有相同的id默认值,它们将共享一个实例(loading类型与其他类型实例不共享),新的内容和设置将取代旧的,多个Toast不能同时出现。如果不需要共享实例,可以给其设置id。
+如果不设置id,多个Toast将默认拥有相同的id,**它们将共享一个实例**(loading类型与其他类型实例不共享),新的内容和设置将取代旧的,多个Toast不能同时出现。如果不需要共享实例,可以给其设置id。
 
 ```javascript
 //二者id不同,不会共享一个实例
@@ -93,46 +100,73 @@ this.$toast.text(msg,{
 });
 ```
 
-## 自定义样式
-
+## 支持在JS模块中导入使用
 ```javascript
-//自定义背景颜色/透明度
-this.$toast.text('提示文案',{
-    bgColor:'rgba(50, 50, 50, 0.9)'
-});
+import { Toast } from "@nutui/nutui";
+
+Toast.text('在js模块中使用');
+// 返回实例,可以手动调用实例中的hide方法关闭提示
+const toast = Toast.loading('在js模块中使用');
+toast.hide();
+```
 
-//自定义字号,'small'/'base'/'large'三选一
-this.$toast.text('提示文案',{
-    size:'small'
+## 修改默认配置
+
+通过**Toast.setDefaultOptions**函数可以全局修改 Toast 的默认配置,**值得注意的是,loading无法支持默认配置的修改和重置**。
+
+```js
+// 更改所有Toast展示时长设置为5000毫秒
+Toast.setDefaultOptions({
+    duration: 5000,
+    coverColor: "rgba(0, 0, 0, 0.2)",
+    closeOnClickOverlay: true,
+    cover: true
 });
 
-//自定义class
-this.$toast.text('提示文案',{
-    customClass:'my-class'
+// 重置所有 Toast 的默认配置
+Toast.resetDefaultOptions();
+
+// 更改所有文字提示默认设置
+Toast.setDefaultOptions("text", {
+    size: "large",
+    cover: true,
+    coverColor: "rgba(0, 0, 0, 0.2)",
+    duration: 3000,
+    closeOnClickOverlay: true
 });
+
+// 重置 text Toast 的默认配置
+Toast.resetDefaultOptions("text");
 ```
-<!-- ```javascript
-//自定义loading的Icon
-this.$toast.loading(msg,{icon:"data:image/svg+xml,%3Csvg fill="#FFFFFF" xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 21'%3E%3Cpath d='M10 13.5l-7-6-3 3L10.5 21 28 3.5l-3-3z' fill-rule='evenodd'/%3E%3C/svg%3E"),
-    duration:3000
-});
-``` -->
-
-
-## API
-
-| 字段 | 说明 | 类型 | 默认值
-|----- | ----- | ----- | ----- 
-| msg | 消息文案 | String | ""
-| option.id | 标识符,相同者共用一个实例。loading类型默认使用一个实例,其他类型默认不共用。 | String/Number | -
-| option.duration | 展示时长(毫秒),为0时不自动关闭(loading类型默认为0) | Number | 2000
-| option.center | 是否展示在页面中部(为false时展示在底部) | Boolean | true
-| option.bottom | 距页面底部的距离(像素),option.center为false时生效 | Boolean | true
-| option.textAlignCenter | 多行文案是否居中 | Boolean | true
-| option.bgColor | 背景颜色(透明度) | String | "rgba(46, 46, 46, 0.7)"
-| option.customClass | 增加自定义class | String | ""
-| option.icon | 自定义图标,Data URI格式 | String | ""
-| option.size | 尺寸,small/base/large三选一 | String | "base"
-| option.cover | 透明遮罩,loading类型默认打开 | Boolean | loading类型true/其他false
-| option.loadingRotate | loading图标是否旋转,仅对loading类型生效 | Boolean | true
-| option.onClose | 关闭时触发的事件 | function | null
+
+### API
+| 方法名                    | 说明                                                                    | 参数            | 返回值     |
+| ------------------------- | ----------------------------------------------------------------------- | --------------- | ---------- |
+| Toast.text                | 展示文字提示                                                            | options/message | toast 实例 |
+| Toast.loading             | 展示加载提示                                                            | options/message | toast 实例 |
+| Toast.success             | 展示成功提示                                                            | options/message | toast 实例 |
+| Toast.fail                | 展示失败提示                                                            | options/message | toast 实例 |
+| Toast.warn                | 展示警告提示                                                            | options/message | toast 实例 |
+| Toast.hide                | 关闭提示                                                                | force:boolean   | void       |
+| Toast.setDefaultOptions   | 修改默认配置,对所有 Toast 生效<br>传入 type 可以修改指定类型的默认配置 | type/options    | void       |
+| Toast.resetDefaultOptions | 重置默认配置,对所有 Toast 生效<br>传入 type 可以重置指定类型的默认配置 | type            | void       |
+
+## Options
+
+| 字段                | 说明                                                                          | 类型          | 默认值                        |
+| ------------------- | ----------------------------------------------------------------------------- | ------------- | ----------------------------- |
+| msg                 | 消息文本内容,支持传入HTML                                                     | String/VNode  | ""                            |
+| id                  | 标识符,相同者共用一个实例<br>loading类型默认使用一个实例,其他类型默认不共用 | String/Number | -                             |
+| duration            | 展示时长(毫秒)<br>值为 0 时,toast 不会自动消失(loading类型默认为0)       | Number        | 2000                          |
+| center              | 是否展示在页面中部(为false时展示在底部)                                     | Boolean       | true                          |
+| bottom              | 距页面底部的距离(像素),option.center为false时生效                          | Boolean       | true                          |
+| textAlignCenter     | 多行文案是否居中                                                              | Boolean       | true                          |
+| bgColor             | 背景颜色(透明度)                                                            | String        | "rgba(46, 46, 46, 0.7)"       |
+| customClass         | 自定义类名                                                                    | String        | ""                            |
+| icon                | 自定义图标,**支持图片链接或base64格式**                                        | String        | ""                            |
+| size                | 尺寸,**small**/**base**/**large**三选一                                                  | String        | "base"                        |
+| cover               | 是否显示遮罩层,loading类型默认显示                                           | Boolean       | loading类型true/其他类型false |
+| coverColor          | 遮罩层颜色,默认透明                                                          | String        | "rgba(0,0,0,0)"               |
+| loadingRotate       | loading图标是否旋转,仅对loading类型生效                                      | Boolean       | true                          |
+| onClose             | 关闭时触发的事件                                                              | function      | null                          |
+| closeOnClickOverlay | 是否在点击遮罩层后关闭提示                                                    | Boolean       | false                         |

+ 68 - 27
src/packages/toast/toast.vue

@@ -1,18 +1,30 @@
 <template>
   <transition name="toastfade">
-    <div :id="id"
-      :class="['nut-toast',{'nut-toast-center':center},{'nut-toast-has-icon':type},{'nut-toast-cover':cover},{'nut-loading':type=='loading'},customClass,'nut-toast-'+size]"
+    <div
+      :id="id"
+      :class="toastClass"
       v-if="visible"
-      :style="{'bottom':center?'auto':bottom+'px'}"
+      :style="{
+        bottom: center ? 'auto' : bottom + 'px',
+        'background-color': coverColor
+      }"
+      @click="clickCover"
     >
       <div
         class="nut-toast-inner"
-        :style="{'text-align':textAlignCenter?'center':'left','background-color':bgColor}"
+        :style="{
+          'text-align': textAlignCenter ? 'center' : 'left',
+          'background-color': bgColor
+        }"
       >
-        <span class="nut-toast-icon-wrapper">
+        <span v-if="hasIcon" class="nut-toast-icon-wrapper">
           <i
-            :class="['nut-toast-icon',type,{'nut-toast-icon-rotate':type==='loading'&&loadingRotate}]"
-            :style="{'background-image':cusIcon}"
+            :class="[
+              'nut-toast-icon',
+              type,
+              { 'nut-toast-icon-rotate': type === 'loading' && loadingRotate }
+            ]"
+            :style="{ 'background-image': cusIcon }"
           ></i>
         </span>
         <span class="nut-toast-text" v-html="msg"></span>
@@ -26,24 +38,26 @@ export default {
   props: {},
   data() {
     return {
-        id:"",
-        msg: "",
-        visible: false,
-        duration: 2000, //显示时间(毫秒)
-        timer: null,
-        center: true,
-        type: "",
-        customClass: "",
-        bottom: 30,
-        size:"base",
-        icon:null,
-        textAlignCenter: true,
-        loadingRotate:true,
-        bgColor: "rgba(46, 46, 46, 0.7)",
-        onClose:null,
-        textTimer: null,
-        cover:false,
-        timeStamp:null
+      id: "",
+      msg: "",
+      visible: false,
+      duration: 2000, //显示时间(毫秒)
+      timer: null,
+      center: true,
+      type: "",
+      customClass: "",
+      bottom: 30,
+      size: "base",
+      icon: null,
+      textAlignCenter: true,
+      loadingRotate: true,
+      bgColor: "rgba(46, 46, 46, 0.7)",
+      onClose: null,
+      textTimer: null,
+      cover: false,
+      coverColor: "rgba(0, 0, 0, 0)",
+      timeStamp: null,
+      closeOnClickOverlay: false
     };
   },
   watch: {
@@ -56,6 +70,24 @@ export default {
   computed: {
     cusIcon() {
       return this.icon ? `url("${this.icon}")` : "";
+    },
+    toastClass() {
+      return [
+        "nut-toast",
+        { "nut-toast-center": this.center },
+        { "nut-toast-has-icon": this.hasIcon },
+        { "nut-toast-cover": this.cover },
+        { "nut-loading": this.type == "loading" },
+        this.customClass,
+        "nut-toast-" + this.size
+      ];
+    },
+    hasIcon() {
+      if (this.type !== "text") {
+        return true;
+      } else {
+        return this.cusIcon;
+      }
     }
   },
   methods: {
@@ -79,14 +111,23 @@ export default {
           this.msg = "";
         }, 300);
       }
-      typeof(this.onClose) === "function" && this.onClose();
+      typeof this.onClose === "function" && this.onClose();
     },
     clearTimer() {
       if (this.timer) {
         clearTimeout(this.timer);
         this.timer = null;
       }
+    },
+    clickCover() {
+      if (this.closeOnClickOverlay) {
+          this.hide();
+      }
     }
+  },
+  destroyed() {
+    this.textTimer = null;
+    this.timer = null;
   }
 };
-</script>
+</script>