后台UI框架开发(一)

article/2025/9/2 9:05:48

后台UI框架开发(一)

众所周知,现在的后台管理系统的前端页面基本上都是一个样子……

在这里插入图片描述

那既然,每个后台管理页面的样子都是这样的,那我们能不能设计一个页面,专门写成这个样子,只需要以面向对象的方式去使用某些方法来修改标题、快捷菜单、功能菜单、导航菜单……

整体设计

我们直接来套用一下Vue的目录结构:

  • src
    • api
      • index.js
    • router
      • index.js
  • static
  • pages
    • styles
    • scripts
    • simple1.html
    • simple2.html
    • child1.html
    • child2.html
    • child3.html
    • child4.html
    • child5.html
    • child6.html
  • index.html
  • main.js

然后我们看一下每一个目录/文件都是干什么的。

目录:src/api/index.js

const host = "http://example.com";
const request = {doGet: (url, data, func) => {let ajax = new XMLHttpRequest();let params = "";for (let param in data) {params = params + param + "=" + data[param] + "&";}params = params.substr(0, params.length - 1);ajax.open('GET', host + url + "?" + params);ajax.send();ajax.onreadystatechange = function() {if (ajax.readyState == 4 && ajax.status == 200) {let json = JSON.parse(ajax.responseText);func(json);}}},doPost: (url, data, func) => {let ajax = new XMLHttpRequest();ajax.open("POST", host + url, true);ajax.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');let params = "";for (let param in data) {params = params + param + "=" + data[param] + "&";}ajax.send(params);ajax.onreadystatechange = function() {if (ajax.readyState == 4 && ajax.status == 200) {let json = JSON.parse(ajax.responseText);func(json);}}}
};
const userApi = {userReg: (params, func) => request.doPost("/userApi/userReg", params, func),// 用户注册userLogin: (params, func) => request.doPost("/userApi/userLogin", params, func),// 用户登录
};

目录:src/router/index.js

const routes = [{name:"下拉标题1",children:[{to:"/child1",name:"子级菜单1",path:"/child1.html"},{to:"/child2",name:"子级菜单2",path:"/child2.html"},{to:"/child3",name:"子级菜单3",path:"/child3.html"},]},{name:"下拉标题2",children:[{to:"/child4",name:"子级菜单4",path:"/child4.html"},{to:"/child5",name:"子级菜单5",path:"/child5.html"},{to:"/child6",name:"子级菜单6",path:"/child6.html"},]},{to:"/simple1",name:"简单导航1",path:"/simple1.html"},{to:"/simple2",name:"简单导航2",path:"/simple2.html"},
]

然后我们编写一下,这个后台页面

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title></title><link rel="stylesheet" type="text/css" href="css/main.css"/></head><body><div class="box"><div class="header-box"><div class="logo-box"><div class="logo">logo站位</div></div><div class="tool-box"><div class="control-box"></div><div class="info-box"></div></div></div><div class="content-box"><div class="nav-box"></div><div class="main-box"><object class="frame" id="obj" data="" type="text/html"></object></div></div></div></body><script src="src/router/index.js" type="text/javascript" charset="utf-8"></script><script src="main.js" type="text/javascript" charset="utf-8"></script>
</html>

现在介绍一下各个class对应的元素的意义:

  • box:包围盒

    • header-box:头部包围盒

      • logo-box:Logo包围盒
      • logo:Logo站位
      • tool-box:快捷导航包围盒
        • control-box:控制器包围盒
        • info-box:信息包围盒
    • content-box:主体包围盒

      • nav-box:导航菜单包围盒
      • main-box:主体内容包围盒
        • frame:类似于“iframe”一样的产物,进行页面内部跳转

然后我们需要构思,如何能够直接通过router/index.js中的数据来直接生成导航菜单呢

js献上

// 生成导航菜单
const navBox = document.querySelector(".nav-box");
// 获取导航菜单包围盒
routes.forEach(item => {if (!item.children) {// 简单导航let simple = document.createElement("div");simple.classList.add("simple-nav");simple.innerHTML = "<i class='icon'></i><span>" + item.name + "</span>";simple.dataset.to = item.to;navBox.appendChild(simple);} else {// 下拉菜单let multip = document.createElement("dl");multip.classList.add("nav-list");let dt = document.createElement("dt");dt.innerHTML = "<i class='icon'></i><span>" + item.name + "</span>";navBox.appendChild(multip);multip.appendChild(dt);item.children.forEach(child => {let dd = document.createElement("dd");dd.classList.add("multip");dd.innerHTML = "<span>" + child.name + "</span>";dd.dataset.to = child.to;multip.appendChild(dd);});}
});
// 这个操作,应该所有人都看得懂吧,我就不多于陈述了。// 菜单添加效果
const navLists = document.querySelectorAll(".nav-list>dt");
// 我们首先要把所有的下拉菜单取出
const clearElementsClass = (doms, className) => {doms.forEach(item => {item.classList.remove(className);});
};
// 定义一个方法,可以将"NodeList"中的所有元素的某一个className删除
const clearElementParentsClass = (doms, className) => {doms.forEach(item => {item.parentNode.classList.remove(className);});
};
// 定义一个方法,可以将"NodeList"中的所有元素的父级元素的某一个className删除
navLists.forEach(item => {item.addEventListener("click", e => {clearElementParentsClass(navLists, "active");item.parentNode.classList.add("active");});
});
// 现在来遍历所有的下拉菜单,清除所有下拉菜单中的"active"类,并为当前鼠标单击行添加"active"类,这里是实现效果
let martJokes = document.querySelectorAll(".multip");
// 获取所有的下拉菜单项
let coverJokes = document.querySelectorAll(".simple-nav");
// 获取所有的简单导航项
const clearJokesClass = () => {martJokes.forEach(item => {item.classList.remove("ajok");});coverJokes.forEach(item => {item.classList.remove("ajok");});
};
// 定义一个方法,可以清除掉下拉菜单项和简单导航项的"ajok"类
martJokes.forEach(item => {item.addEventListener("click", e => {clearJokesClass();item.classList.add("ajok");});
});
coverJokes.forEach(item => {item.addEventListener("click", e => {clearJokesClass();item.classList.add("ajok");});
});
// 和上面清除"active"类效果一样,清除"ajok"类,并为当前鼠标单击项添加"ajok"

至此,我们想要实现的效果就已经完成了。

那么接下来,我们就要考虑,如何在鼠标点击导航项之后,让“#obj”的内联框架进行跳转了。

js献上

const links = document.querySelectorAll("[data-to]");
// 现将上面操作中所有含有dataset.to的项取出。
const frame = document.querySelector("#obj");
// 再将内联框架取出。
const foundPath = itemTo => {let path = "";routes.forEach(item => {if (!item.children) {if (item.to == itemTo) {path = "pages" + item.path;}} else {item.children.forEach(child => {if (child.to == itemTo) {path = "pages" + child.path;}});}});return path;
};
// 定义方法,检索每个"to"所对应的"path"
links.forEach(item => {item.addEventListener("click", e => {frame.data = foundPath(item.dataset.to);});
});
// 为每个导航菜单项添加一个单击事件监听,通过标签上的"data-to"找到对应的"path",并让内联框架进行跳转。

这样一来,基本的模型就设计完成了。

但是,我们文章开头时说过,要进行面向对象的操作,也就是XXX.setXXX()和XXX.getXXX()来进行操作,但是现在并未拥有这个能力,这该怎么搞呢?

现在,我们拥有三种方法:

  • 类似于JQuery一样,去修改某些模型的“prototype”原型及原型链
  • 定义一个class直接在class中定义方法进行操作
  • 定义一个对象,在对象中定义方法进行操作,其实这个和第二个一样,但是方便呀,所以,我们暂且称之为第三种方法,并且,我们就选择这种方法了。

既然如此,我们要将上面的js合并到一个对象中去了,js献上

const martApp = {// init nav-list.startApp:()=>{const navLists = document.querySelectorAll(".nav-list>dt");const clearElementsClass = (doms,className) =>{doms.forEach(item=>{item.classList.remove(className);});};const clearElementParentsClass = (doms,className) =>{doms.forEach(item=>{item.parentNode.classList.remove(className);});};navLists.forEach(item=>{item.addEventListener("click",e=>{clearElementParentsClass(navLists,"active");item.parentNode.classList.add("active");});});let martJokes = document.querySelectorAll(".multip");let coverJokes = document.querySelectorAll(".simple-nav");const clearJokesClass = () => {martJokes.forEach(item=>{item.classList.remove("ajok");});coverJokes.forEach(item=>{item.classList.remove("ajok");});};martJokes.forEach(item=>{item.addEventListener("click",e=>{clearJokesClass();item.classList.add("ajok");});});coverJokes.forEach(item=>{item.addEventListener("click",e=>{clearJokesClass();item.classList.add("ajok");});});},initNavList:()=>{const navBox = document.querySelector(".nav-box");routes.forEach(item=>{if(!item.children){// 简单导航let simple = document.createElement("div");simple.classList.add("simple-nav");simple.innerHTML="<i class='icon'></i><span>" + item.name + "</span>";simple.dataset.to = item.to;navBox.appendChild(simple);}else{// 下拉菜单let multip = document.createElement("dl");multip.classList.add("nav-list");let dt = document.createElement("dt");dt.innerHTML = "<i class='icon'></i><span>" + item.name + "</span>";navBox.appendChild(multip);multip.appendChild(dt);item.children.forEach(child=>{let dd = document.createElement("dd");dd.classList.add("multip");dd.innerHTML = "<span>" + child.name + "</span>";dd.dataset.to = child.to;multip.appendChild(dd);});}});},style:{setLogoBgColor:color=>{document.querySelector(".logo-box").style["backgroundColor"] = color;}},initRoutes:()=>{const links = document.querySelectorAll("[data-to]");const frame = document.querySelector("#obj");const foundPath = itemTo => {let path = "";routes.forEach(item=>{if(!item.children){if(item.to==itemTo){path = "pages" + item.path;}}else{item.children.forEach(child=>{if(child.to==itemTo){path = "pages" + child.path;}});}});return path;};links.forEach(item=>{item.addEventListener("click",e=>{frame.data = foundPath(item.dataset.to);});});}
}

我这个写的有点乱,但是,我们可以清晰的看到,如果想要调整某部分的样式,例如:Logo的背景颜色,我们只需要在script标签中这样写:

martApp.style.setLogoBgColor("#012345");

因为我们这个是初步的模型,所以,我们没有编写那么多的方法,以后会完善的,现在我们看一下初步的执行顺序:

martApp.initNavList();
martApp.initRoutes()
martApp.startApp();

这样,我们的页面就跑起来了,但是,好像忘记一个重点,没有样式呀!

css献上,因为东西都简单,所以就不适用预处理css了,大伙将就着看。

*{margin: 0;padding: 0;box-sizing: border-box;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;font-family: "comic sans ms","microsoft yahei";
}
body{width: 100vw;height: 100vh;background-color: #F0F0F0;
}
.box{width: 100%;height: 100%;
}
.header-box{width: 100%;height: 60px;display: flex;box-shadow: 0 5px 10px rgba(0,0,0,.5);background-color: #FFFFFF;
}
.logo-box{width: 200px;height: 100%;background-color: #002548;padding: 16px 28px;
}
.logo{width: 100%;height: 100%;background-color: rgba(255,255,255,.2);display: flex;align-items: center;justify-content: center;color: #FFFFFF;
}
.tool-box{width: calc(100% - 200px);height: 100%;display: flex;align-items: center;justify-content: space-between;padding: 0 24px;
}
.control-box{height: 48px;
}
.info-box{height: 48px;
}
.content-box{width: 100%;height: calc(100% - 60px);display: flex;
}
.nav-box{width: 200px;height: 100%;background-color: #002548;
}
dl.nav-list{width: 100%;height: auto;
}
dl.nav-list>dt{width: 100%;height: 40px;color: rgba(255,255,255,.65);font-size: 14px;display: flex;align-items: center;padding: 0 34px 0 24px;transition-duration: .3s;cursor: pointer;
}
dl.nav-list>dt>i.icon{display: flex;align-items: center;justify-content: center;width: 14px;height: 14px;font-size: 14px;margin-right: 10px;
}
dl.nav-list>dt:hover{color: #FFFFFF;
}
dl.nav-list.active>dt{color: #FFFFFF;
}
dl.nav-list>dd{width: 100%;height: 0;overflow: hidden;font-size: 14px;color: rgba(255,255,255,.65);display: flex;align-items: center;padding: 0 16px 0 48px;background-color: #000000;transition-duration: .3s;cursor: pointer;
}
dl.nav-list.active>dd{height: 40px;
}
dl.nav-list.active>dd:hover{color: #FFFFFF;
}
dl.nav-list.active>dd.ajok{background-color: #1890ff;color: #FFFFFF;
}
.simple-nav{width: 100%;height: 40px;font-size: 14px;display: flex;align-items: center;padding: 0 34px 0 24px;transition-duration: .3s;cursor: pointer;color: rgba(255,255,255,.65);
}
.simple-nav>i.icon{display: flex;align-items: center;justify-content: center;width: 14px;height: 14px;font-size: 14px;margin-right: 10px;
}
.simple-nav:hover{color: #FFFFFF;
}
.simple-nav.ajok{background-color: #1890ff;color: #FFFFFF;
}
.main-box{width: calc(100% - 200px);height: 100%;padding: 12px 24px;
}
.frame{width: 100%;height: 100%;background-color: #FFFFFF;box-shadow: 0 5px 10px rgba(0,0,0,.5);
}

效果图奉上:

在这里插入图片描述

本篇文章就先到这里,如果有什么建议,请在评论区留言,大神们勿喷,这是自己想法的一个实践。

接下来会去封装组件,配合后台去写傻瓜式组件!

感谢您的阅读,下期见!!!


http://chatgpt.dhexx.cn/article/rPyRZpFb.shtml

相关文章

开箱即用的后台UI框架eui(原eadmin)

&#xff08;很多人问有没有开箱即用&#xff0c;不需要复杂打包环境配置的功能强大、界面精美的后台UI框架&#xff0c;现在他来了&#xff09; eui 基于原生JS开发&#xff0c;开箱即用&#xff0c;无需打包环境&#xff0c;专门为不太熟悉mvvm开发模式的人员定制打造。此次…

国内主流在用的10大后台UI框架,私活必备

目录 vue-Element-Admin AdminLTE ant-design-pro tabler ng2-admin Gentelella iview-admin blur-admin vue-admin material-dashboard 前任何企业在开发的过程中&#xff0c;都摆脱不了管理后台的开发需要。 如果一切从0开始&#xff0c;费时费力&#xff0c;而且…

解决xshell无限窗口方法

解决xshell无限窗口方法 百度10分钟&#xff0c;群里吹逼2两小时纸上得来终觉浅,绝知此事要躬行解决xshell-"要继续使用此程序,您必须应用最新的更新或使用新版本"的问题解决xshell-无限窗口的问题 百度10分钟&#xff0c;群里吹逼2两小时 今天xshell突然提示“要继…

正版Xshell+Xftp免费使用,你还在找破解版吗

想必很多人都和阿福一样使用一款软件&#xff0c;先是去官网下载。用了一段时间后提示要付费就直接搜破解版接着用。 今天我的Xshell就到期了&#xff0c;笔记本还是裸奔状态&#xff0c;下载的破解版报毒不敢用&#xff0c;用习惯的软件也不想说换就换&#xff0c;怎么办&…

Finalshell安全吗?Xshell怎么样?

文章目录 一、我的常用ssh连接工具二、Xshell2.1 下载&#xff1a;认准官网2.2 Xshell 配置2.3 Xftp和WinSCP 一、我的常用ssh连接工具 之前讲过&#xff1a; 【服务器】远程连接选SSH&#xff08;PUTTY、Finalshell、WinSCP&#xff09; 还是 远程桌面&#xff08;RDP、VNC、…

【XShell】安装免费版XShell

该文章书写时间&#xff1a;2023年4月18日 最新一次修改&#xff1a;2023年4月19日 目录 一、下载XShell的目的 为什么配置环境需求需要Xshell 为什么Linux就适合 为什么要选择Xshell 二、下载XShell 三、安装XShell 四、使用XShell建立静态 1. XShell初始化界面 2、点击…

mac linux工具下载,xshell mac版

xshell mac版功能非常齐全,可以满足不同人的个性需求。具有强大的分页式环境,还可以定义的文本编辑器编辑终端内容,应对不安全的Telnet客户端,帮助大家实现控制终端的目的,带给用户良好的终端服务器操作体验。感兴趣的朋友可以前来尝试下! xshell for mac软件简介: xshe…

xshell免费版安装使用

介绍 Xshell是一款非常实用的SSH&#xff08;Secure Shell&#xff09;客户端软件&#xff0c;它可以让你在Windows系统中安全地远程登录到Linux或其他UNIX服务器中&#xff0c;并进行终端操作。本文将为大家介绍Xshell 7的安装方法&#xff0c;希望对大家有所帮助。 一、下载…

xshell下载

文章目录 xshell 官网下载地址 xshell 官网下载地址 xshell官网&#xff1a;https://www.xshell.com/zh/xshell/ 进入官网之后选择“所有下载-家庭/学校下载”&#xff0c;这个是免费的填写自己的邮箱地址&#xff0c;然后就会收到相对应的下载地址

你还在使用xshell绿色破解版?

你还在使用xshell绿色破解版&#xff1f; 一、xshell 介绍二、1分钟助你申请Xshell&#xff08;免费版&#xff09;个人版本和家庭版本&#xff0c;避免盗版问题1.访问Xshell官网下载页面 https://www.netsarang.com/zh/xshell-download/2、找到免费授权页面3、收到邮箱一个下载…

xshell免费版 正版,非xshell破解版

国内的下载网址下载的xshell是收费的&#xff0c;解决方法就是找国外的下载网址&#xff0c;国外提供学生和学校使用的免费版本。 连接网址&#xff1a;https://www.netsarang.com/en/all-downloads/

还在为XShell破解烦恼,试试tabby

Tabby (前身是 Terminus) 是一个可高度配置的终端模拟器和 SSH 或串口客户端&#xff0c;支持 Windows&#xff0c;macOS 和 Linux 集成 SSH&#xff0c;Telnet 客户端和连接管理器集成串行终端定制主题和配色方案完全可配置的快捷键和多键快捷键分体式窗格自动保存标签页支持…

xshell7,xftp7个人免费版官方下载,无需破解,免激活,下载即可使用

对于开发人员来说&#xff0c;xshell这款软件应该不陌生&#xff0c;是一款非常好用的服务器连接工具&#xff0c;但同时它又是收费的&#xff0c;导致很多同学下载后使用不久后就到期了。于是很多人都去网上搜索绿色版、破解版的&#xff0c;结果搜索出来的要么是有很多的捆绑…

NB!更方便Xshell本地密码破解工具

工具介绍 XshellCrack是基于SharpXDecrypt的二次开发&#xff0c;用go语言重写&#xff0c;增加了注册表查询设置&#xff0c;更方便xshell本地密码破解。 关注【Hack分享吧】公众号&#xff0c;回复关键字【230717】获取下载链接 工具使用 Usage:root SshCrack [flags]Flags…

Xshell Plus 6标准版详细安装破解教程,解决评估过期问题(附注册机,全网独家可用),非学校/家庭免费版

声明&#xff1a;相关软件仅供学习研究软件之用&#xff0c;不得用于商业用途&#xff0c;请大家购买正版&#xff0c;支持正版软件&#xff0c;请认准官方正版网站&#xff0c;与此同时&#xff0c;本软件数字签名为NetSarang Computer&#xff0c;与苏州思杰马克丁无关 注册机…

xshell7配置文件密码破解

工具 how-does-Xmanager-encrypt-password 实现 xshell配置文件位置&#xff1a; xshell7: C:\Users\%username%\Documents\NetSarang Computer\7\Xshell\Sessions xshell6: C:\Users\%username%\Documents\NetSarang Computer\6\Xshell\Sessions XShell5: %userpro…

工具推荐 | Xshell全版本解密工具(包括Xshell7)——SharpXDecrypt

声明 本程序仅供个人恢复密码使用&#xff01; 用户滥用造成的一切后果与作者无关&#xff01; 使用者请务必遵守当地法律&#xff01; 本程序不得用于商业用途&#xff0c;仅限学习交流&#xff01; 请在下载后24小时内删除&#xff01;如果代码中存在侵权行为&#xff0…

Keras中Sequential模型及方法详细总结

Sequential 序贯模型 序贯模型是函数式模型的简略版&#xff0c;为最简单的线性、从头到尾的结构顺序&#xff0c;不分叉&#xff0c;是多个网络层的线性堆叠。 Keras实现了很多层&#xff0c;包括core核心层&#xff0c;Convolution卷积层、Pooling池化层等非常丰富有趣的网…

sklearn中的模型评估

1. 介绍 有三种不同的方法来评估一个模型的预测质量&#xff1a; estimator的score方法&#xff1a;sklearn中的estimator都具有一个score方法&#xff0c;它提供了一个缺省的评估法则来解决问题。 Scoring参数&#xff1a;使用cross-validation的模型评估工具&#xff0c;依…

sklearn 模型在线学习、增量更新实现 (以SGD方式训练LR为例)

sklearn online learning 在 sklearn官方文档里以 online 为关键字进行检索 在线学习是可以通过小批量的数据迭代更新模型的权重&#xff0c;增量训练方法看 partial_fit&#xff0c;于是检索了一下 partial_fit&#xff0c;介绍如下&#xff1a; 不同与使用fit方法&#xff0…