vue3中常用工具类(自用)

2022-05-22  本文已影响0人  硅谷干货

observer.ts

const eventList = {};

const $on = function (eventName, callback) {
  if (!eventList[eventName]) {
    eventList[eventName] = [];
  }
  eventList[eventName].push(callback);
};

const $off = function (eventName, callback) {
  if (eventList[eventName]) {
    if (callback) {
      const index = eventList[eventName].indexOf(callback);
      eventList[eventName].splice(index, 1);
    } else {
      eventList[eventName].length = 0;
    }
  }
};

const $emit = function (eventName, ...params) {
  if (eventList[eventName]) {
    const fnArr = eventList[eventName];
    fnArr.forEach((callback) => {
      callback(...params);
    });
  }
};

export default {
  $on,
  $off,
  $emit,
};

setRem.ts

import { getCurrentInstance } from 'vue';
import { MapConsts } from '@/common/consts/MapConsts';
import { getPageClientWidth } from './usePagePosition';

const baseFont = 16; // 字体大小基准值

// 计算rem
const setRem = () => {
  // 相对于750像素的缩放比
  const clientWidth = getPageClientWidth();
  let scale = clientWidth / 375;
  // 根据屏幕变化 1rem 对应的 font-size
  // scale = scale > 1 ? 1 : scale;
  // const ratio = Math.max(parseFloat(window.devicePixelRatio.toFixed(2)), 1)
  const realFont = baseFont * scale;
  document.documentElement.style.fontSize = realFont + 'px';
 
  // 根据视口计算vh
  // let vh = window.innerHeight * 0.01
  // document.documentElement.style.setProperty('--vh', `${vh}px`)
};

// 初始化rem
export const initRem = () => {
  // 初始化rem
  setRem();
  // 获取全局属性变量
  const instance = getCurrentInstance();
  const globalProperties = instance.appContext.config.globalProperties;
  // 改变窗口大小时重新设置 rem
  window.addEventListener(MapConsts.RESIZE, () => {
    setRem();
    // 视窗大小变化监听
    globalProperties.$observer.$emit(MapConsts.HANDLERR_ESIZE);
  });
};

usePagePosition.ts

// 获取页面左边卷起距离
export function getPageScrollLeft() {
  const scrollLeft =
    window.pageXOffset ||
    document.documentElement.scrollLeft ||
    document.body.scrollLeft ||
    0;
  return scrollLeft;
}

// 获取页面顶部卷起距离
export function getPageScrollTop() {
  const scrollTop =
    window.pageYOffset ||
    document.documentElement.scrollTop ||
    document.body.scrollTop ||
    0;
  return scrollTop;
}

// 获取页面左边、顶部卷起距离
export function getPageScroll() {
  return {
    left: getPageScrollLeft(),
    top: getPageScrollTop(),
  };
}

// 获取可视区域宽度
export function getPageClientWidth() {
  const w =
    window.innerWidth ||
    document.documentElement.clientWidth ||
    document.body.clientWidth ||
    0;
  return w;
}

// 获取可视区域高度
export function getPageClientHeight() {
  const h =
    window.innerHeight ||
    document.documentElement.clientHeight ||
    document.body.clientHeight ||
    0;
  return h;
}

// 获取屏幕可见高度的兼容性document.documentElement.clientHeight之前是这样获取的,PC端没什么问题,就是手机浏览器打开时,出现异常。网上查了下,最终的实现代码
export function getPageClient() {
  return {
    width: getPageClientWidth(),
    height: getPageClientHeight(),
  };
}

// 以上获取做了浏览器兼容性处理,可直接对外提供使用,同时也可以对外统一使用
export const usePagePosition = () => {
  return {
    getPageScrollLeft,
    getPageScrollTop,
    getPageScroll,
    getPageClientWidth,
    getPageClientHeight,
    getPageClient,
  };
};

loadDevTools.ts

;(function () {
  if (!/mdebug=true/.test(window.location.href)) return;
  var script = document.createElement('script');
  script.src = 'https://cdn.bootcss.com/eruda/1.2.6/eruda.min.js';
  script.async = true;
  document.getElementsByTagName('head')[0].appendChild(script);
  script.onload = function () {
    // @ts-ignore
    eruda.init();
  };
})();

ConfigUtils.ts

import { getConfig } from "@/api";
import Config from "./Config";

export default class ConfigUtils {
  private static config = null;
  private static callbackResolves = [];

  static async initConfig() {
    const response = await getConfig();
    this.config = response;
    this.callbackResolves.forEach((resolve) => resolve(this.config));
    return this.config;
  }

  static getConfig(): Promise<Config> {
    return new Promise((resolve) => {
      if (this.config) {
        resolve(this.config);
      } else {
        this.callbackResolves.push(resolve);
      }
    })
  }
}

DeviceType.ts

export default class DeviceType {
  static getDeviceType() {
    const obj = this.checkDeviceType();
    if (obj.isMobile) {
      return 'phone';
    }
    if (obj.isTablet) {
      return 'pad';
    }
    if (obj.isPc) {
      return 'pc';
    }
    return 'pc';
  }

  static checkDeviceType() {
    const ua = navigator.userAgent;
    const isWindowsPhone = /(?:Windows Phone)/.test(ua);
    const isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone;
    const isAndroid = /(?:Android)/.test(ua);
    const isFireFox = /(?:Firefox)/.test(ua);
    const isTablet =
      /(?:iPad|PlayBook)/.test(ua) ||
      (isAndroid && !/(?:Mobile)/.test(ua)) ||
      (isFireFox && /(?:Tablet)/.test(ua));
    const isiPhone = /(?:iPhone)/.test(ua) && !isTablet;
    const isMacOSX = /(?:iPad|Mac OS X)/.test(ua);
    const isPc =
      window.devicePixelRatio === 1 &&
      !isiPhone &&
      !isAndroid &&
      !isSymbian &&
      !('ontouchend' in document.body);
    return {
      isTablet,
      isMobile:
        (DeviceType.isMobileDevice() && !isTablet) ||
        (isAndroid && !isTablet) ||
        isiPhone,
      isAndroid,
      isPc,
      isiPhone,
      isMacOSX,
      isWeChat: Boolean(navigator.userAgent.match(/MicroMessenger/gi)),
    };
  }

  // 判断设备类型是否为手机、平板
  // 方式一:推荐
  static isMobile(): boolean {
    const obj = this.checkDeviceType();
    if (obj.isMobile) { // 手机
      return true;
    }
    if (obj.isTablet) { // 平板
      return true;
    }
    return false;
  }

  // 方式二:normal
  static isMobileDevice() {
    return 'ontouchend' in document.body;
  }

  // 方式一:推荐
  static isAndroid(): boolean {
    return this.checkDeviceType().isAndroid;
  }
  // 方式二:normal
  static isAndroid2(): boolean {
    return navigator.userAgent.toLowerCase().indexOf('android') > 0;
  }

  // 判断移动设备是否横屏模式(推荐)
  static isMobileLandscape() { 
    if (window.orientation == 0 || window.orientation == 180) {
      return false
    } else if (window.orientation == 90 || window.orientation == -90) {
      return true
    }
    return false
  }

  // 判断移动设备是否竖屏模式
  static isMobilePortrait() {
    const isMobileDevice = this.checkDeviceType().isMobile;
    return isMobileDevice && window.innerWidth <= window.innerHeight;
  }
}

language.ts

/*
 * @Descripttion: 描述:需要哪种语言就在languageList里面加上
 */
const languageList = ['zh', 'en']

export const getLanguage = () => {
  let localLang = navigator.language.toLocaleLowerCase() || 'en'
  if (languageList.indexOf(localLang) !== -1) {
    return localLang
  } else if (localLang.match(/\w+(?=[\-]|[\_])/g)) {
    localLang = localLang.match(/\w+(?=[\-]|[\_])/g)[0]
    if (languageList.indexOf(localLang) !== -1) {
      return localLang
    }
  }
  localLang = localLang === 'zh' ? 'zh-cn' : localLang // zh   zh-cn均代表中文
  localLang = localLang === 'iw' ? 'he' : localLang // 'he', 'iw'都是希伯来语
  localLang = languageList.indexOf(localLang) === -1  ? 'en' : localLang   // 定义默认的语言为 en
  return localLang
}

// 获取浏览器,默认语言'zh'
export const getNavigatorLanguage = () => {   // getNavigatorLanguage 此函数没有用到
  let language = (
    (navigator.language ? navigator.language : navigator.userLanguage) || "zh"
  ).toLowerCase();
  return language.split("-")[0] || "zh";
}

RegExpUtils.ts

export default class RegExpUtils {
  // 基础uri
  private static publicPath = '/about';

  // 替换路径
  public static rmPublicPath(path: string): string {
    if (path) {
      return path.replace(this.publicPath, '');
    }
    return '';
  }

  // 检查用户输入是否以http或者https开头,如果不是则添加http或者https
  public static httpCheck(href) {
    if (href == null || href.length == 0) {
      return;
    }
    var reg = new RegExp(/^(http|https).*$/);
    if (!reg.test(href)) {
      return 'https://' + href;
    }
    return href;
  }

  public static getQueryParam(paramName: string): string {
    return (
      (new RegExp(`[?|&]${paramName}=([^&;]+?)(&|#|;|$)`).exec(
        location.href
      ) || ["", ""])[1].replace(/\+/g, "%20") || ""
    );
  }

  public static getFileName(disposition: string): string {
    let fileName = "";
    if (disposition) {
      const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
      const matches = filenameRegex.exec(disposition);
      if (matches != null && matches[1]) {
        fileName = matches[1].replace(/['"]/g, "");
      }
    }
    return fileName;
  }
  //更新url地址参数
  public static changeURLPar(url, params) {
    for (let key in params) {
      let pattern = key + "=([^&]*)";
      let replaceText = key + "=" + params[key];
      if (url.match(pattern)) {
        let tmp = new RegExp(`${key}=[^&]*`);
        url = url.replace(tmp, replaceText);
      } else {
        if (url.match("[?]")) {
          url = url + "&" + replaceText;
        } else {
          url = url + "?" + replaceText;
        }
      }
    }
    return url;
  }
  // 处理url,防xss攻击
  public static isValidURL(url: string): string {
    const tempURL = url?.toLowerCase();
    if (tempURL && tempURL.indexOf("javascript:") !== -1) {
      return "#";
    }
    return url;
  }
}

useContentObserver.ts

import { onMounted, onBeforeUnmount, getCurrentInstance } from "vue";
import { MapConsts } from "@/common/consts/MapConsts"

// 替代v2中的mixins,但是注意使用顺序
export default function(): void{ 
  
  const instance = getCurrentInstance(); // 获取当前组件的实例、上下文来操作router和vuex等
  // 通过 getCurrentInstance这个函数来返回当前组件的实例对象,也就是当前vue这个实例对象

  onMounted(() => {
    window.addEventListener(MapConsts.SCROLL, handleScroll);
  });
  
  onBeforeUnmount(() => {
    window.removeEventListener(MapConsts.SCROLL, handleScroll);
  });
  
  const handleScroll = ()=> {
    //挂载全局属性和方法,使用app.config.globalProperties
    const globalProperties = instance.appContext.config.globalProperties;  
    globalProperties.$observer.$emit(MapConsts.HANDLER_SCROLL);
  };
}

animate.ts

// 动画方法
export function animate(obj, target, callback) {
  // console.log(callback);  callback = function() {}  调用的时候 callback()

  // 先清除以前的定时器,只保留当前的一个定时器执行
  clearInterval(obj.timer);
  obj.timer = setInterval(function() {
      // 步长值写到定时器的里面
      // 把我们步长值改为整数 不要出现小数的问题
      // var step = Math.ceil((target - obj.offsetLeft) / 10);
      var step = (target - obj.offsetLeft) / 10;
      step = step > 0 ? Math.ceil(step) : Math.floor(step);
      if (obj.offsetLeft == target) {
          // 停止动画 本质是停止定时器
          clearInterval(obj.timer);
          // 回调函数写到定时器结束里面
          // if (callback) {
          //     // 调用函数
          //     callback();
          // }
          callback && callback();
      }
      // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
      obj.style.left = obj.offsetLeft + step + 'px';

  }, 15);
}
上一篇下一篇

猜你喜欢

热点阅读