vue 封装一个数美验证

Event 发布者订阅模式

type ICallback = (data: any) => void;

export default class Event {
  listener: { [key in string]: any[] } = {};
  on(event: string, fn: ICallback) {
    if (!this.listener[event]) {
      this.listener[event] = [];
    }
    this.listener[event].push(fn);
    return true;
  }

  off(event: string, fn: ICallback) {
    if (this.listener[event]) {
      var index = this.listener[event].indexOf(fn);
      if (index > -1) {
        this.listener[event].splice(index, 1);
      }
      return true;
    }
    return false;
  }

  offAll() {
    this.listener = {};
  }

  dispatch(event: string, data: any) {
    if (this.listener[event]) {
      this.listener[event].map(each => {
        each.call(null, data);
      });
      return true;
    }
    return false;
  }
}

SmPhotoVerify.ts页面

import Event from './Event';

interface ISmCaptchaOptions {
  // 数美分配的公司标识,数美后台可以查看看
  organization?: string;
  // 应用标识,区分不同应用,数美后台可以管理
  appId?: string;
  channel?: string; //  推广渠道,可自定义
  product?: string; // embed(嵌入式)   展现形式,支持:embed(嵌入式)、float(浮动式)、popup(弹出层)
  mode?: string; // 模式:支持slide(滑动验证码)、auto_slide(无图片滑动验证码)、select(文字点选验证码)、 icon_select(图标点选验证码)、 seq_select(成语语序验证码)、spatial_select(空间逻辑)
  appendTo?: string; // 验证码dom元素的id。embed(嵌入式)、float(浮动式)必须配置,popup(弹出层)不需要
  lang?: string; // zh-cn(简体中文) 模式:支持zh-cn(简体中文)、en(英文)、ph(菲律宾语)、ina(印尼语)、tha(泰语)、vn(越南语)、mys(马来语)、jp(日语)、kr(韩语)、西班牙语(es)、孟加拉语(bn)、葡萄牙语(pt)、德语(de)、法语(fr)、印地语(hi)、意大利语(it)、乌尔都语(ur)、俄语(ru)、瑞典语(sv)、土耳其语(tr)、中文繁体 (zh-tw)、阿拉伯语(ar)。注意:成语语序和文字点选模式下,验证码图片内容默认为中文,不随语言调整而变化。
  useBrowserLang?: boolean; //  false   是否高优使用浏览器设置的语言作为验证码的语言
  customData?: { [key: string]: any }; // 自定义数据
  tipsMessage?: {
    slidePlaceholder?: string; // 向右滑动滑块填充拼图    自定义滑块默认文案,仅滑块验证支持自定义设置
  };
  disabled?: boolean; //    false   初始状态是否禁用验证码
  https?: boolean; //   加载资源是否是https
  width?: number | string; //   验证码宽度,单位支持数字、%、px,建议最小宽度为300px,宽高比建议为2:1
  debug?: boolean; //   开发过程中可以开启,出现异常会打印log,方便开发;上线后,务必关闭
  maskBindClose?: boolean; //   popup模式有效,是否可以通过点击遮罩层来关闭弹框
  onError?: () => void; //  监听配置获取接口异常,参数: errType, errMsg
  onInit?: () => void; //   开始加载验证码的回调,其中有个参数是captchaUuid
  style?: { [key: string]: any }; //    支持自定义样式及风格设置,详细配置请见3.12
  captchaUuid?: string; // 32位随机字符串 支持业务侧传入一个32位随机字符串,与业务方自身埋点数据配合,便于后续定位问题或进行数据统计
}

export class SmPhotoVerify extends Event {
  static isCreatedScript = false;

  private static url = 'https://castatic.fengkongcloud.cn/pr/v1.0.4/smcp.min.js';

  // 加载sdk
  static async createSmsSdk(): Promise<void> {
    if (this.isCreatedScript) {
      console.warn('sdk已经加载,已阻止重复加载');
      return;
    }
    const sm = document.createElement('script');
    const s = document.getElementsByTagName('script')[0];
    sm.src = this.url;

    if (s.parentNode) {
      s.parentNode.insertBefore(sm, s);
    } else {
      document.body.appendChild(sm);
    }
    this.isCreatedScript = true;
    return new Promise(resolve => {
      sm.onload = () => {
        resolve();
      };
    });
  }

  options = {
    organization: 'FOIj56LX23Xlg5Bvosc3',
  };

  initSMCaptcha = (options: ISmCaptchaOptions) => {
    if (!SmPhotoVerify.isCreatedScript) {
      console.warn('验证码初始化失败,请检查是否引入验证码sdk');
      return;
    }

    window.initSMCaptcha(Object.assign(this.options, options), (SMCaptcha: any) => {
      this.dispatch('message', {
        type: 'INSTANCE',
        data: {
          instance: SMCaptcha,
        },
      });

      SMCaptcha.onReady((dom: any, params: any) => {
        // params中有type字段,'init'-启动后 | 'refresh'-手动刷新图片后 | 'afterFail'-验证失败后
        this.dispatch('message', {
          type: 'READY',
          data: {
            dom,
            params,
          },
        });
      });

      // 验证码校验情况回调
      SMCaptcha.onSuccess((data: any) => {
        this.dispatch('message', {
          type: 'SMS_VERIFY_SUCCESS',
          data: data,
        });
      });

      SMCaptcha.onError((errType: any, errMsg: any) => {
        // errType格式: 'SERVER_ERROR'
        // errMsg格式: {code: 2002, message: " 服 务 器 异 常 : 无 权 限 操 作 (invalid organization)"}
        this.dispatch('message', {
          type: 'SMS_VERIFY_ERROR',
          data: {
            errType,
            errMsg,
          },
        });
      });

      SMCaptcha.onClose(() => {
        this.dispatch('message', {
          type: 'SMS_VERIFY_CLOSE',
        });
      });
    });
  };
}

export default new SmPhotoVerify();

mixin/smCaptchaMixin.ts

import { Vue, Component } from 'vue-property-decorator';
import smPhoneVerifyInstace, { SmPhotoVerify } from '@/utils/SmPhotoVerify';

@Component
export default class captchaMixin extends Vue {
  waitingRid: any = null;
  instance: any = null;

  isOpenSmVerify(retry: boolean = false): Promise<string> {
    return new Promise((resolve, reject) => {
      this.waitingRid = resolve;
      if (!this.instance) {
        reject('实例没加载完成');
      }
      this.instance.verify();
    });
  }

  getVerifyMessage({ type, data }: any) {
    if (!type) {
      return;
    }
    switch (type) {
      case 'INSTANCE': {
        this.instance = data.instance;
        break;
      }
      // 添加块作用域
      case 'SMS_VERIFY_SUCCESS': {
        const { rid, pass } = data;
        if (pass) {
          this.waitingRid && this.waitingRid(rid);
          this.instance.reset();
        }
        break;
      }
      case 'SMS_VERIFY_ERROR':
        console.log(data.errMsg.message || '验证失败');
        break;
    }
  }

  beforeUnmount() {
    smPhoneVerifyInstace.offAll();
  }

  mounted() {
    smPhoneVerifyInstace.offAll();
    SmPhotoVerify.createSmsSdk().then(() => {
      smPhoneVerifyInstace.initSMCaptcha({
        product: 'popup',
        width: 300,
        https: false,
      });
    });

    smPhoneVerifyInstace.on('message', this.getVerifyMessage.bind(this));
  }
}

页面调用

import SmCaptchaMixin from '@/mixin/smCaptchaMixin';
export default class extends Mixins(SmCaptchaMixin) 
     this.rid = await this.isOpenSmVerify();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。