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);
}