mirror of
https://github.com/liriliri/eruda.git
synced 2026-02-02 09:49:00 +08:00
Dev: Optimize big array display
This commit is contained in:
@@ -383,7 +383,10 @@ function substituteStr(args)
|
||||
|
||||
function formatObj(val)
|
||||
{
|
||||
return `${getObjType(val)} ${getAbstract(val)}`;
|
||||
let type = getObjType(val);
|
||||
if (type === 'Array' && val.length > 1) type = `(${val.length})`;
|
||||
|
||||
return `${type} ${getAbstract(val)}`;
|
||||
}
|
||||
|
||||
function formatFn(val)
|
||||
|
||||
@@ -10,9 +10,14 @@ import {
|
||||
uniqId,
|
||||
upperFirst,
|
||||
isNum,
|
||||
toNum,
|
||||
isBool,
|
||||
escape,
|
||||
toStr
|
||||
toStr,
|
||||
chunk,
|
||||
each,
|
||||
map,
|
||||
isNaN
|
||||
} from './util';
|
||||
|
||||
export default class JsonViewer
|
||||
@@ -22,20 +27,121 @@ export default class JsonViewer
|
||||
evalCss(require('./json.scss'));
|
||||
|
||||
this._data = [data];
|
||||
this._data.erudaId = uniqId('erudaJson');
|
||||
this._$el = $el;
|
||||
this._map = {};
|
||||
createMap(this._map, this._data);
|
||||
|
||||
this._appendTpl();
|
||||
this._bindEvent();
|
||||
}
|
||||
jsonToHtml(data, firstLevel)
|
||||
{
|
||||
let ret = '';
|
||||
|
||||
for (let key in data)
|
||||
{
|
||||
let val = data[key];
|
||||
|
||||
if (key === 'erudaObjAbstract' ||
|
||||
key === 'erudaCircular' ||
|
||||
key === 'erudaId' ||
|
||||
key === 'erudaSplitArr' ||
|
||||
(isStr(val) && startWith(val, 'erudaJson'))) continue;
|
||||
|
||||
if (Object.hasOwnProperty.call(data, key)) ret += this.createEl(key, val, firstLevel);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
createEl(key, val, firstLevel = false)
|
||||
{
|
||||
let type = 'object',
|
||||
isUnenumerable = false,
|
||||
id;
|
||||
|
||||
if (key === 'erudaProto') key = '__proto__';
|
||||
if (startWith(key, 'erudaUnenumerable'))
|
||||
{
|
||||
key = trim(key.replace('erudaUnenumerable', ''));
|
||||
isUnenumerable = true;
|
||||
}
|
||||
|
||||
if (isArr(val)) type = 'array';
|
||||
|
||||
function wrapKey(key)
|
||||
{
|
||||
if (firstLevel || val.erudaSplitArr) return '';
|
||||
|
||||
let keyClass = 'eruda-key';
|
||||
if (isUnenumerable || contain(LIGHTER_KEY, key)) keyClass = 'eruda-key-lighter';
|
||||
|
||||
return `<span class="${keyClass}">${encode(key)}</span>: `;
|
||||
}
|
||||
|
||||
if (val === null)
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-null">null</span>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
if (isObj(val))
|
||||
{
|
||||
id = val.erudaId;
|
||||
let circularId = val.erudaCircular;
|
||||
let objAbstract = val['erudaObjAbstract'] || upperFirst(type);
|
||||
|
||||
let obj = `<li ${firstLevel ? 'data-first-level="true"' : ''} ${'data-object-id="' + (circularId ? circularId : id) + '"'}>
|
||||
<span class="${firstLevel ? '' : 'eruda-expanded eruda-collapsed'}"></span>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-open">${firstLevel ? '' : objAbstract}</span>
|
||||
<ul class="eruda-${type}" ${firstLevel ? '' : 'style="display:none"'}>`;
|
||||
|
||||
if (firstLevel) obj += this.jsonToHtml(this._map[id]);
|
||||
|
||||
return obj + '</ul><span class="eruda-close"></span></li>';
|
||||
}
|
||||
if (isNum(val) || isBool(val))
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-${typeof val}">${encode(val)}</span>
|
||||
</li>`;
|
||||
}
|
||||
if (isStr(val) && startWith(val, 'function'))
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-function">${encode(val).replace('function', '')}</span>
|
||||
</li>`;
|
||||
}
|
||||
if (val === 'undefined' || val === 'Symbol' || val === '(...)')
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-special">${val}</span>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-${typeof val}">"${encode(val)}"</span>
|
||||
</li>`;
|
||||
}
|
||||
_appendTpl()
|
||||
{
|
||||
this._$el.html(jsonToHtml(this._data, this._map, true));
|
||||
let data = this._map[this._data.erudaId];
|
||||
|
||||
this._$el.html(this.jsonToHtml(data, true));
|
||||
}
|
||||
_bindEvent()
|
||||
{
|
||||
let map = this._map;
|
||||
|
||||
let self = this;
|
||||
|
||||
this._$el.on('click', 'li', function (e)
|
||||
{
|
||||
let $this = $(this),
|
||||
@@ -45,7 +151,7 @@ export default class JsonViewer
|
||||
if ($this.data('first-level')) return;
|
||||
if (circularId)
|
||||
{
|
||||
$this.find('ul').html(jsonToHtml(map[circularId], map, false));
|
||||
$this.find('ul').html(self.jsonToHtml(map[circularId], false));
|
||||
$this.rmAttr('data-object-id');
|
||||
}
|
||||
|
||||
@@ -67,108 +173,86 @@ export default class JsonViewer
|
||||
}
|
||||
}
|
||||
|
||||
function jsonToHtml(data, map, firstLevel)
|
||||
function createMap(map, data)
|
||||
{
|
||||
let ret = '';
|
||||
let id;
|
||||
|
||||
for (let key in data)
|
||||
if (data.erudaId)
|
||||
{
|
||||
id = data.erudaId;
|
||||
} else
|
||||
{
|
||||
id = uniqId('erudaJson');
|
||||
data.erudaId = id;
|
||||
}
|
||||
|
||||
if (id)
|
||||
{
|
||||
let objAbstract = data.erudaObjAbstract;
|
||||
|
||||
let isArr = objAbstract && startWith(objAbstract, 'Array');
|
||||
if (isArr)
|
||||
{
|
||||
let arr = objToArr(data);
|
||||
if (arr.length > 100) data = splitBigArr(objToArr(data), id);
|
||||
}
|
||||
map[id] = data;
|
||||
}
|
||||
|
||||
for (let key in data)
|
||||
{
|
||||
let val = data[key];
|
||||
|
||||
if (key === 'erudaObjAbstract' ||
|
||||
key === 'erudaCircular' ||
|
||||
key === 'erudaId' ||
|
||||
(isStr(val) && startWith(val, 'erudaJson'))) continue;
|
||||
|
||||
if (Object.hasOwnProperty.call(data, key)) ret += createEl(key, val, map, firstLevel);
|
||||
if (isObj(val)) createMap(map, val);
|
||||
}
|
||||
}
|
||||
|
||||
function splitBigArr(val, id)
|
||||
{
|
||||
let ret = chunk(val, 100);
|
||||
let idx = 0;
|
||||
ret = map(ret, val =>
|
||||
{
|
||||
let obj = {};
|
||||
let startIdx = idx;
|
||||
obj.erudaObjAbstract = '[' + startIdx;
|
||||
each(val, val =>
|
||||
{
|
||||
obj[idx] = val;
|
||||
idx += 1;
|
||||
});
|
||||
let endIdx = idx - 1;
|
||||
obj.erudaObjAbstract += ((endIdx - startIdx) > 0 ? (' … ' + endIdx) : '') + ']';
|
||||
obj.erudaId = uniqId('erudaJson');
|
||||
obj.erudaSplitArr = true;
|
||||
return obj;
|
||||
});
|
||||
each(val.erudaStrKeys, (val, key) => ret[key] = val);
|
||||
ret.erudaId = id;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function createEl(key, val, map, firstLevel = false)
|
||||
function objToArr(val)
|
||||
{
|
||||
let type = 'object',
|
||||
isUnenumerable = false,
|
||||
id;
|
||||
let ret = [];
|
||||
|
||||
if (key === 'erudaProto') key = '__proto__';
|
||||
if (startWith(key, 'erudaUnenumerable'))
|
||||
let strKeys = {};
|
||||
|
||||
each(val, (val, key) =>
|
||||
{
|
||||
key = trim(key.replace('erudaUnenumerable', ''));
|
||||
isUnenumerable = true;
|
||||
}
|
||||
|
||||
if (isArr(val)) type = 'array';
|
||||
|
||||
function wrapKey(key)
|
||||
{
|
||||
if (firstLevel) return '';
|
||||
|
||||
let keyClass = 'eruda-key';
|
||||
if (isUnenumerable || contain(LIGHTER_KEY, key)) keyClass = 'eruda-key-lighter';
|
||||
|
||||
return `<span class="${keyClass}">${encode(key)}</span>: `;
|
||||
}
|
||||
|
||||
if (val === null)
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-null">null</span>
|
||||
</li>`;
|
||||
}
|
||||
if (isObj(val))
|
||||
{
|
||||
if (val.erudaId)
|
||||
let idx = toNum(key);
|
||||
if (!isNaN(idx))
|
||||
{
|
||||
id = val.erudaId;
|
||||
} else
|
||||
ret[idx] = val;
|
||||
} else
|
||||
{
|
||||
id = uniqId('erudaJson');
|
||||
val.erudaId = id;
|
||||
strKeys[key] = val;
|
||||
}
|
||||
let circularId = val.erudaCircular;
|
||||
if (id) map[id] = val;
|
||||
let objAbstract = val['erudaObjAbstract'] || upperFirst(type);
|
||||
});
|
||||
|
||||
let obj = `<li ${firstLevel ? 'data-first-level="true"' : ''} ${'data-object-id="' + (circularId ? circularId : id) + '"'}>
|
||||
<span class="${firstLevel ? '' : 'eruda-expanded eruda-collapsed'}"></span>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-open">${firstLevel ? '' : objAbstract}</span>
|
||||
<ul class="eruda-${type}" ${firstLevel ? '' : 'style="display:none"'}>`;
|
||||
ret['erudaStrKeys'] = strKeys;
|
||||
|
||||
let jsonHtml = jsonToHtml(val, map);
|
||||
if (firstLevel) obj += jsonHtml;
|
||||
|
||||
return obj + '</ul><span class="eruda-close"></span></li>';
|
||||
}
|
||||
if (isNum(val) || isBool(val))
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-${typeof val}">${encode(val)}</span>
|
||||
</li>`;
|
||||
}
|
||||
if (isStr(val) && startWith(val, 'function'))
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-function">${encode(val).replace('function', '')}</span>
|
||||
</li>`;
|
||||
}
|
||||
if (val === 'undefined' || val === 'Symbol' || val === '(...)')
|
||||
{
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-special">${val}</span>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
return `<li>
|
||||
${wrapKey(key)}
|
||||
<span class="eruda-${typeof val}">"${encode(val)}"</span>
|
||||
</li>`;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const LIGHTER_KEY = ['__proto__'];
|
||||
|
||||
@@ -66,7 +66,7 @@ export default function getAbstract(obj, {
|
||||
{
|
||||
if (i > keyNum)
|
||||
{
|
||||
objEllipsis = ', ...';
|
||||
objEllipsis = ', …';
|
||||
return;
|
||||
}
|
||||
let key = wrapKey(escapeJsonStr(name));
|
||||
@@ -124,7 +124,7 @@ export default function getAbstract(obj, {
|
||||
if (len > 100)
|
||||
{
|
||||
len = 100;
|
||||
arrEllipsis = ', ...';
|
||||
arrEllipsis = ', …';
|
||||
}
|
||||
for (let i = 0; i < len; i++)
|
||||
{
|
||||
@@ -133,7 +133,7 @@ export default function getAbstract(obj, {
|
||||
json += parts.join(', ') + arrEllipsis + ']';
|
||||
} else
|
||||
{
|
||||
json = wrapStr(`Array[${obj.length}]`);
|
||||
json = wrapStr(`Array(${obj.length})`);
|
||||
}
|
||||
} else if (isObj)
|
||||
{
|
||||
@@ -148,10 +148,11 @@ export default function getAbstract(obj, {
|
||||
i = 1;
|
||||
json = '{ ';
|
||||
each(names, objIteratee);
|
||||
json += moveFnToTail(parts).join(', ') + objEllipsis + ' }';
|
||||
json += parts.join(', ') + objEllipsis + ' }';
|
||||
} else
|
||||
{
|
||||
json = getObjType(obj);
|
||||
if (json === 'Object') json = '{…}';
|
||||
}
|
||||
} else if (isNum)
|
||||
{
|
||||
@@ -189,10 +190,11 @@ export default function getAbstract(obj, {
|
||||
json = '{ ';
|
||||
names = unenumerable ? Object.getOwnPropertyNames(obj) : Object.keys(obj);
|
||||
each(names, objIteratee);
|
||||
json += moveFnToTail(parts).join(', ') + objEllipsis + ' }';
|
||||
json += parts.join(', ') + objEllipsis + ' }';
|
||||
} else
|
||||
{
|
||||
json = getObjType(obj);
|
||||
if (json === 'Object') json = '{…}';
|
||||
}
|
||||
} catch (e)
|
||||
{
|
||||
@@ -212,16 +214,3 @@ function canBeProto(obj)
|
||||
|
||||
return emptyObj && proto && proto !== Object.prototype;
|
||||
}
|
||||
|
||||
function moveFnToTail(parts)
|
||||
{
|
||||
let front = [],
|
||||
tail = [];
|
||||
|
||||
each(parts, val =>
|
||||
{
|
||||
val.indexOf('function') > -1 ? tail.push(val) : front.push(val);
|
||||
});
|
||||
|
||||
return front.concat(tail);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
li {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
line-height: 16px;
|
||||
min-height: 16px;
|
||||
}
|
||||
& > li > .key {
|
||||
display: none;
|
||||
@@ -59,14 +61,14 @@
|
||||
position: absolute;
|
||||
border-top-color: $gray;
|
||||
left: -12px;
|
||||
top: 5px;
|
||||
top: 6px;
|
||||
}
|
||||
.collapsed:before {
|
||||
content: "";
|
||||
border-left-color: $gray;
|
||||
border-top-color: transparent;
|
||||
left: -10px;
|
||||
top: 3px;
|
||||
top: 4px;
|
||||
}
|
||||
li .collapsed ~ .close:before {
|
||||
color: #999;
|
||||
|
||||
@@ -281,7 +281,7 @@ function canBeProto(obj)
|
||||
|
||||
function getObjAbstract(obj)
|
||||
{
|
||||
if (isArr(obj)) return `Array[${obj.length}]`;
|
||||
if (isArr(obj)) return `Array(${obj.length})`;
|
||||
if (isFn(obj)) return getFnAbstract(obj);
|
||||
if (isRegExp(obj)) return obj.toString();
|
||||
|
||||
|
||||
@@ -620,6 +620,49 @@ export var kebabCase = _.kebabCase = (function ()
|
||||
return exports;
|
||||
})();
|
||||
|
||||
/* ------------------------------ chunk ------------------------------ */
|
||||
|
||||
export var chunk = _.chunk = (function ()
|
||||
{
|
||||
/* Split array into groups the length of given size.
|
||||
*
|
||||
* |Name |Type |Desc |
|
||||
* |--------|------|--------------------|
|
||||
* |arr |array |Array to process |
|
||||
* |[size=1]|number|Length of each chunk|
|
||||
*
|
||||
* ```javascript
|
||||
* chunk([1, 2, 3, 4], 2); // -> [[1, 2], [3, 4]]
|
||||
* chunk([1, 2, 3, 4], 3); // -> [[1, 2, 3], [4]]
|
||||
* chunk([1, 2, 3, 4]); // -> [[1], [2], [3], [4]]
|
||||
* ```
|
||||
*/
|
||||
|
||||
/* module
|
||||
* env: all
|
||||
* test: all
|
||||
*/
|
||||
|
||||
function exports(arr, size)
|
||||
{
|
||||
var ret = [];
|
||||
|
||||
size = size || 1;
|
||||
|
||||
for (var i = 0, len = Math.ceil(arr.length / size); i < len; i++)
|
||||
{
|
||||
var start = i * size,
|
||||
end = start + size;
|
||||
|
||||
ret.push(arr.slice(start, end));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return exports;
|
||||
})();
|
||||
|
||||
/* ------------------------------ clamp ------------------------------ */
|
||||
|
||||
export var clamp = _.clamp = (function ()
|
||||
|
||||
Reference in New Issue
Block a user