JS原生管理系统介绍模板

注:本文没有展示全部代码,部分样式没有写上,只挑拣部分重要功能代码详解
课程详情请见千锋教育PC端原生JavaScript项目案例实战开发,高含金量web前端项目教学

需求分析

登录界面

能够实现正常用户上传文章账号,以及后台管理账号
在登录进去时需要动态加载,避免安全隐患

管理界面

每个功能模块都能单独展示自己的内容

主页面

动态加载功能而不是多个页面拼凑
能够实现通过后台的操作,更新文章改变主页面的显示

核心功能

登录

利用强大的json serve构建数据存放网址
可以实现管理员登陆和普通登录

动态加载HTML

利用localStorage判断是否有token属性来确定是否加载进主页面

导航栏

点击退出后拿出token属性,防止返回
通过拿取数据获得用户名并显示

侧边栏

每个选项都能展示自己的模块内容
bs样式覆盖

首页模块

每个功能分别做一个页面(个人感觉不太好,一个页面写多个模块功能感觉更简便)

添加用户

输入用户信息,点击button获取并保存
监听事件
照片地址的转换、获取

用户列表

显示所有已经创建的普通账户,并且能进行编辑
DOM操作
动态创建表格

编辑用户

能够打开一个框,里面显示着用户的信息(modal框)

删除用户

再次利用modal块写出是否确定的框

创建新闻

富文本的工具栏和编辑器

实现技术

登录

<style>
    html,body{
        height: 100%;
    }
    body{
        background-color: #2d3a4b;
        display: flex;
        justify-content: center;
        align-items: center;
        color: white;
        .logincontainer{
            background-color: rgba($color:#000000,$alpha:0.7);
            height:400px;
            width:600px;
            padding:50px;
        }
    }
</style>
<div class="logincontainer">
    <h2>锋企网站后台管理系统</h2>
    <form id="loginform">
        <div class="mb-3">
            <label for="username" class="form-label">用户名</label>
            <input type="text" class="form-control" id="username" aria-describedby="emailHelp">
        </div>
        <div class="mb-3">
            <label for="password" class="form-label">Password</label>
            <input type="password" class="form-control"
            id="password">
        </div>
        <button type="submit" class="btn btn-promary">登录</button>

        <div id="emailHelp" class="form-text">用户名密码不匹配</div>
    </form>
    <script>
        const loginform=document.querySelector('#loginform')
        loginform.onsubmit=function(evt){
            evt.preventDefault()//组织点击刷新的默认行为
            //正常 post请求
            //json-server get获取 post添加 put修改 delete删除
            let res = await fetch(`http://localhost:3000/users?username=${username.value}password=${password.value}`).then(res=>res.json())

            if(res.length>0){
                location.href="/admin/views/home/index.html"
            }else{
                console.log('失败')
            }
        }


    </script>
</div>

动态加载

//登录页面
if(res.length>0){
                localStorage.setItem("token",JSON.stringify({
                    ...res[0]
                    password:"***"//避免密码放在本地被窃取
                }))
                location.href="/admin/views/home/index.html"
            }else{
                console.log('失败')
                loginwarning.style.display="block"
            }
//主页面
if(localStorage.getItem("token")){

}else{
	location.herf="/admin/views/login/index.html"
}

导航栏

<html>
	<nav class="navbar navbar-light bg-light">
	    <div class="container-fulid">
	        <a  class="navbar-brand">锋企网站后台管理系统</a>
	        <div>
	            <img src="" alt="" id="topbar-photo" style="width: 40px;">欢迎
	            <span id="currentUsername">aaaa</span>
	            回来
	            <button type="button" class="btn btn-danger" id="exut">退出</button>
	        </div>
	    </div>
	</nav>
</html>
<script>
	function renderTopbar(user){
	    let photo=document.querySelector("#topbar-photo")
	    let currentUsername=document.querySelector("#currentUsername")
	    let exit =document.querySelector("#exit")
	
	    photo.src=user.photo
	    currentUsername.innerHTML=user.username
	
	    exit.onclick=function(){
	        localStorage.removeItem("token")
	        location.href="/admin/views/login/index.html"
	    }
	}
</script>

侧边栏

<ul class="nav flex-column" style="margin-top: 10px;">
    <li class="nav-item">
        <a class="nav-link active" aria-current="page" href="#" id="sidemenu-home">首页</a>
    </li>
    <li class="nav-item">
        <div class="accordion" id="accordionExample">
            <div class="accordion-item">
                <h2 class="accordion-header" id="headeringOne">
                    <button class="accordion-header" id="headingOne" data-bs-toggle="collapse" data-ba-target="#user-manage" aria-expanded="true" aria-controls="collapseOne">用户管理</button>
                </h2>
                <div id="user-manage" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
                    <div class="accordion-body">
                        <a href="#" class="nav-link active" aria-current="page" id="sidemenu-addUser">添加用户</a>
                        <a href="#" class="nav-link active" aria-current="page" id="sidemenu-userlist">用户列表</a>
                    </div>
                </div>
            </div>
        </div>
    </li>
    <li class="nav-item">
        <div class="accordion" id="accordionExample">
            <div class="accordion-item">
                <h2 class="accordion-header" id="headeringOne">
                    <button class="accordion-header" id="headingOne" data-bs-toggle="collapse" data-ba-target="#news-manage" aria-expanded="true" aria-controls="collapseOne">新闻管理</button>
                </h2>
                <div id="news-manage" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
                    <div class="accordion-body">
                        <a href="#" class="nav-link active" aria-current="page" id="sidemenu-addNews">创建新闻</a>
                        <a href="#" class="nav-link active" aria-current="page" id="sidemenu-NewsList">新闻列表</a>
                    </div>
                </div>
            </div>
        </div>
    </li>
</ul>

<style>
    .accordion-button:not(.collapsed){
        color: black;
        background-color: white;
        box-shadow: none;
    }
    .accordion-item{
        border: 0;
    }
    .nav-link{
        color: black;
    }
    .accordion-button:focus{
        box-shadow: none;
    }
</style>

首页模块

//个人信息栏
<div class="maincontent">
	//面包屑
	<nav aria-label="breadcrumb">
		<ol class="breadcrumb">
			<li class="breadcurmb-item active" aria-current="page">首页</li>
		</ol>
	</nav>
	//个人信息
	<div class="userprofile"></div>
<script>
	import {load,isLogin} from "/admin/utill/LoadView.js"
	load("sidemenu-home")//加载topbar //sidemenu
	let user=JSON.parse(isLogin())
	document.queryselector(".userprofile").innerHTML=`
		<img src="${user.photo}" style="width:100px;"/>
		<div>
			<div>${user.username}</div>
			<div><pre>${user.introduction || "这个人很懒"}</pre></div>
		</div>
	`
</script>

用户添加

<nav aria-label="breadcrumb">
	<ol class="breadcrumb">
		<li class="breadcrumb-item" aria=current="page">用户管理</li>
		<li class="breadcrumb-item active" aria=current="page">添加用户</li>
	</ol>
</nav>

<form id="addUserForm">
	<div class="mb-3">
		<label for="username" class="form-label">用户名</label>
		<input type="text" class="form-control" id="username" aria-describedby="emailHelp" required>
	</div>
	<div class="mb-3">
		<label for="password" class="form-label">密码</label>
		<input type="password" class="form-control" id="password" required>
	</div>
	<div class="mb-3">
		<label for="introduction" class="form-label">个人简介</label>
		<textarea class="form-control" id="introduction"  row="3"></textarea>
	</div>
	<div class="mb-3">
		<label for="photofile" class="form-label">头像</label>
		<input type="file" class="form-control" id="photo-file" required >
	</div>
	<button type="submit" class="btn btn-primary">添加用户</button>
</form>

<script>
import {load} from "/admin/util/LoadView.js"
load("sidemenu-addUser")
let photo=""
addUserForm.onsubmit=async function(evt){
	evt.preventDefault()
	await fetch("http://localhost:3000/users",{
		method:"post",
		headers:{
			"content-type":"application/json"
		},
		body:JSON.stringify({
			username:username.value
			password:password.value
			introduction:introduction.value
			photo
		})
	}).then(res=>res.json())
	location.herf="/admin/views/user-manage/UserList/index.html"
}
photofile.onchange=function(evt){//内部发生变化就将地址转化
	let reader=new FileReader()
	reader.readAsDataUrl(evt.target.files[0])
	reader.onload=function(e){
		console.log(e.target,result)
	}
}
</script>

用户列表

<nav aria-label="breadcrumb">
	<ol class="breadcrumb">
		<li class="breadcrumb-item" aria=current="page">用户管理</li>
		<li class="breadcrumb-item active" aria=current="page">用户列表</li>
	</ol>
</nav>
<table class="table">
	<thead>
		<tr>
			<th scope="col">用户名</th>
			<th scope="col">头像</th>
			<th scope="col">操作</th>
		</tr>
	</thead>
	<tbody id="listbody">
	</tbody>
</table>


<script>
import {load} from "/admin/until/LoadView.js"

load("sidemenu-userList")

asnyc function render(){
	let list = awit fetch("http://localhost:3000/users").then(res=>res.json())
	listbody.innerHTML=list.map(item=>`
	<tr>
	<th scope="row">${item.username}</th>
	<td>
			<img src="${item.photo}" style="width:50px; border-radius:50%">
	</td>
	<td>
		<button type="button" class="btn btn-primary btn-sm" ${item.default?"disabled":""}>编辑</button>//管理员不能动
		<button type="button" class="btn btn-danger btn-sm" ${item.default?"disabled":"">删除</button>
	</td>
	</tr>
	`).join("")
}
</script>

编辑用户

let myModal=new bootstrap.Model(document.getElementById('editModal'))
let updateId=0
let photodata =""
listbody.onclick=function(evt){
	if(evt.target.className.includes("btn-edit")){
		//显示modal
		myEditModal.toggle()
		updateId=evt.target.dataset.myid
		...
		//预填modal
		let {username,password,introduction,photo}=list.filter(item=>item.id==updateId)[0]
		document,queryselector("#username").value=username
		document,queryselector("#password").value=password
		document,queryselector("#introduction").value=introduction
		photodata=photo
		}else if(evt.target.className.includes("btn-del")){
		console.log("del")
	}
}
editConfirm.onclick=async function(){
	await fetch(`http://localhost:3000/users/`,{
		method:"PATCH",
		headers:{
			"content-type":"application/json"
		},
		body:JSON.stringify({
			username:document.queryselector("#username").value,
			password:document.queryselector("#password").value,
			introduction:document.queryselector("#introduction").value,
			photo:photodata
		})
	}).then(res=>res.json())
	myEditModal.toggle()
	render()
}
photofile.onchange=function(evt){
	let reader=new FileReader()
	reader.readAsDataUrl(evt.target.files[0])
	reader.onload=function(e){
		photodata=e.target.result
	}
}

删除用户

let myDelModal= new bootstrap.Modal(document.getElementById('delModel'))
updataId=evt.target.dataset.myid//else if 中的语句
delConfirm.onclick=async function(){
	await fetch(`http://localhost:3000/users/${updateId}`,{
		method:"delete"
	}).then(res=>res.json())
	myDelModal.toggle()
	render()
}

创建新闻

//下拉菜单
<div class="mb-3">
	<label for="category" class="form-label">类别</label>
	<select class="form_select" aria-label="Default select example" id="category">
		<option value="0">最新动态</option>
		<option value="1">典型案例</option>
		<option value="2">通知公告</option>
	</select>
</div>
//富文本内容删减,详情请前往bootstrap官网查看

项目总结

面对困难

json server环境搭建困难

前后端的数据交互

多层文件的叠加使用
js文件方法的导入导出

首页模块多个功能用多个页面写,虽然代码清晰简便很多,但是感觉不太合适

bootstrap的引用

后续规划

将多个模块多个页面改为一个页面多个模块

整体总结

环境搭建需重视

缺少实践实战

缺少对配件中各个工具的熟悉度和应用度

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优降宁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值