如何进行JS框架搭建
框架是一个项目中很重要的东西,每个后台管理系统都离不开这个,那么今天我们就来讲一下框架是如何进行搭建的。
功能有:树状菜单栏、面包屑、刷新页面、全屏、锁屏
先来看来一下我们分析框架的效果图片
第一步,我们先将框架进行分析布局,左侧为树状才菜单栏的显示位置,右侧则是我们的iframe框架页面显示的位置,
这是右侧iframe框架的链接
树状菜单栏的显示:
我们将左侧树桩菜单栏的样式布局好之后进行获取数据,第一张图左侧就是为渲染好数据的树桩菜单栏,我们看是如何进行实现的,
首先,我们先获取到数据,将获取到的数据进行转换,
// 声明一个数组和brr数组
let arr = []; // 用于存储菜单数据
let tree = [];
let res;
$(document).ready(function () {
//获取数据
$.ajax({
//获取数据链接
url: 'js/ifrom.json',
//获取什么类型的数据
dataType: 'json',
//成功响应
success: function (data) {
//让data等于响应回来的数据
tree.push(data[0]);
res = data;
//让数组等于转换完的数据
arr = tree_menu(data, 0, []);
//获取数组
show_tree(arr);
// 创建一个新的p元素的jQuery对象
var $newParagraph = $("<div class='block'></p>");
// 获取目标div元素(假设它的id是myDiv)
var $targetDiv = $('.treemenu');
// 将新的p元素添加到div元素的末尾
$targetDiv.append($newParagraph);
},
error: function (xhr, status, error) {
// 当请求失败时执行的回调函数
console.error('请求失败:', status, error);
// 可以在这里处理请求失败的情况,例如显示错误信息给用户
}
});
});
//转换数据
function tree_menu(data, pid, arr) { // 定义一个名为 tree_menu 的函数,接收参数 data, pid, arr
//遍历数据
for (let i = 0; i < data.length; i++) {
//判断data下标的pid是否等于pid
if (data[i].pid == pid) {
//用dtat下标的子节点,继续调用函数
data[i].children = tree_menu(data, data[i].id, []);
//把获取到的放入到数组里面
arr.push(data[i]);
}
}
//返回arr
return arr;
}
将数据进行转换后,循环遍历获取到的数据,这里是循环遍历出为父级的数据出来,循环出父级的数据后放入到声明的数组中,然后我们声明一个函数接到这个数组后,进行循环遍历渲染数据,循环遍历渲染数据的时候,进行判断看是否父级下面有对应的二级数据,如果有的话,将二级数据渲染到对应的父级下方,如果没有父级则还是渲染他本身,下方是循环渲染到的实例;
//渲染
function show_tree(arrs) {
//声明一个字符串先写一个大盒子包起来
let str = `<div class="tree_wrap">`;
//遍历数组
for (let i = 0; i < arrs.length; i++) {
//判断它的子级长度大于0
if (arrs[i].children) {
if (arrs[i].children.length > 0) { // 判断子级是否存在
//拼接它本身,拼接子级,通过递归继续判断它的子级
str += `<div class="icon icons"><div><img class="treemenu_img" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div><img class="ico" src="./img/xia.png" alt="" /></div>
<div style="display: none;" class="show tree_wrap">`;
str += show_tree(arrs[i].children);
str += `</div>`;
} else {
if (arrs[i].pid == 0) { // 判断是否是顶级菜单
//拼接它本身
str +=
`<div class="icon" onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" ><div><img class="treemenu_img" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div></div>`;
} else {
str +=
`<div class="icon" onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" ><div class="child"><img class="treemenu_img" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div></div>`;
}
}
} else {
//拼接它本身
str +=
`<div class="icon"><div><img class="treemenu_img" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div></div>`;
}
}
//拼接结束标签
str += `</div>`;
//渲染到页面上
$('.treemenu').html(str);
数据渲染出来之后方便查看那些有二级数据会给有二级数据的父级后面添加显示一个箭头图片,然后添加点击事件,让二级数据进行显示隐藏,并且让图片进行旋转
//下拉框的点击事件
$(document).on('click', '.icons', function () {
//获取子级框架
let children = $(this).next();
//获取图片,过渡1s
$(this).find('.ico').css('transition', 'all 0.5s');
//判断是否显示
if (children.css('display') == 'block') {
//滑出
children.hide(500);
//图片初始化
$(this).find('.ico').css('transform', 'rotate(0deg)');
} else {
//滑入
children.show(500);
//图片旋转180
$(this).find('.ico').css('transform', 'rotate(180deg)');
}
});
这里是存放树状菜单栏的盒子用于显示数据
右侧的框架只需要跟文件名对应就可以显示,我们主要说的是右侧面包屑的显示和高亮显示。
面包屑和高亮显示
我们先声明一个函数用于接收对应的数据 声明一个键名然后进行存储树状菜单栏的名称, 我们声明个函数,用于渲染面包屑使用, 我们先声明两个变量用来获取到存储的值,然后声明字符串用于渲染显示面包屑,然后我们进行循环数组,进行判断数组中的id是否为1 不是1的时候进行拼接渲染,并且将对应的路径也渲染上去。下面要注意!
如果不进行过滤去重,点击左侧名称在面包屑显示的时候会一直显示对应的名称,这时候我们进行去重过滤之后就不会重复显示,我们看是如何实现的
//点击渲染面包屑
// 该函数用于处理面板数据,包括存储标题和路径等信息。
function panel(paneldata, i) { // 定义一个名为 panel 的函数,接收参数 paneldata
// 移除所有菜单项的 icon_click 类
$('.icon').removeClass('icon_click');
//高亮点击事件
if (paneldata.id == 4) {
// 为当前点击的菜单项添加 icon_click 类
$('.icon').eq(3).addClass('icon_click');
} else if (paneldata.id == 6) {
// 为当前点击的菜单项添加 icon_click 类
$('.icon').eq(5).addClass('icon_click');
} else {
// 为当前点击的菜单项添加 icon_click 类
$('.icon').eq(i).addClass('icon_click');
}
sessionStorage.setItem('title', paneldata.title) // 将 paneldata 的标题存储到 sessionStorage 中,键为 'title'
if (JSON.stringify(tree).indexOf(JSON.stringify(paneldata.id)) == -1) { // 判断 tree 中是否包含 paneldata,如果不包含则继续
tree.push(paneldata); // 将 paneldata 添加到 tree 数组中
}
let redirect = sessionStorage.setItem('redirect', paneldata.path); // 将 paneldata 的路径存储到 临时存储中,键名为 'redirect'
$('#font').html(paneldata.title); // 使用 jQuery 将 DOM 元素 #font 的 HTML 内容设置为 paneldata 的标题
$('#iframe').attr('src', `./${paneldata.path}.html`); // 设置 DOM 元素 #iframe 的 src 属性为 paneldata.path 对应的 HTML 文件路径
apple(tree); // 调用 apple 函数,并将 tree 作为参数传入
}
//渲染
function apple(data) {
let name = sessionStorage.getItem('title'); // 获取 sessionStorage 中存储的标题
let redirect = sessionStorage.getItem('redirect'); // 获取 sessionStorage 中存储的路径
let str = ``; // 声明一个字符串变量,用于拼接面包屑导航栏
for (let i = 0; i < data.length; i++) { // 遍历 tree 数组
if (data[i].id != 1) { // 如果 tree 数组的 id 不是 1
str +=
`<div class="pagees" onclick="crumb(${JSON.stringify(data[i]).replace(/\"/g, "'")})" style="background-color:${data[i].title == name ? '#ecf5ff' : ''}; color:${data[i].title == name ? '#5ca9ff' : ''}; "><div >${tree[i].title}</div>
<img onclick="clears(${JSON.stringify(data[i]).replace(/\"/g, "'")})" src="./img/chahao.png" alt="" /> </div>`
$('iframe').attr('src', `./${redirect}.html`); // 设置 iframe 的 src 属性为 redirect 对应的 HTML 文件路径
$('.pages').css({ // 设置 pages 元素的 CSS 样式
'color': 'black',
'border-bottom': "none",
'background-color': 'white'
});
}
}
if (name == arr[0].title || tree.length == []) { // 判断条件,如果 name 等于 arr 数组第一个元素的 title 或 tree 数组的长度为0
for (let i = 0; i < res.length; i++) { // 遍历 res 数组
if ($('.icon').eq(i).text() == name) { // 检查当前图标的文本是否等于 name
$('.icon').removeClass('icon_click'); // 移除所有图标的点击状态样式
$('.icon').eq(i).addClass('icon_click'); // 为当前匹配的图标添加点击状态样式
$('iframe').attr('src', `./${tree[i].path}.html`); // 设置 iframe 的 src 属性为 tree 数组对应路径的 HTML 文件
}
}
$('#font').html(name); // 将 font 元素的 HTML 内容设置为 name
$('.pages').css({ // 设置 pages 元素的 CSS 样式
'color': ' #5ca9ff', // 设置文本颜色
'background-color': '#ecf5ff', // 设置背景颜色
});
}
$('.navigation')[0].html(str); // 将导航栏的 HTML 内容设置为 str
}
function tree_hover(arrs) {
//声明一个字符串先写一个大盒子包起来
let str = `<div class="tree_wrap">`;
let name = localStorage.getItem('name');
//遍历数组
for (let i = 0; i < arrs.length; i++) {
//判断它的子级长度大于0
if (arrs[i].children) {
if (arrs[i].children.length > 0) {
//拼接它本身,拼接子级,通过递归继续判断它的子级
str += `<div class="icon icons">${arrs[i].title}<img class="ico" src="./img/jiantou.png" alt="" /></div>
<div style="display: none;" class="show">`;
str += tree_hover(arrs[i].children);
str += `</div>`;
} else {
if (arrs[i].pid == 0) {
//拼接它本身
str +=
`<div class="icon" onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" ><img class="treemenu_image" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div>`;
} else {
str +=
`<div class="icon" onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" >${arrs[i].title}</div>`;
}
}
} else {
//拼接它本身
str +=
`<div class="icon"><img class="treemenu_image" src="${arrs[i].icon}" alt="" />${arrs[i].title}</div>`;
}
}
//拼接结束标签
str += `</div>`;
//渲染到页面上
$('.treeicon').html(str);
//返回字符串
return str;
}
let p = 2; // 定义变量 p,初始值为 2
function flexible() { // 定义函数 flexible
// 点击管理图片切换只显示图片状态
if (p === 1) { // 如果 p 的值为 1
$('.background').css('display', 'block'); // 显示背景元素
$('.backgrounds').css('display', 'none'); // 隐藏背景图元素
$('.framework').css('width', '87.5%'); // 设置框架的宽度为 87.5%
show_tree(arr); // 调用 show_tree 函数,传入 arr
p = 2; // 将 p 的值设置为 2
} else { // 如果 p 的值不是 1
$('.background').css('display', 'none'); // 隐藏背景元素
$('.backgrounds').css('display', 'block'); // 显示背景图元素
$('.framework').css('width', '96%'); // 设置框架的宽度为 96%
let arrs = []; // 定义一个空数组 arrs
arrs = arr; // 将 arr 的值赋给 arrs
let str = `<div class="tree_wraps">`; // 初始化字符串 str,为树状图的包装 div
let name = localStorage.getItem('name'); // 从 localStorage 获取 'name' 的值
for (let i = 0; i < arrs.length; i++) { // 遍历 arrs 数组
if (arrs[i].children && arrs[i].children.length > 0) { // 如果当前元素有子元素
str += `<div class="icones icos icons">` +
`<div ><img class="treemenu_image" title="${arrs[i].title}" src="${arrs[i].icon}" alt="" /></div>` +
`<div class=" icon_text" >`; // 添加文本容器
str += show_treeto(arrs[i].children); // 调用 show_treeto 函数,处理子元素
str += `</div></div>`; // 关闭 div 标签
} else { // 如果当前元素没有子元素
str += `<div class="icones " onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})">` + // 创建可点击的 div,并传入当前元素的 JSON 字符串
`<img class="treemenu_image" title="${arrs[i].title}" src="${arrs[i].icon}" alt="" />` +
`<div class="icon_text">${arrs[i].title}</div>` + // 添加标题文本
`</div>`; // 关闭 div 标签
}
}
str += `</div>`; // 关闭树状图的包装 div
$('.treemenus').html(str); // 将生成的 HTML 字符串插入到 treemenus 元素中
p = 1; // 将 p 的值设置为 1
}
}
//渲染
function show_treeto(arrs) {
//声明一个字符串先写一个大盒子包起来
let str = `<div class="tree_wraps">`;
let name = localStorage.getItem('name'); // 从 localStorage 获取 'name' 的值
//遍历数组
for (let i = 0; i < arrs.length; i++) {
//判断它的子级长度大于0
if (arrs[i].children) {
if (arrs[i].children.length > 0) { //判断是否有子级
//拼接它本身,拼接子级,通过递归继续判断它的子级
str += `<div class=" icons"><img class="treemenu_image" src="./img/${arrs[i].icon}.png" alt="" />${arrs[i].title}<img class="ico" src="./img/jiantou.png" alt="" /></div>
<div style="display: none;" class="show">`;
str += show_treeto(arrs[i].children);
str += `</div>`;
} else {
if (arrs[i].pid == 0) {
//拼接它本身
str +=
`<div onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" ><img src="./img/${arrs[i].icon}.png" alt="" />${arrs[i].title}</div>`;
} else {
str +=
`<div class="icos" onclick="panel(${JSON.stringify(arrs[i]).replace(/\"/g, "'")},${i})" >${arrs[i].title}</div>`;
}
}
}
}
//拼接结束标签
str += `</div>`;
//渲染到页面上
$('.treemenu').html(str);
//返回字符串
return str;
}
这里只是将面包屑进行了正确的渲染显示,但是并没有去添加高亮,不添加高亮当用户点击的页面多了,就会不知道自己在哪个页面,这时候我们要给面包屑添加高亮让面包屑和树状菜单栏的高亮相对应。
我们先声明一个变量用于接取数据, 然后我们将对应的名字进行一个存储,然后我们进行循环数组的长度进行判断我们存储的数据ID是否等于数据中的ID,ID对应了就直接添加样式 并且显示高亮
//点击面包屑显示高亮
function crumb(data) {
// 将传入的数据标题存储到本地存储中,键为'name'
localStorage.setItem('name', data.title);
// 遍历数组res
for (let i = 0; i < res.length; i++) {
// 如果数据ID不是17
if (data.id != 17) {
// 找到与传入数据ID匹配的项
if (res[i].id == data.id) {
// 更新页面中的字体信息为数据标题
$('#font').html(data.title);
// 将iframe的源路径设置为匹配项的路径
$('iframe').attr('src', `./${res[i].path}.html`);
}
} else {
// 如果ID为17,设置标题为“个人信息”
$('#font').html("个人信息");
// 将iframe的源路径设置为个人信息页面
$('iframe').attr('src', `./individual.html`);
}
}
// 遍历icon元素
for (let i = 0; i < res.length; i++) {
// 如果当前icon的文本与数据标题匹配
if ($('.icon').eq(i).text() == data.title) {
// 移除所有icon的点击样式
$('.icon').removeClass('icon_click');
// 给当前匹配的icon添加点击样式
$('.icon').eq(i).addClass('icon_click');
}
}
// 遍历数组brr
for (let i = 0; i < tree.length; i++) {
// 如果brr中的ID与数据ID匹配
if (tree[i].id == data.id) {
// 设置页面的样式
$('.pages').css({
'color': 'black',
'border-bottom': "none",
'background-color': 'white'
});
// 移除所有pagees的样式
$('.pagees').removeAttr('style');
$('.pagees').removeClass('crumbs');
// 给前一个元素添加crumbs类
$('.pagees').eq(i - 1).addClass('crumbs');
}
}
}
既然有添加面包屑,对应的我们也要删除面包屑,在删除对应的面包屑的时候让他跳转到别的面包屑并且显示对应的页。
首先我们声明一个函数接取数据后,循环遍历存储面包屑的那个数组,判断存储面包屑中对应页面的id是否是数据中的id,如果为想等的id,循环找到对应的id之后将对应的名称和路径进行删除,删除过后,进行一个判断当存储面包屑的长度大于 0,当进行删除面包屑后,如果有别的面包屑,将让他跳转到最后一个面包屑上并且显示出对应的页面和高亮
//点击删除面包屑按钮
function clears(data) {
event.stopPropagation(); // 阻止事件冒泡
for (let i = 0; i < tree.length; i++) { // 遍历 tree 数组
if (tree[i].id == data.id) { // 如果 tree 数组的 id 等于 data 的 id
tree.splice(i, 1); // 从 tree 数组中删除该元素
sessionStorage.setItem('title', tree[tree.length - 1].title); // 将 tree 数组的最后一个元素的标题存储到 sessionStorage 中,键名为 'title'
sessionStorage.setItem('redirect', tree[tree.length - 1].path); // 将 tree 数组的最后一个元素的路径存储到 sessionStorage 中,键名为 'redirect'
}
}
apple(tree); // 调用 apple 函数,并将 tree 作为参数传入
let titleToFind = tree[tree.length - 1].title; // 获取 tree 数组的最后一个元素的标题
$('.icon').removeClass('icon_click'); // 移除所有菜单项的 icon_click 类
$('.icon').each(function () { // 遍历菜单项
if ($(this).text() === titleToFind) { // 如果菜单项的文本内容等于要查找的标题
// 为找到的菜单项添加 icon_click 类
$(this).addClass('icon_click');
}
});
// 修改导航栏文字
if (tree.length > 0) { // 如果 tree 数组的长度大于 0
$('#font').html(tree[tree.length - 1].title); // 将 tree 数组的最后一个元素的标题设置到 #font 元素的 HTML 内容中
} else { // 如果 tree 数组的长度等于 0
$('#font').html(tree[0].title); // 将 tree 数组的第一个元素的标题设置到 #font 元素的 HTML 内容中
}
$('.my_information_box').hide(); // 隐藏个人信息框
$('.information_box').hide(); // 隐藏信息框
$('#infos').css({ // 设置信息框的样式
"color": "",
"background-color": ""
});
selfs = 0; // 重置自身变量
infor = 0; // 重置信息变量
$('#info').css({ // 设置信息框的样式
"color": "",
"background-color": ""
});
}
这样一个框架的基本都已经出来了,
我们接下来说一下框架中所用到的功能。
第一个为全屏功能:
首先,我们给全屏按钮添加一个点击事件,然后定义一个函数用于显示全屏,我们进行判断当前的状态是否是全屏状态,当我们点击全屏的时候,直接请求全屏模式的函数,当我们在全屏的时候再次点击全屏按钮,判断是否支持退出全屏,支持后,我们调用退出全屏的方法。
// 全屏功能
function toggleFullScreen() { // 定义一个函数,用于切换全屏模式
if (!document.fullscreenElement) { // 检查当前文档是否已经进入全屏模式
// 进入全屏
document.documentElement.requestFullscreen(); // 请求全屏模式,针对文档的根元素
} else {
// 退出全屏
if (document.exitFullscreen) { // 检查浏览器是否支持退出全屏的方法
document.exitFullscreen(); // 调用退出全屏的方法
}
}
}
// 绑定一个按钮点击事件来触发全屏功能
document.getElementById('full_screen').addEventListener('click', toggleFullScreen); // 为ID为'blowup'的按钮添加点击事件监听器,点击按钮时调用toggleFullScreen函数
然后是刷新功能。
我们给刷新按钮添加一个点击事件,然后获取到iframe对应的src路径
function refreshPage() {
// 刷新iframe的链接,通过重新设置src属性来实现
$('iframe').attr('src', $('iframe').attr('src'));
// 阻止事件的默认行为和冒泡(如果有事件对象event时)
event.preventDefault(); // 阻止默认行为
event.stopPropagation(); // 阻止事件冒泡
}
最后是锁屏功能,
我们给锁屏添加点击事件让他进入到锁屏页面,这里要做一个判断,点击浏览器的返回箭头的时候让他禁止返回上一页,接下里我们给解锁按钮添加点击事件,获取到我们存储的登录密码进行判断,当他不等于我们的密码时进行弹窗提醒用户,当等于我们的密码的时候跳回到我们的页面
function lockhiode() {
// 检查密码输入框是否为空
if ($("#password").val() == "") {
// 弹出提示:请填写密码
showPopup("请填写密码", '#f44336', '#ffebee', '#f44336');
return;
// 判断密码格式是否错误
} else if ($('#password').val().length < 6 || $('#password').val().length > 18) {
// 弹出提示:密码格式错误
showPopup("密码格式错误", '#f44336', '#ffebee', '#f44336');
return;
} else if ($('#password').val() != localStorage.getItem('code')) {
// 弹出提示:密码错误
showPopup("密码错误", '#f44336', '#ffebee', '#f44336');
return;
} else {
// 弹出提示:解锁成功
showPopup("解锁成功", '#4caf50', '#e8f5e9', '#4caf50');
// 设置定时器,1秒后隐藏锁定框并清空密码输入框
setTimeout(function () {
$('.lock_box').hide();
$('#password').val("");
}, 1000);
}
// 设置定时器
}
// 添加回车事件监听
$(document).on('keydown', function (e) {
if (e.key === "Enter") {
// 当按下回车键时,调用lockhiode函数
lockhiode();
}
});
// 禁止用户返回上一页
window.onpopstate = function (event) {
// 将当前状态推入历史记录,防止返回
history.pushState(null, document.title, location.href);
};