MENU
- web前端之原生实现分时函数、分时间段渲染页面,而不是等到所有操作都执行结束才渲染页面、提高用户体验
- web前端之原生实现树形目录结构、一维数组生成多维数组、无限级菜单目录
web前端之原生实现分时函数、分时间段渲染页面,而不是等到所有操作都执行结束才渲染页面、提高用户体验
前言
当前需要向页面插入十万个div元素,如果使用普通的渲染方式,会造成延迟。这时候就需要通过分时函数来实现渲染了。
html
<div class="w_680 d_f jc_sb"><div class="d_f fd_c ai_c"><button onclick="handleInsert()">插入1万个元素(原始写法)</button><div id="idOld"></div></div><div class="d_f fd_c ai_c"><button onclick="handleOptimize()">插入1万个元素(优化后的写法)</button><div id="idOptimize"></div></div>
</div>
原始写法
function handleInsert() {let idOld = document.querySelector('#idOld'),datas = Array.from({ length: 100000 }, (_, i) => i + 1);for (const item of datas) {const div = document.createElement('div');div.textContent = item;idOld.appendChild(div);}
}
优化方式一(参数归一化)
function handleOptimize() {let datas = Array.from({ length: 100000 }, (_, i) => i + 1),idOptimize = document.querySelector('#idOptimize'),taskHandler = (item, i) => {const div = document.createElement('div');div.textContent = item;idOptimize.appendChild(div);};performChunk(datas, taskHandler);// performChunk(100000, taskHandler);
}function performChunk(datas, taskHandler) {// 参数归一化if (typeof datas === 'number') datas = Array.from({ length: datas }, (_, i) => i + 1);if (datas.length === 0) return false;let i = 0;function _run() {if (i >= datas.length) return false;requestIdleCallback((idle) => {while (idle.timeRemaining() > 0 && i < datas.length) {taskHandler(datas[i], i);i++;}_run();});}_run();
}
优化方式二(当浏览器不支持requestIdleCallback方法的时候)
function handleOptimize() {let datas = Array.from({ length: 100000 }, (_, i) => i + 1),idOptimize = document.querySelector('#idOptimize'),taskHandler = (item, i) => {const div = document.createElement('div');div.textContent = item;idOptimize.appendChild(div);},scheduler = (task) => {setTimeout(() => {const start = Date.now();task(() => Date.now() - start < 50);}, 100);};performChunk(datas, taskHandler, scheduler);
}function performChunk(datas, taskHandler, scheduler) {if (typeof datas === 'number') datas = Array.from({ length: datas }, (_, i) => i + 1);if (datas.length === 0) return false;let i = 0;function _run() {if (i >= datas.length) return false;scheduler((isGoOn) => {while (isGoOn() > 0 && i < datas.length) {taskHandler(datas[i], i);i++;}_run();});}_run();
}
优化方式三(判断环境)
function handleOptimize() {let datas = Array.from({ length: 100000 }, (_, i) => i + 1),idOptimize = document.querySelector('#idOptimize'),taskHandler = (item, i) => {const div = document.createElement('div');div.textContent = item;idOptimize.appendChild(div);}browserPerformChunk(datas, taskHandler);
}function browserPerformChunk(datas, taskHandler) {const scheduler = (task) => {requestIdleCallback((idle) => {task(() => idle.timeRemaining() > 0);})};performChunk(datas, taskHandler, scheduler);
}function performChunk(datas, taskHandler, scheduler) {if (typeof datas === 'number') datas = Array.from({ length: datas }, (_, i) => i + 1);if (datas.length === 0) return false;let i = 0;function _run() {if (i >= datas.length) return false;scheduler((isGoOn) => {while (isGoOn() > 0 && i < datas.length) {taskHandler(datas[i], i);i++;}_run();});}_run();
}
解析
待定…
web前端之原生实现树形目录结构、一维数组生成多维数组、无限级菜单目录
html
<div id="menuBox"></div>
JavaScript
mainInit();// 数据处理
// 扁平数组结构转换成JSON树形结构
function mainInit() {// 源数据let data = [{ id: 5, parentId: 2, name: "目录1-1-1", },{ id: 1, parentId: 0, name: "目录1", },{ id: 13, parentId: 9, name: "目录2-2-3", },{ id: 3, parentId: 1, name: "目录1-2", },{ id: 2, parentId: 1, name: "目录1-1", },{ id: 12, parentId: 9, name: "目录2-2-2", },{ id: 4, parentId: 1, name: "目录1-3", },{ id: 7, parentId: 0, name: "目录2", },{ id: 9, parentId: 7, name: "目录2-2", },{ id: 6, parentId: 2, name: "目录1-1-2", },{ id: 11, parentId: 9, name: "目录2-2-1", },{ id: 8, parentId: 7, name: "目录2-1", },{ id: 10, parentId: 7, name: "目录2-3", },];// 构造一个新对象// 对象的属性名是id值// 对象的属性值是数组对应项的值let map = {};data.forEach(item => {map[item.id] = item;});const result = [];data.forEach(item => {const parent = map[item.parentId];if (parent) {// 如果有children则push数据到children中// 如果没有就新建一个空的children数组// 然后再push数据parent.children = parent.children || [];parent.children.push(item);} else {// 在本例中// else只会进入两次// 也是最外层目录result.push(item);}});const root = document.getElementById('menuBox');createMenu(result, root);
}// 生成标签元素
function createMenu(data, root) {if (!data.length) throw new Error('出错啦');data.forEach(item => {const detailsEle = document.createElement('details');const summaryEle = document.createElement('summary');const span = document.createElement('span');span.innerHTML = item.name;summaryEle.appendChild(span);detailsEle.appendChild(summaryEle);root.appendChild(detailsEle);if (item.children?.length) createMenu(item.children, detailsEle);});
}
CSS
null