bee-table
Version:
Table ui component for react
476 lines (436 loc) • 14.5 kB
JavaScript
import warning from 'warning';
import parseInt from 'lodash/parseInt';
let scrollbarSize;
// Measure scrollbar width for padding body during modal show/hide
const scrollbarMeasure = {
position: 'absolute',
top: '-9999px',
width: '50px',
height: '50px',
overflow: 'scroll',
};
//注意需要处理各系统及各浏览器的兼容性
export function measureScrollbar(selectors,direction = 'vertical') {
if (typeof document === 'undefined' || typeof window === 'undefined') {
return 0;
}
if (scrollbarSize) {//计算一次即可
return scrollbarSize;
}
let brow = myBrowser();
let containerDom =(selectors&&document.querySelector(selectors))||document.body;
let doubleDiv = function (){
let scrollDivParent = document.createElement('div');
scrollDivParent.setAttribute("id",'measureScrollbar_temp');
scrollDivParent.style.position = 'absolute';
scrollDivParent.style.top = '-9999px';
scrollDivParent.style.overflow = 'scroll';
// scrollDivParent.style.background = 'red';
scrollDivParent.style.width = '50px';
scrollDivParent.style.height = '100px';
let scrollDivChild = document.createElement('div');
// scrollDivChild.style.background = 'green';
scrollDivChild.style.height = '200px';
scrollDivChild.style.flex = "1";
scrollDivParent.appendChild(scrollDivChild);
let a = document.getElementById('measureScrollbar_temp');
if(a){
containerDom.replaceChild(scrollDivParent,a);
}else{
containerDom.appendChild(scrollDivParent);
}
let barSize = scrollDivParent.getBoundingClientRect().width-scrollDivChild.getBoundingClientRect().width;
containerDom.removeChild(scrollDivParent);
scrollDivParent = null;
scrollDivChild = null;
return barSize;
}
let singleDiv = function(){
const scrollDiv = document.createElement('div');
Object.keys(scrollbarMeasure).forEach(scrollProp => {
scrollDiv.style[scrollProp] = scrollbarMeasure[scrollProp];
});
containerDom.appendChild(scrollDiv);
let barSize = scrollDiv.offsetWidth - scrollDiv.clientWidth;
containerDom.removeChild(scrollDiv);
return barSize;
}
if(brow.osType == 'Win'){
switch (brow.browserType) {
case "IE":
case "FF":
scrollbarSize = doubleDiv(); //window系统下firefox的offsetWidth同clientWidth一致,所以通过父子容器间带滚动条的墨盒尺寸计算出滚动条宽度
break;
default:
scrollbarSize= singleDiv();//注意:chrome浏览器可以自定义宽度::-webkit-scrollbar{width:8px}
}
}else if(brow.osType == 'Mac') {
switch (brow.browserType) {
case "FF":
scrollbarSize = 8;
break;
default:
scrollbarSize= singleDiv();
}
}else{
scrollbarSize= singleDiv();
}
return scrollbarSize;
}
export function myBrowser() {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var browserType = '',osType = '';
if (userAgent.indexOf("Opera") > -1) { //判断是否Opera浏览器
browserType = "Opera"
}else
if (userAgent.indexOf("Firefox") > -1) { //判断是否Firefox浏览器
browserType = "FF";
}else
if (userAgent.indexOf("Chrome") > -1) {
browserType = "Chrome";
}else
if (userAgent.indexOf("Safari") > -1) { //判断是否Safari浏览器
browserType = "Safari";
}else
if ((userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1) ||
(userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1) //ie版本11
) { //判断是否IE浏览器
browserType = "IE";
}
if(userAgent.indexOf("Win")>-1){
osType = 'Win';
}else if(userAgent.indexOf("Mac")>-1){
osType = 'Mac';
}
return {browserType,osType}
}
export function debounce(func, wait, immediate) {
let timeout;
return function debounceFunc() {
const context = this;
const args = arguments;
// https://fb.me/react-event-pooling
if (args[0] && args[0].persist) {
args[0].persist();
}
const later = () => {
timeout = null;
if (!immediate) {
func.apply(context, args);
}
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(function(){later()}, wait); // 兼容火狐浏览器的写法
if (callNow) {
func.apply(context, args);
}
};
}
const warned = {};
export function warningOnce(condition, format, args) {
if (!warned[format]) {
warning(condition, format, args);
warned[format] = true;
}
}
export function getOffset (Node, offset ) {
if(!offset) {
offset = {};
offset.top = 0;
offset.left = 0;
}
if(Node == document.body) {
return offset;
}
offset.top += Node.offsetTop;
offset.left += Node.offsetLeft;
if(Node.offsetParent)
return getOffset(Node.offsetParent, offset);
else
return offset;
};
export const tryParseInt = (value, defaultValue = 0) => {
const resultValue = parseInt(value);
if (isNaN(resultValue)) {
return defaultValue;
}
return resultValue;
};
export function addClass(elm, className) {
if (!className) return;
const els = Array.isArray(elm) ? elm : [elm];
els.forEach((el) => {
if (el.classList) {
el.classList.add(className.split(' '));
} else {
el.className += ` ${className}`;
}
});
}
export function removeClass(elm, className) {
if (!className) return;
const els = Array.isArray(elm) ? elm : [elm];
els.forEach((el) => {
if (el.classList) {
el.classList.remove(className.split(' '));
} else {
el.className = el.className.replace(new RegExp(`(^|\\b)${className.split(' ').join('|')}(\\b|$)`, 'gi'), ' ');
}
});
}
/**
* 简单数组数据对象拷贝
* @param {*} obj 要拷贝的对象
*/
export function ObjectAssign(obj){
let b = obj instanceof Array;
let tagObj = b?[]:{};
if(b){//数组
obj.forEach(da => {
let _da = {};
Object.assign(_da,da);
tagObj.push(_da);
});
}else{
Object.assign(tagObj,obj);
}
return tagObj;
}
/**
* 获取某个父元素
* */
export function closest(ele, selector) {
const matches = ele.matches || ele.webkitMatchesSelector || ele.mozMatchesSelector || ele.msMatchesSelector;
if (matches) {
while (ele) {
if (matches.call(ele, selector)) {
return ele;
} else {
ele = ele.parentElement;
}
}
}
return null;
}
export function getMaxColChildrenLength(columns){
let arr=[];
arr = columns.map((item,index)=>{
let chilrenLen = 0;
if(item.children){
chilrenLen = getColChildrenLength(item.children,chilrenLen+1)
}
return chilrenLen
})
var max = Math.max.apply(null,arr);
return max;
}
export function getColChildrenLength(columns,chilrenLen){
columns.forEach((item,index)=>{
if(item.children){
chilrenLen = getColChildrenLength(item.children,chilrenLen+1);
}
})
return chilrenLen;
}
function addHandler(element,type,handler){
if(!element)return ;
let event = null;
if(element.addEventListener){//检测是否为DOM2级方法
event = element.addEventListener(type, handler, false);
}else if (element.attachEvent){//检测是否为IE级方法
event = element.attachEvent("on" + type, handler);
} else {//检测是否为DOM0级方法
event = element["on" + type] = handler;
}
return event;
}
function removeHandler(element, type, handler){
if (element&&element.removeEventListener){//element&& ie11报错兼容
element.removeEventListener(type, handler, false);
} else if (element&&element.detachEvent){
element.detachEvent("on" + type, handler);
} else if(element) {
element["on" + type] = null;
}
}
function addHandlerArray(elemArray,type,handler){
if(!elemArray || !elemArray.length)return;
for(let i=0;i<elemArray.length;i++){
let elem = elemArray[i];
addHandler(elem,type,handler);
}
}
function removeHandlerArray(elemArray, type, handler){
if(!elemArray || !elemArray.length)return;
for(let i=0;i<elemArray.length;i++){
let elem = elemArray[i];
removeHandler(elem,type,handler);
}
}
//获取事件对象的兼容性写法
function getEvent(event){
return event ? event : window.event;
}
//获取事件对象目标的兼容性写法
function getTarget(event){
return event.target || event.srcElement;
}
function preventDefault(event){
if (event.preventDefault){
event.preventDefault();
} else {
event.returnValue = false;
}
}
function stopPropagation(event){
if (event.stopPropagation){
event.stopPropagation();
} else {
event.cancelBubble = true;
}
}
//是否支持触摸事件
function isSupportTouch() {
var support = {
touch: !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch)
};
return support;
}
//用事件冒泡方式,如果想兼容事件捕获只需要添加个bool参数
export const EventUtil = {
addHandler: addHandler,
removeHandler: removeHandler
}
/*
* 处理精度
*/
export function DicimalFormater(value,precision) {
var value = value + '',
precision = precision?precision:0;
for (var i = 0; i < value.length; i++) {
if ("-0123456789.".indexOf(value.charAt(i)) == -1)
return "";
}
return checkDicimalInvalid(value, precision);
};
export function checkDicimalInvalid(value, precision) {
if (value == null || isNaN(value))
return "";
// 浮点数总位数不能超过10位
var digit = parseFloat(value);
var result = (digit * Math.pow(10, precision) / Math.pow(10, precision))
.toFixed(precision);
if (result == "NaN")
return "";
return result;
};
/**
* 将数值转化为货币类型
* @param {*} number 数值
* @param {*} places 精度
* @param {*} thousand 是否展示千分位
*/
export function formatMoney(number, places, thousand) {
number = number || 0;
places = !isNaN(places = Math.abs(places)) ? places : 2;
let thousandSymbol = thousand ? "," : '';
let negative = number < 0 ? "-" : "";
let i = parseInt(number = Math.abs(+number || 0).toFixed(places), 10) + "";
let j = (j = i.length) > 3 ? j % 3 : 0;
return negative + (j ? i.substr(0, j) + thousandSymbol : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousandSymbol) + (places ? '.' + Math.abs(number - i).toFixed(places).slice(2) : "");
}
export const Event = {
addHandler,
removeHandler,
addHandlerArray,
removeHandlerArray,
isSupportTouch,
getEvent,
getTarget,
preventDefault,
stopPropagation
}
/**
* 将一维数组转换为树结构
* @param {*} treeData 扁平结构的 List 数组
* @param {*} attr 属性配置设置
* @param {*} flatTreeKeysMap 存储所有 key-value 的映射,方便获取各节点信息
*/
export function convertListToTree(treeData, attr, flatTreeKeysMap) {
let tree = []; //存储所有一级节点
let resData = treeData, //resData 存储截取的节点 + 父节点(除一级节点外)
resKeysMap = {}, //resData 的Map映射
treeKeysMap = {}; //tree 的Map映射
resData.map((element) => {
let key = attr.id;
resKeysMap[element[key]] = element;
});
// 查找父节点,为了补充不完整的数据结构
let findParentNode = (node) => {
let parentKey = node[attr.parendId];
if(parentKey !== attr.rootId) { //如果不是根节点,则继续递归
let item = flatTreeKeysMap[parentKey];
// 用 resKeysMap 判断,避免重复计算某节点的父节点
if(resKeysMap.hasOwnProperty(item[attr.id])) return;
resData.unshift(item);
resKeysMap[item[attr.id]] = item;
findParentNode(item);
}else{
// 用 treeKeysMap 判断,避免重复累加
if (!treeKeysMap.hasOwnProperty(node[attr.id]) ) {
let { key, title, children, _isLeaf, ...otherProps } = node;
let obj = {
key,
title,
_isLeaf,
children: []
}
tree.push(Object.assign(obj, {...otherProps}));
treeKeysMap[key] = node;
}
}
}
// 遍历 resData ,找到所有的一级节点
for (let i = 0; i < resData.length; i++) {
let item = resData[i];
if (item[attr.parendId] === attr.rootId && !treeKeysMap.hasOwnProperty(item[attr.id])) { //如果是根节点,就存放进 tree 对象中
let { key, title, children, ...otherProps } = item;
let obj = {
key: item[attr.id],
_isLeaf: item[attr._isLeaf],
children: []
};
tree.push(Object.assign(obj, {...otherProps}));
treeKeysMap[key] = item;
resData.splice(i, 1);
i--;
}else { //递归查找根节点信息
findParentNode(item);
}
}
// console.log('resData',resKeysMap);
var run = function(treeArrs) {
if (resData.length > 0) {
for (let i = 0; i < treeArrs.length; i++) {
for (let j = 0; j < resData.length; j++) {
let item = resData[j];
if (treeArrs[i].key === item[attr.parendId]) {
let { key, title, children, ...otherProps } = item;
let obj = {
key: item[attr.id],
_isLeaf: item[attr._isLeaf],
children: []
};
treeArrs[i].children.push(Object.assign(obj, {...otherProps}));
resData.splice(j, 1);
j--;
}
}
run(treeArrs[i].children);
}
}
};
run(tree);
return tree;
}