zoukankan      html  css  js  c++  java
  • 基于Vant封装一套弹窗插件

    ​ 最近这段时间,公司要求做一套移动端审批流程的页面。大量页面包含了固定样式的提示窗口。类似(alert、toast、confirm)的提示弹窗。考虑到移动端开发,所以采用了市面上面比较火的Vant(友赞)的UI框架。

    ​ 但是一般公司的设计都会比较定制化,会再原有的基础之上,做些主题、样式、交互上的一些调整。不过话说回来,毕竟用的是基于Vue这种框架。此时插槽不就是信手拈来。

    ​ 考虑到多人协作开发,弹窗又都是一样。所以就自己封装了一套插件,供其他人使用。虽可能不尽完美,但是确实是学习到了一些底层封装的思路。这不就是我们作为开发的人热衷的方向吗?做这些事情实际上也是在锻炼自己的技术,学习其他框架编写的思路,理解底层业务的实现原理。这一套封装虽不是多么强大,但也算是重新给我打开了一扇大门,让我对Javascript的有了更进一步的理解。

    公司UI


    封装的弹窗最终效果

    虽然可能有些出入(button,主要是没完善)

    设计思路

    ​ 最开始想到的肯定是Components,因为Vue本身全部都是组件,所有页面也都是以组件的形式开发,包括Template。通常如果封装弹窗组件,使用顺序一般都是import、然后声明、再然后用标签注入到相对应的页面上面使用,其实感觉并不是很友好。而且操作起来很麻烦,还要考虑到子组件注册弹窗后调用的时候,生命周期问题。如果对依赖顺序不太理不清的时候,会出现类似this.$refs... is undifiend | not function的情况。

    ​ 那为什么不能用类似this.$confirm 或者 this.$alert的形式,再我想要用到的时候直接一条命令就可以了呢?想到这里,就想到Vue提供的插件开发的支持。也就有了上面的最终效果。

    供上代码

    目录结构

    VMessage
        ├── Confirm
        │   ├── main.js
        │   └── main.vue
        └── index.js
    

    Confirm/mian.vue

    <template>
      <div class="private-vant-confirm-container">
        <private-dialog
          v-model="show"
          :before-close="beforeClose"
          :show-cancel-button="showCancelButton"
          :show-confirm-button="showConfirmButton"
          :close-on-click-overlay="closeOnClickOverlay"
        >
          <section>
            <svg-icon :icon-class="iconClass" v-if="iconClass" class-name="icon"></svg-icon>
            <span v-if="tips" class="tips">{{tips}}</span>
            <span v-if="message" class="message">{{message}}</span>
          </section>
        </private-dialog>
      </div>
    </template>
    
    <script>
    /* 确认弹窗 */
    import { Dialog } from "vant";
    
    export default {
      components: {
        "private-dialog": Dialog.Component
      },
      data() {
        return {
          show: false,
          type: "success",
          tips: "",
          icon: "",
          message: "",
          showCancelButton: false /* 是否展示取消按钮 */,
          showConfirmButton: false /* 是否展示确认按钮 */,
          closeOnClickOverlay: false /* 是否在点击遮罩层后关闭弹窗 */,
          onClose: null,
          duration: 2000
        };
      },
      watch: {
        show(val) {
          const { showCancelButton, showConfirmButton, duration } = this.$data;
          if (val && !showCancelButton && !showConfirmButton) {
            setTimeout(() => {
              this.show = false;
              this.handleCallback("close");
            }, duration);
          }
        }
      },
      computed: {
        iconClass() {
          return this.icon || this.type;
        }
      },
      methods: {
        beforeClose(action, done) {
          this.show = false;
          done();
          this.handleCallback(action);
        },
        handleCallback(action) {
          if (typeof this.onClose === "function") {
            this.onClose(action);
          }
        }
      }
    };
    </script>
    
    <style lang="scss" scoped>
    .private-vant-confirm-container {
      section {
        padding: 20px 0;
        display: flex;
        justify-content: space-around;
        align-items: center;
        flex-direction: column;
        .icon {
          font-size: 65px;
        }
        span {
          margin-top: 10px;
        }
        .tips {
          color: #2c2d2f;
          font-size: 20px;
        }
        .message {
          color: #48494c;
          font-size: 17px;
        }
      }
    }
    </style>
    

    Confirm/mian.js

    import Vue from "vue";
    import Main from "./main.vue";
    let ConfirmConstructor = Vue.extend(Main);
    
    const Confirm = function(options) {
      options = options || {};
      if (typeof options === "string") {
        options = {
          message: options,
        };
      }
    
      let instance = new ConfirmConstructor({
        data: options,
      });
      instance.$mount();
      document.body.appendChild(instance.$el);
      instance.show = true;
    
      return instance;
    };
    
    ["success", "warning"].forEach((type) => {
      Confirm[type] = (options) => {
        if (typeof options === "string") {
          options = {
            message: options,
          };
        }
        options.type = type;
        return Confirm(options);
      };
    });
    
    export default Confirm;
    

    VMessage/index.js

    /* 确认弹窗 */
    import Confirm from "./Confirm/main";
    
    /**
    
      使用示例
      this.$vConfirm.success({
        message: "提交成功",
        onClose(action) {
          console.log(action, " action");
        }
      });
    
      this.$vConfirm.warning({
        message: "确定同意该申请?",
        tips: "提示",
        showCancelButton: true,
        showConfirmButton: true,
        onClose(action) {
          console.log(action, " action");
        }
      });
    
      try {
        const action = await this.$vConfirmSync({
          type: "warning",
          message: "提交成功",
          showCancelButton: true,
          closeOnClickOverlay: false
        });
        console.log(action, " action");
      } catch (error) {
        console.log(error, " error");
      }
    
    */
    
    /**
     * 同步用法
     * @param {String} tips 提示
     * @param {String} message 内容
     * @param {String} type success (default) | warning
     * @param {String} icon 图标 load svg-icon
     * @param {Boolean} showCancelButton 是否展示取消按钮 default:false
     * @param {Boolean} showConfirmButton 是否展示确认按钮 default:false
     * @param {Boolean} closeOnClickOverlay 是否在点击遮罩层后关闭弹窗 default: false
     * @param {Number} duration 关闭时间 showCancelButton为false && showConfirmButton为false时 default:2000
     */
    function vConfirmSync(options) {
      return new Promise((resolve, reject) => {
        Confirm({
          ...options,
          onClose(action) {
            if (action === "confirm") resolve(action);
            else reject(action);
          },
        });
      });
    }
    
    /**
     * @author Gj
     * 封装Vant Dialog
     */
    const install = function(Vue) {
      Vue.prototype.$vConfirm = Confirm;
      Vue.prototype.$vConfirmSync = vConfirmSync;
    };
    
    export default {
      install,
    };
    

    src/main.js vue的注入口文件注册

    import { VMessage } from "@/components/index";
    Vue.use(VMessage);
    
    ...
    new Vue({
      router,
      store,
      i18n,
      render: (h) => h(App),
    }).$mount("#app");
    
  • 相关阅读:
    httpcontext in asp.net unit test
    initialize or clean up your unittest within .net unit test
    Load a script file in sencha, supports both asynchronous and synchronous approaches
    classes system in sencha touch
    ASP.NET MVC got 405 error on HTTP DELETE request
    how to run demo city bars using sencha architect
    sencha touch mvc
    sencha touch json store
    sencha touch jsonp
    51Nod 1344:走格子(贪心)
  • 原文地址:https://www.cnblogs.com/ivday/p/13073285.html
Copyright © 2011-2022 走看看