浅谈前端工具库设计--交互类

80 阅读4分钟

前言

前端的工具库,常用的也都比较多,一些数据转换、格式化、存储等,也都比较杂,我们试着进行一个大的归类

  • 文字复杂、文件下载
  • 全屏处理公用方法
  • 图片下载以及转换 base64/blob等

copy.js

export default function copy(text) {
  const input = document.createElement("input");
  input.type = "text";
  input.value = text;
  document.body.appendChild(input);
  input.select();
  document.execCommand("copy");
  input.remove()
}

这个思路是在全局的根节点下,创建一个input标签,然后把赋值选中,使用execCommand执行复制动作

download.js

创建 A 标签下载

/**
 * 创建A标签下载
 * @param {string} url: 下载地址
 * @param {string} title: 下载标题
 * @param {string} target: 窗口位置(默认新开窗口)
 */
export default function download({ url, title = '', target = '_blank' }) {
  let tagA = document.createElement('a');
  tagA.setAttribute('href', url);
  tagA.setAttribute('download', title);
  tagA.setAttribute('target', target);
  document.body.appendChild(tagA);
  tagA.click();
  document.body.removeChild(tagA);
}

临时创建一个a标签,设置相关下载相关属性,然后执行点击动作

业务应用

//使用示例
import { download } from '@basic-utils';
download({ url: path, title });

fullScreenHelper 全屏

浏览器窗口全屏方法

业务应用

//使用示例
import { fullScreenHelper } from '@basic-utils';
//判断是否全屏
const fullScreenEle = fullScreenHelper.isFullscreen();
if (fullScreenEle) {
  //退出全屏
  fullScreenHelper.exitFullscreen();
} else {
  //进入全屏
  fullScreenHelper.fullscreen('dom');
}

源代码:

function fullscreen(element) {
  if (element.requestFullScreen) {
    element.requestFullScreen();
  } else if (element.webkitRequestFullScreen) {
    element.webkitRequestFullScreen();
  } else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen();
  } else if (element.msRequestFullscreen) {
    element.msRequestFullscreen();
  }
}

/**
 * exitFullscreen 退出全屏
 * @param  {Objct} element 选择器
 */
function exitFullscreen() {
  if (!isFullscreen()) {
    return;
  }
  if (document.exitFullscreen) {
    document.exitFullscreen();
  } else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
  } else if (document.webkitExitFullscreen) {
    document.webkitExitFullscreen();
  } else if (document.msExitFullscreen) {
    document.msExitFullscreen();
  }
}

/**
 * 判读是否支持全屏
 */
function fullscreenEnabled() {
  return document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled;
}

/**
 * [isFullscreen 判断浏览器是否全屏]
 * @return [全屏则返回当前调用全屏的元素,不全屏返回false]
 */
function isFullscreen() {
  return document.fullscreenElement || document.msFullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || false;
}
// 添加 / 移除 全屏事件监听
function fullScreenListener(type, fullscreenchange) {
  const fullScreenEvents = ['fullscreenchange', 'mozfullscreenchange', 'webkitfullscreenchange', 'msfullscreenchange'];
  fullScreenEvents.map((v) => document[type](v, fullscreenchange));
}

export default {
  fullScreenListener,
  isFullscreen,
  fullscreenEnabled,
  exitFullscreen,
  fullscreen,
};

imageMethods

图片转换方法

业务应用

//使用示例
import { imageMethods } from '@basic-utils';

//图片base64转换为blob
const oldFile = imageMethods.base64ToBlob(base64Url);
//转base64下载网络图片
imageMethods.downloadLocalImage(imgUrl, title);
//图片地址转base64
imageMethods.urlToBase64({ imgUrl, imgQuality: 0.8 }, (base64Url, err) => {});

API

下载网络图片 downloadLocalImage
图片地址转base64 urlToBase64
dom绘图获取base64Url drawImage
图片base64转换为blob base64ToBlob

源代码

import tagAToDownload from './download';
/**
 * 下载网络图片
 *  @param imgUrl: 下载地址
 *  @param title: 下载标题
 */
function downloadLocalImage(imgUrl, title) {
  urlToBase64({ imgUrl, imgQuality: 0.8 }, (base64Url, err) => {
    if (err) return console.error(err);
    let path = URL.createObjectURL(base64ToBlob(base64Url));
    tagAToDownload({
      url: path,
      title,
    });
    setTimeout(() => {
      URL.revokeObjectURL(path);
    }, 10000);
  });
}

/**
 * 图片地址转base64
 */
function urlToBase64({ imgUrl, imgQuality = 1, width, height }, callback) {
  let img = document.createElement('img');
  // crossOrigin属性必须在src之前,否则会报错!!
  img.setAttribute('crossOrigin', 'anonymous');
  img.src = imgUrl;
  img.onload = () => {
    width = width ? width : img.width;
    height = height ? height : img.height;
    const base64Url = drawImage({
      target: img,
      width,
      height,
      imgQuality,
    });
    return callback && callback(base64Url, null);
  };
  img.onerror = (err) => {
    return callback && callback(null, err);
  };
}

/**
 * dom绘图获取base64Url
 * @param {element} target: 绘图目标: video、img、canvas
 * @param {Number} width: 图片宽度
 * @param {Number} height: 图片高度
 * @param {string} imgType: 图片类型
 * @param {Number} imgQuality: 图片质量 0-1
 */
function drawImage({ target, width, height, imgType = 'image/jpeg', imgQuality = 1 }) {
  let canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  canvas.getContext('2d').drawImage(target, 0, 0);
  const base64Url = canvas.toDataURL(imgType, imgQuality);
  return base64Url;
}

/**
 * 图片base64转换为blob
 * @param {string} base64Url
 */
function base64ToBlob(base64Url) {
  // 去掉url的头,并转换为byte
  var bytes = window.atob(base64Url.split(',')[1]); 
  // 处理异常,将ascii码小于0的转换为大于0
  var ab = new ArrayBuffer(bytes.length);
  var ia = new Uint8Array(ab);
  for (var i = 0; i < bytes.length; i++) {
    ia[i] = bytes.charCodeAt(i);
  }
  return new Blob([ab], { type: 'image/png' });
}

export default {
  downloadLocalImage,
  urlToBase64,
  drawImage,
  base64ToBlob,
};

UUID

通用唯一标识

业务应用

//使用示例
import { uuid } from '@basic-utils';;
const id = uuid();

源代码

/**
 * 生成UUID
 */
export default function uuid() {
  let s = [];
  let hexDigits = '0123456789abcdef';
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  s[14] = '4';
  s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
  s[8] = s[13] = s[18] = s[23] = '-';

  let uuidStr = s.join('');
  return uuidStr;
}

queryHelper

URL参数处理方法集合

API:

comparisonPahtname 判断2个path是否相等
queryFormat 对URL后的参数字符串转换成JSON
objectToQuery 对象转化为&连接符拼接

源代码:

/**
 * 处理location.search的方法,将字符串转换成json
 * @param {string} search
 */
export function queryFormat(search = '') {
  let params = {};
  if (search === '') {
    return params;
  }
  if (typeof search === 'string') {
    search = search.indexOf('?') < 0 ? search : search.substr(search.indexOf('?') + 1);
    let a = search.split('&');
    let b = a.map((v) => v.split('='));
    b.map((v) => (params[v[0]] = v[1]));
  }
  return params;
}

/**
 * @desc 对象转化为&连接符拼接
 */
export function objectToQuery(params) {
  let url = '';
  for (var i in params) {
    if (params[i]) {
      url += `${i}=${params[i]}&`;
    }
  }
  return url.substr(0, url.length - 1);
}

function comparisonPahtname(pathname1, pathname2) {
  if (!pathname1 || !pathname2) {
    return false;
  }
  if (pathname1 === pathname2) {
    return true;
  }
  const arr1 = pathname1.split('/');
  const arr2 = pathname2.split('/');
  if (arr1.length !== arr2.length) {
    return false;
  }

  return arr1.every((v, i) => {
    if (v === arr2[i]) {
      return true;
    }
    if (arr2[i].includes(':')) {
      return true;
    }
    return false;
  });
}

export default {
  comparisonPahtname,
  queryFormat,
  objectToQuery,
};

核心解读

comparisonPahtname,对2个path进行了多重判断
1、字符串
2、分割后数组长度判断
3、数组内每项进行判断,如果目标项中包含 : 就视为正常

queryFormat
参数后缀获取使用 location.search,对其进行了解析,?号和&进行查找和分割,遍历组装到对象返回。

isEqual

数据深比较

业务应用

//使用示例
import { isEqual } from '@basic-utils';

const isBool = !isEqual(obj, obj2);

源代码

import equal from 'fast-deep-equal';

export default function isEqual(objValue, othValue) {
  return equal(objValue, othValue);
}

核心解读

fast-deep-equal 深度的比较插件,性能比lodash高好几倍

性能基准:

fast-deep-equal x 261,950 ops/sec ±0.52% (89 runs sampled)
fast-deep-equal/es6 x 212,991 ops/sec ±0.34% (92 runs sampled)
fast-equals x 230,957 ops/sec ±0.83% (85 runs sampled)
nano-equal x 187,995 ops/sec ±0.53% (88 runs sampled)
shallow-equal-fuzzy x 138,302 ops/sec ±0.49% (90 runs sampled)
underscore.isEqual x 74,423 ops/sec ±0.38% (89 runs sampled)
lodash.isEqual x 36,637 ops/sec ±0.72% (90 runs sampled)
deep-equal x 2,310 ops/sec ±0.37% (90 runs sampled)
deep-eql x 35,312 ops/sec ±0.67% (91 runs sampled)
ramda.equals x 12,054 ops/sec ±0.40% (91 runs sampled)
util.isDeepStrictEqual x 46,440 ops/sec ±0.43% (90 runs sampled)
assert.deepStrictEqual x 456 ops/sec ±0.71% (88 runs sampled)

The fastest is fast-deep-equal

老铁们,系列设计持续更新中:

浅谈应用设计-basic-utils工具库
浅谈前端工具库设计--数据类
浅谈前端工具库设计--存储类
浅谈前端工具库设计--通信类