基於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");


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM