DUtils/index.js

727 lines
21 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function debounce(func, wait, immediate) {
var timeout, result;
var debounced = function () {
var context = this;
var args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function () {
timeout = null;
}, wait);
if (callNow) result = func.apply(context, args);
}
else {
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
}
return result;
};
debounced.cancel = function () {
clearTimeout(timeout);
timeout = null;
};
return debounced;
}
// 防抖的原理就是:
// 你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件那我就以新的事件的时间为准n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行!
// function getUserAction(e) {
// ...
// };
// // 防抖
// var setUseAction = debounce(getUserAction, 10000, true);
// // 取消
// setUseAction.cancel();
function throttle(func, wait, options) {
var timeout, context, args;
var previous = 0;
if (!options) options = {};
var later = function() {
previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
func.apply(context, args);
if (!timeout) context = args = null;
};
var throttled = function() {
var now = new Date().getTime();
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0 || remaining > wait) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
func.apply(context, args);
if (!timeout) context = args = null;
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
};
throttled.cancel = function() {
clearTimeout(timeout);
previous = 0;
timeout = null;
};
return throttled;
}
// 节流的原理:
// 如果你持续触发事件,每隔一段时间,只执行一次事件。
// 根据首次是否执行以及结束后是否执行,效果有所不同,实现的方式也有所不同。 我们用 leading 代表首次是否执行trailing 代表结束后是否再执行一次。
// throttle(getUserAction, 1000);
// //leadingfalse 表示禁用第一次执行
// throttle(getUserAction, 1000, {
// leading: false
// });
// //trailing: false 表示禁用停止触发的回调
// throttle(getUserAction, 1000, {
// trailing: false
// });
function transformJson(a, idStr, pidStr, chindrenStr) {
var r = [], hash = {}, id = idStr, pid = pidStr, children = chindrenStr, i = 0, j = 0, len = a.length;
for (; i < len; i++) {
hash[a[i][id]] = a[i];
}
for (; j < len; j++) {
var aVal = a[j], hashVP = hash[aVal[pid]];
if (hashVP) {
!hashVP[children] && (hashVP[children] = []);
hashVP[children].push(aVal);
} else {
r.push(aVal);
}
}
return r;
}
// // 二维字符串
// var jsonData = [{"belongsname":"","id":901,"isleaf":0,"name":"XJBHX-2标项目部","pid":"","type":""},{"belongsname":"","id":902,"isleaf":1,"name":"综合部(办公室)","pid":"901","type":""},{"belongsname":"","id":903,"isleaf":1,"name":"工程部(工技部/技术部)","pid":"901","type":""},{"belongsname":"","id":904,"isleaf":1,"name":"安质部","pid":"901","type":""},{"belongsname":"","id":905,"isleaf":1,"name":"计财部","pid":"901","type":""},{"belongsname":"","id":906,"isleaf":1,"name":"物设部(物机部)","pid":"901","type":""},{"belongsname":"","id":907,"isleaf":1,"name":"中心试验室","pid":"901","type":""}];
// //绑定的字段
// var jsonDataTree = transData(jsonData, 'id', 'pid', 'chindren');
// 加载带回调js
// loadScript('https://cdn.bootcss.com/Turf.js/5.1.6/turf.min.js',function(){
// console.log('onload');
// console.log(turf);
// });
function loadScriptCallback(src, callback) {
var script = document.createElement('script'),
head = document.getElementsByTagName('head')[0];
script.type = 'text/javascript';
script.charset = 'UTF-8';
script.src = src;
if (script.addEventListener) {
script.addEventListener('load', function () {
callback();
}, false);
} else if (script.attachEvent) {
script.attachEvent('onreadystatechange', function () {
var target = window.event.srcElement;
if (target.readyState == 'loaded') {
callback();
}
});
}
head.appendChild(script);
}
// 动态加载js脚本文件
// loadScript("javascript/lib/cookie.js");
function loadScript(url) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
// 动态加载js脚本
// var text = "function test(){alert('test');}";
// loadScriptString(text);
// test();
function loadScriptString(code) {
var script = document.createElement("script");
script.type = "text/javascript";
try{
// firefox、safari、chrome和Opera
script.appendChild(document.createTextNode(code));
}catch(ex) {
// IE早期的浏览器 ,需要使用script的text属性来指定javascript代码。
script.text = code;
}
document.body.appendChild(script);
}
// 动态加载css文件
// loadStyles("css/secondindex.css");
function loadStyles(url) {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;
document.getElementsByTagName("head")[0].appendChild(link);
}
// 动态加载css脚本
// var css = "body{color:blue;}";
// loadStyleString(css);
function loadStyleString(cssText) {
var style = document.createElement("style");
style.type = "text/css";
try{
// firefox、safari、chrome和Opera
style.appendChild(document.createTextNode(cssText));
}catch(ex) {
// IE早期的浏览器 ,需要使用style元素的stylesheet属性的cssText属性
style.styleSheet.cssText = cssText;
}
document.getElementsByTagName("head")[0].appendChild(style);
}
function getExt(filename) {
if (typeof filename == 'string') {
return filename
.split('.')
.pop()
.toLowerCase()
} else {
throw new Error('filename must be a string type')
}
}
// getExt("1.text") //->text
function copyToBoard(value) {
const element = document.createElement('textarea');
document.body.appendChild(element);
element.value = value;
element.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
document.body.removeChild(element);
return true
}
document.body.removeChild(element);
return false
}
// 原理:
// 创建一个textare元素并调用select()方法选中
// document.execCommand('copy')方法,拷贝当前选中内容到剪贴板。
//如果复制成功返回true
// copyToBoard('lalallala')
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
//使用方式
// const fetchData = async () => {
// await sleep(1000)
// }
function uuid(length, chars) {
chars =
chars ||
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
length = length || 8;
var result = '';
for (var i = length; i > 0; --i)
result += chars[Math.floor(Math.random() * chars.length)];
return result
}
// 使用方式
//第一个参数指定位数第二个字符串指定字符都是可选参数如果都不传默认生成8位
// uuid()
// 保留小数点以后几位默认2位
function cutNumber(number, no = 2) {
if (typeof number != 'number') {
number = Number(number);
}
return Number(number.toFixed(no))
}
// 使用场景JS的浮点数超长有时候页面显示时需要保留2位小数
function getFormData(object) {
const formData = new FormData();
Object.keys(object).forEach(key => {
const value = object[key];
if (Array.isArray(value)) {
value.forEach((subValue, i) =>
formData.append(key + `[${i}]`, subValue)
);
} else {
formData.append(key, object[key]);
}
});
return formData
}
// 使用场景上传文件时我们要新建一个FormData对象然后有多少个参数就append多少次使用该函数可以简化逻辑
// 使用方式:
// let req={
// file:xxx,
// userId:1,
// phone:'15198763636',
// //...
// }
// fetch(getFormData(req))
function getQueryValue(queryName) {
let reg = new RegExp("(^|&)" + queryName + "=([^&]*)(&|$)", "i");
let r = window.location.search.substr(1).match(reg);
if (r != null) {
return decodeURI(r[2]);
} else {
return null;
}
}
// 示例URL:
// http://htmlJsTest/getrequest.html?uid=admin&rid=1&fid=2&name=小明
// @param {[string]} queryName [参数名]
// @return {[string]} [参数值]
function objExtension (inObj, path, parms) {
// 一个长得像对象的字符串
var Things = path.split(".");
// 即将返回的对象
var obj = inObj;
// 不断迭代的key值
var key = "";
// 赋值
var strparms = JSON.stringify(parms);
for (var i = 0; i < Things.length; i++) {
// 累加key
key += Things[i];
// 如果对象不存在
if (!eval("obj." + key)) {
// 则创建它
eval("obj." + key + " = {}");
}
// 如果是最后一个的话
if (i === Things.length - 1) {
eval("obj." + key + " = " + strparms);
}
// 再叠加一次.
key += ".";
}
// 循环结束,返回对象
return obj
}
// var path = "D01.D0104.D010442.D01044207.D0104420707.D010442070701"
// objExtension({a: 123}, path, {id: 123, label: 321})
function getRequest(urlStr) {
let url = decodeURI(location.search);
if (typeof urlStr !== "undefined") {
url = "?" + urlStr.split("?")[1];
}
let theRequest = new Object();
if (url.indexOf("?") != -1) {
let str = url.substr(1);
let strs = str.split("&");
for (var i = 0; i < strs.length; i++) {
theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);
}
}
return theRequest;
}
// 示例URL:
// http://htmlJsTest/getrequest.html?uid=admin&rid=1&fid=2&name=小明
// @param {[string]} urlStr [当该参数不为空的时候则解析该url中的参数集合]
// @return {[string]} [参数集合]
/* eslint-disable promise/prefer-await-to-then */
const methodMap = [['requestFullscreen', 'exitFullscreen', 'fullscreenElement', 'fullscreenEnabled', 'fullscreenchange', 'fullscreenerror'], // New WebKit
['webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitFullscreenElement', 'webkitFullscreenEnabled', 'webkitfullscreenchange', 'webkitfullscreenerror'], // Old WebKit
['webkitRequestFullScreen', 'webkitCancelFullScreen', 'webkitCurrentFullScreenElement', 'webkitCancelFullScreen', 'webkitfullscreenchange', 'webkitfullscreenerror'], ['mozRequestFullScreen', 'mozCancelFullScreen', 'mozFullScreenElement', 'mozFullScreenEnabled', 'mozfullscreenchange', 'mozfullscreenerror'], ['msRequestFullscreen', 'msExitFullscreen', 'msFullscreenElement', 'msFullscreenEnabled', 'MSFullscreenChange', 'MSFullscreenError']];
const nativeAPI = (() => {
const unprefixedMethods = methodMap[0];
const returnValue = {};
for (const methodList of methodMap) {
const exitFullscreenMethod = methodList[1];
if (exitFullscreenMethod in document) {
for (const [index, method] of methodList.entries()) {
returnValue[unprefixedMethods[index]] = method;
}
return returnValue;
}
}
return false;
})();
const eventNameMap = {
change: nativeAPI.fullscreenchange,
error: nativeAPI.fullscreenerror
}; // eslint-disable-next-line import/no-mutable-exports
let screenfull = {
// eslint-disable-next-line default-param-last
request(element = document.documentElement, options) {
return new Promise((resolve, reject) => {
const onFullScreenEntered = () => {
screenfull.off('change', onFullScreenEntered);
resolve();
};
screenfull.on('change', onFullScreenEntered);
const returnPromise = element[nativeAPI.requestFullscreen](options);
if (returnPromise instanceof Promise) {
returnPromise.then(onFullScreenEntered).catch(reject);
}
});
},
exit() {
return new Promise((resolve, reject) => {
if (!screenfull.isFullscreen) {
resolve();
return;
}
const onFullScreenExit = () => {
screenfull.off('change', onFullScreenExit);
resolve();
};
screenfull.on('change', onFullScreenExit);
const returnPromise = document[nativeAPI.exitFullscreen]();
if (returnPromise instanceof Promise) {
returnPromise.then(onFullScreenExit).catch(reject);
}
});
},
toggle(element, options) {
return screenfull.isFullscreen ? screenfull.exit() : screenfull.request(element, options);
},
onchange(callback) {
screenfull.on('change', callback);
},
onerror(callback) {
screenfull.on('error', callback);
},
on(event, callback) {
const eventName = eventNameMap[event];
if (eventName) {
document.addEventListener(eventName, callback, false);
}
},
off(event, callback) {
const eventName = eventNameMap[event];
if (eventName) {
document.removeEventListener(eventName, callback, false);
}
},
raw: nativeAPI
};
Object.defineProperties(screenfull, {
isFullscreen: {
get: () => Boolean(document[nativeAPI.fullscreenElement])
},
element: {
enumerable: true,
get: () => document[nativeAPI.fullscreenElement] || undefined
},
isEnabled: {
enumerable: true,
// Coerce to boolean in case of old WebKit.
get: () => Boolean(document[nativeAPI.fullscreenEnabled])
}
});
if (!nativeAPI) {
screenfull = {
isEnabled: false
};
}
function isFullscreenEnabled() {
return !!(
document.webkitIsFullScreen ||
document.mozFullScreen ||
document.msFullscreenElement ||
document.fullscreenElement
);
}
//定义一些常量
var x_PI = 3.14159265358979324 * 3000.0 / 180.0;
var PI = 3.1415926535897932384626;
var a = 6378245.0;
var ee = 0.00669342162296594323;
/**
* 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
* 即 百度 转 谷歌、高德
* @param bd_lon
* @param bd_lat
* @returns {*[]}
*/
function bd09togcj02(bd_lon, bd_lat) {
var bd_lon = +bd_lon;
var bd_lat = +bd_lat;
var x = bd_lon - 0.0065;
var y = bd_lat - 0.006;
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
var theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
var gg_lng = z * Math.cos(theta);
var gg_lat = z * Math.sin(theta);
return [gg_lng, gg_lat]
}/**
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
* 即谷歌、高德 转 百度
* @param lng
* @param lat
* @returns {*[]}
*/
function gcj02tobd09(lng, lat) {
var lat = +lat;
var lng = +lng;
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
var theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
var bd_lng = z * Math.cos(theta) + 0.0065;
var bd_lat = z * Math.sin(theta) + 0.006;
return [bd_lng, bd_lat]
}/**
* WGS84转GCj02
* @param lng
* @param lat
* @returns {*[]}
*/
function wgs84togcj02(lng, lat) {
var lat = +lat;
var lng = +lng;
if (out_of_china(lng, lat)) {
return [lng, lat]
} else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [mglng, mglat]
}
}/**
* GCJ02 转换为 WGS84
* @param lng
* @param lat
* @returns {*[]}
*/
function gcj02towgs84(lng, lat) {
var lat = +lat;
var lng = +lng;
if (out_of_china(lng, lat)) {
return [lng, lat]
} else {
var dlat = transformlat(lng - 105.0, lat - 35.0);
var dlng = transformlng(lng - 105.0, lat - 35.0);
var radlat = lat / 180.0 * PI;
var magic = Math.sin(radlat);
magic = 1 - ee * magic * magic;
var sqrtmagic = Math.sqrt(magic);
dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI);
dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI);
var mglat = lat + dlat;
var mglng = lng + dlng;
return [lng * 2 - mglng, lat * 2 - mglat]
}
}
var transformlat = function transformlat(lng, lat) {
var lat = +lat;
var lng = +lng;
var ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
return ret
};
var transformlng = function transformlng(lng, lat) {
var lat = +lat;
var lng = +lng;
var ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
return ret
};
/**
* 判断是否在国内,不在国内则不做偏移
* @param lng
* @param lat
* @returns {boolean}
*/
var out_of_china = function out_of_china(lng, lat) {
var lat = +lat;
var lng = +lng;
// 纬度3.86~53.55,经度73.66~135.05
return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
};
// 其它方法
function calcAngle(p1, p2) {
// angle in radians
Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
// angle in degrees
var angleDeg = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) * 180 / Math.PI;
return angleDeg;
}
/**
* 事件总线
*
* 使用方法:
* 1. 引入组件类
* import EventBus from './EventBus'
* 2. 事件输出与订阅
* 输出EventBus.emit('ww.myevent','nihao1')
*
* 订阅EventBus.addEventListener('ww.myevent', (data) => {
* name = data;
* })
*
*/
class EventDispatcer {
constructor () {
// if (window && window.EventBus) {
// throw new Error('这是一个单例!')
// }
this.eventMap = new Map();
}
emit (evt,data) {
const event = new Event(evt);
let evtSet = this.eventMap.get(event.type);
if (evtSet) {
for (let item of evtSet.values()) {
item(data);
}
}
}
addEventListener (eventType, func) {
let evtSet = this.eventMap.get(eventType);
if (!evtSet) {
evtSet = new Set();
this.eventMap.set(eventType, evtSet);
}
evtSet.add(func);
}
removeEventListener (eventType, func) {
let evtSet = this.eventMap.get(eventType);
if (evtSet) {
evtSet.delete(func);
}
}
}
const bus = new EventDispatcer();
var main = {
debounce,
throttle,
transformJson,
getExt,
copyToBoard,
sleep,
uuid,
cutNumber,
getFormData,
getQueryValue,
isFullscreenEnabled,
objExtension,
getRequest,
screenfull,
loadScript,
loadScriptString,
loadScriptCallback,
loadStyles,
loadStyleString,
bd09togcj02,
gcj02tobd09,
gcj02towgs84,
wgs84togcj02,
calcAngle,
bus
};
export { bd09togcj02, bus, calcAngle, copyToBoard, cutNumber, debounce, main as default, gcj02tobd09, gcj02towgs84, getExt, getFormData, getQueryValue, getRequest, isFullscreenEnabled, loadScript, loadScriptCallback, loadScriptString, loadStyleString, loadStyles, objExtension, screenfull, sleep, throttle, transformJson, uuid, wgs84togcj02 };