Vue.extend封装函数式调用弹窗组件

33 篇文章 1 订阅
12 篇文章 0 订阅

问题背景:

平时我们使用组件都是import xxx from 'xxx';然后components里面注册,最后template中使用,这样一套流程下来略麻烦,有没有一种方式能像ElementUI的弹窗组件一样代码调用呢?下面看看如何实现

封装组件:

首先准备好组件和一个js文件用于导出调用组件的函数:

组件目录结构大概就是这样 

然后我们需要在index.js中创建调用组件的函数,创建组件的代码就是继承一份原组件进行实例化然后挂载到叶面的节点中,这里我是挂载了一个弹窗组件,封装了一些默认props:

import emitter from '@/plugins/mitt';
import router from '@/router';
import { Message } from 'element-ui';
import Vue from 'vue';
import PayDialog from './pay-dialog.vue';
const PayDialogConstructor = Vue.extend(PayDialog); // 倒入组件然后先继承一份组件得到新的组件构造函数
/**
 * @description 付费弹窗组件props校验
 * @param {{
 * url: string,
 * trackingId?: number,
 * onSuccess?: function,
 * } | string} props
 * @param {PromiseRejectionEvent} reject
 * @param {Function} executeFunc
 */
const validateProps = (props, reject, executeInitComponent) => {
  const propsTypes = ['string', 'object'];
  const propsType = typeof props;
  if (!propsTypes.includes(propsType)) {
    return reject(
      `Error in component PayDialog: invalid props type! expected ${propsTypes.join(
        ','
      )}, got ${propsType}`
    );
  }
  if (propsType === 'string' && props.trim() === '') {
    return reject('Error in component PayDialog: url can not be empty string!');
  }
  if (propsType === 'object' && props.trackingId && !props.url) {
    return reject(
      'Error in component PayDialog: renewal must be have props trackingId with valid url!'
    );
  }
  executeInitComponent();
};
/**
 * @description 付费/续费弹窗组件
 * 付费: 只需要传入url
 * 续费: 需要同时传入url和trackingId 传了trackingId就代表是续费
 * @param {{
 * url: string,
 * trackingId?: number,
 * onSuccess?: function,
 * } | string} options
 */
export default function (options) {
  return new Promise((resolve, reject) => {
    const executeInitComponent = () => {
      const propsData = {
        onDialogClosed(instance) {
          document.querySelector('.app').removeChild(instance.$el); // 窗口完全关闭后销毁窗口
          resolve(); // dosomething...
        },
        onSuccess: () => {
          // 如果没传成功的回调就走默认的成功提示和页面跳转逻辑
          if (!options.onSuccess) {
            Message({
              message: `${options.trackingId ? '续费' : '添加'}成功`,
              type: 'success',
              duration: 3000,
            });
            if (options.trackingId) {
              return emitter.emit('reloadPage'); // 如果传了trackingId则是续费,刷新页面
            }
            return router.push('/safety'); // 如果没传trackingId就是添加,跳转至检测链接页面
          }
          options.onSuccess(); // 付费/续费成功自定义dosomething...
        },
      };
      if (typeof options === 'string') {
        propsData.url = options; // 如果是ASIN字符串 则为付费
      } else {
        Object.assign(propsData, {
          trackingId: options.trackingId || 0, // 续费需要传商品的trackingId,
          url: options.url, // asin/商品url
        });
      }
      const payDialogInstance = new PayDialogConstructor({
        propsData, // props的key叫做propsData 这个和普通组件不一样要注意
      }); // 实例化组件
      document
        .querySelector('.app')
        .appendChild(payDialogInstance.$mount().$el); // $mount()不传参就是将组件实例挂载到文档外,返回值就是实例本身,传选择器就是挂载到具体元素里
      payDialogInstance.visible = true; // 组件挂载后显示出来
    };
    validateProps(options, reject, executeInitComponent); // 校验props
  });
}

这样我们在使用时直接从index.js中导入函数调用即可:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值