html+css+js+layui
1. 项目前期的准备工作
1.1. 初始化项目结构
- 项目文件夹命名为
code
,在该目录下新建login.html
和index.html
页面 - 在
code
目录下放入assets
和home
文件夹 - 在
assets
中新建lib
文件,放入layui
和jquery
的开发包
1.2. 使用GitHub管理大事件的项目
在
code
目录中运行git init
命令在
code
目录中运行git add .
命令在
code
目录下运行git commit -m "init project"
命令新建 Github 仓库
web_bigevent
将本地仓库和Github仓库建立关联关系
git remote add origin https://[token]@github.com/[username]/web_bigevent.git
将本地仓库的代码推送到Github仓库中,运行
git push -u origin master
命令运行
git checkout -b login
命令,创建并切换到login
分支查看当前所处分支,运行
git branch
命令
1.3. 安装插件
Expressv0.0.5
Hosts current workspace with Express web server in Visual Studio Code
快捷键 shift+command+p
打开命令面板
选择 express: Hosts Current Workspace and Open in Browser
2. 登录注册
2.1. 绘制login页面的基本结构
样式来源 :https://layuion.com/docs/
- 编写 HTML 结构
1 |
|
- 美化样式
1 | html, |
2.2. 实现登录和注册的按需切换
编写html结构
1
2
3
4
5
6
7
8
9
10
11
12
13<!-- 登录注册区域 -->
<div class="loginAndRegBox">
<!-- 标题 -->
<div class="title-box"></div>
<!-- 登录页面 -->
<div class="login-box">
<a href="javascript:;">去注册</a>
</div>
<!-- 注册页面 -->
<div class="reg-box">
<a href="javascript:;">去登录</a>
</div>
</div>引入jquery
1
<script src="./assets/lib/jquery.js"></script>
创建
asset/js/login.js
,并引入到login.html
1
2
3
4
5
6
7
8
9$(".login-box a").on("click",()=>{
$(".login-box").hide();
$(".reg-box").show();
})
$(".reg-box a").on("click",()=>{
$(".reg-box").hide();
$(".login-box").show();
})
2.3. 绘制登录表单的基本结构
1 | <!-- 登录页面 --> |
2.4. 美化登录表单的样式
1 | .login-box, |
2.5. 绘制文本框前面的小图标
在用户名的文本框之前,添加如下的标签结构:
1
<i class="layui-icon layui-icon-username"></i>
在密码框之前,添加如下的标签结构:
1
<i class="layui-icon layui-icon-password"></i>
美化样式:
1
2
3
4
5
6
7
8
9
10
11
12
13.loginAndRegBox .layui-form-item{
position: relative;
}
.loginAndRegBox .layui-form-item i{
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
}
.loginAndRegBox .layui-form-item .layui-input{
padding-left: 32px;
}
2.6. 快速绘制注册的表单
将登录的表单复制一份,并修改为注册的表单即可
1 | <!-- 注册页面 --> |
2.7. 实现登录表单的验证
导入 layui 的 js 文件
1
2<!-- 导入layui.js -->
<script src="./assets/lib/layui/layui.js"></script>为需要验证的表单项添加
lay-verify
属性,同时指定具体的校验规则即可
2.8. 自定义校验规则
从 layui 中获取 form 对象:
1
var form = layui.form
通过 form.verify() 函数自定义校验规则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15form.verify({
// 自定义了一个叫做 pwd 校验规则
pwd: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格'],
// 校验两次密码是否一致的规则
repwd: function(value) {
// 通过形参拿到的是确认密码框中的内容
// 还需要拿到密码框中的内容
// 然后进行一次等于的判断
// 如果判断失败,则return一个提示消息即可
var pwd = $('.reg-box [name=password]').val()
if (pwd !== value) {
return '两次密码不一致!'
}
}
})按需为表单项添加校验规则:
1
2
3
4<input type="password" name="password" required lay-verify="required|pwd" placeholder="请输入密码" autocomplete="off" class="layui-input">
<input type="password" name="repassword" required lay-verify="required|pwd|repwd" placeholder="再次确认密码" autocomplete="off" class="layui-input" />
2.9. 发起注册用户的Ajax请求
为注册表单添加Id:
1
2<!-- 注册的表单 -->
<form class="layui-form" id="form_reg"></form>监听提交事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24var layer = layui.layer;
// 监听注册表单的提交事件
$("#form-reg").on("submit",(e)=>{
// 1. 阻止默认的提交行为
e.preventDefault()
// 2. 发起Ajax的POST请求
const username = $("#form-reg [name=username]").val();
// console.log(username);
const password = $("#form-reg [name=password]").val();
$.post("http://127.0.0.1:3007/api/register",{
username:username,
password:password
},(result)=>{
// console.log(result);
if(result.status==1){
return layer.msg(result.message);
}else{
layer.msg('注册成功,请登录!');
// 模拟人的点击行为
$(".reg-box a").click();
}
});
})
2.10. 使用layer提示消息
导入 layer:
1
var layer = layui.layer
调用
layer.msg()
提示消息:1
layer.msg('注册成功,请登录!')
2.11. 发起登录的Ajax请求
为登录表单添加id:
1
<form class="layui-form" id="form_login"></form>
监听提交事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 监听注册表单的登录事件
$("#form-login").on("submit",(e)=>{
// 1. 阻止默认的提交行为
e.preventDefault();
// console.log($(this).serialize());
// 2. 发起Ajax请求
$.ajax({
url: "http://127.0.0.1:3007/api/login",
method: 'POST',
// 快速获取表单中的数据
data: {
username: $("#form-login [name=username]").val(),
password: $("#form-login [name=password]").val()
},
success: function(res) {
if(res.status==1){
return layer.msg(res.message);
}
layer.msg("登录成功!");
// 存储token
localStorage.setItem("token",res.token);
// 跳转至主页
var url = location.href;
url = url.substring(0,url.lastIndexOf("/"));
location.href=url+"/index.html";
}
})
});
2.12. 在ajaxPrefilter中统一拼接请求的根路径
在
/assets/js
目录中新建baseAPI.js
编写如下代码:
1
2
3
4
5
6
7
8// 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候,
// 会先调用 ajaxPrefilter 这个函数
// 在这个函数中,可以拿到我们给Ajax提供的配置对象
$.ajaxPrefilter(function(options) {
// 在发起真正的 Ajax 请求之前,统一拼接请求的根路径
options.url = 'http://ajax.frontend.itheima.net' + options.url
})修改登录,注册中ajax提交的路由
1
2
3
4
5// 监听注册表单的提交事件
$.post("/api/register",...);
// 监听登录表单的提交事件
$.post("/api/login",...);
2.13. 提交login分支的代码到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成了登录和注册的功能"
命令 - 运行
git push -u origin login
命令 - 运行
git checkout master
命令 - 运行
git merge login
命令 - 运行
git push
命令 - 运行
git checkout -b index
命令
3. 后台主页
3.1. 快速实现后台主页的布局效果
从 layUI 官方文档中粘贴布局的主要代码,并修改如下:
https://layuion.com/docs/element/layout.html#admin
1 |
|
3.2. 导入自定义样式
导入css文件
1
2
3
4<head>
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="./assets/css/index.css">
</head>添加样式
1
2
3.layui-footer{
text-align: center;
}
3.3. 使用lay-shrink实现左侧菜单互斥效果
1 | <div class="layui-side layui-bg-black"> |
3.4. 为菜单项添加图标
导入第三方的图标库:
1
2<!-- 导入第三方图标库 -->
<link rel="stylesheet" href="/assets/fonts/iconfont.css" />修改左侧菜单的结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-shrink="all" lay-filter="test">
<li class="layui-nav-item layui-this">
<!--
href属性用来指定打开哪个网页
target属性用来指定在哪里打开网页
target=fm 表示在name为fm的iframe中打开指定网页
-->
<a href="./home/dashboard.html" target="fm">
<span class="iconfont icon-home"></span>
首页
</a>
</li>
<li class="layui-nav-item">
<a class="" href="javascript:;">
<span class="iconfont icon-16"></span>文章管理
</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-app"></i>
文章类别
</a>
</dd>
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-list"></i>
文章列表
</a>
</dd>
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-edit"></i>
发布文章
</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">
<span class="iconfont icon-user"></span>个人中心
</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-form"></i>
基本资料
</a>
</dd>
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-picture"></i>
更换头像
</a>
</dd>
<dd>
<a href="javascript:;">
<i class="layui-icon layui-icon-key"></i>
重置密码
</a>
</dd>
</dl>
</li>
</ul>美化样式
1
2
3
4.iconfont,
.layui-nav-child .layui-icon{
margin-right: 10px;
}
3.5. 使用iframe标签在内容主体区域显示网页内容
在页面主体的 div 中添加
iframe
:1
2
3
4<div class="layui-body">
<!-- 内容主体区域 -->
<iframe src="./home/dashboard.html" name="fm" frameborder="0"></iframe>
</div>为
首页
链接添加href
和target
属性:1
2
3
4
5
6
7
8<li class="layui-nav-item layui-this">
<!--
href属性用来指定打开哪个网页
target属性用来指定在哪里打开网页
target=fm 表示在name为fm的iframe中打开指定网页
-->
<a href="./home/dashboard.html" target="fm">首页</a>
</li>美化
1
2
3
4
5
6
7
8iframe{
width: 100%;
height: 100%;
}
.layui-body{
overflow: hidden;
}
3.6. 解决小问题
为
首页
对应的导航 Item 项添加layui-this
属性:1
2
3
4<li class="layui-nav-item layui-this">
<a href="/home/dashboard.html" target="fm">
<span class="iconfont icon-home"></span>首页</a>
</li>强制清除
<a>
链接的 CSS3 动画:1
2
3a {
transition: none ;
}
3.7. 渲染图片头像和文字头像
修改头部区域的的头像结构如下:
1
2
3
4
5<a href="javascript:;" class="userinfo">
<img src="./assets/images/sample.jpg" class="layui-nav-img">
<span class="text-avatar">A</span>
个人中心
</a>在左侧导航区域的
ul
之前添加如下头像结构:1
2
3
4
5<div class="userinfo">
<img src="./assets/images/sample.jpg" class="layui-nav-img">
<span class="text-avatar">A</span>
<span>欢迎 ***</span>
</div>添加样式美化 UI 结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28.text-avatar{
display: inline-block;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: rgb(65 151 136);
font-size: 20px;
text-align: center;
line-height: 30px;
margin-right: 10px;
position: relative;
top: 4px;
}
.userinfo{
height: 60px;
line-height: 60px;
text-align: center;
}
.layui-side-scroll .userinfo{
border-bottom: 1px solid #282b33;
}
.userinfo img,
.userinfo span{
display: none;
user-select: none;
}
3.8. 获取用户的基本信息
导入需要的脚本:
1
2
3
4
5
6<!-- 导入jquery -->
<script src="./assets/lib/jquery.js"></script>
<!-- 导入自己封装的 baseAPI -->
<script src="./assets/js/baseAPI.js"></script>
<!-- 导入自定义js -->
<script src="./assets/js/index.js"></script>定义 getUserInfo 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var layer = layui.layer;
getUserInfo();
function getUserInfo(){
$.ajax({
method: "GET",
url: "/my/userinfo",
// headers 就是请求头配置对象
headers: {
Authorization: localStorage.getItem("token") || ''
},
success: (result)=>{
// console.log(result);
if(result.status==1){
return layer.msg(result.message);
}else{
// TODO:获取头像信息
renderAvatar(result.data);
}
}
})
}
3.9. 渲染用户头像
定义 renderAvatar 函数
1 | // 获取头像信息 |
3.10. 统一为有权限的接口设置headers请求头
在 baseAPI的 ajaxPrefilter
中添加如下代码:
1 | // 统一为有权限的接口,设置 headers 请求头 |
3.11. 实现退出功能
修改退出的
<a>
链接如下:1
2
3
4<a href="javascript:;" id="btnLogout">
<span class="iconfont icon-tuichu"></span>
退出
</a>实现退出功能:
采用layui的提示框
https://layuion.com/docs/modules/layer.html#layer.confirm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 退出按钮
$("#btnLogout").on("click",()=>{
console.log($(this));
layer.confirm('确定退出登录?', {icon: 3, title:'提示'},
function(index){
//do something
// 删除本地token
localStorage.removeItem("token");
// 跳转至登录页
// 跳转至主页
var url = location.href;
url = url.substring(0,url.lastIndexOf("/"));
location.href=url+"/login.html";
layer.close(index);
});
});
3.12. 控制用户的访问权限
在调用有权限接口的时候,指定complete
回调函数
jquery的ajax函数中请求成功会回调 success
,失败会回调 error
,但无论成功与否都会回调 complete
1 | // 不论成功还是失败,最终都会调用 complete 回调函数 |
3.13. 优化权限控制的代码
将权限控制的代码,从每个请求中,抽离到 ajaxPrefilter
中:
1 | // 全局统一挂载 complete 回调函数 |
3.14. 提交index分支的代码到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成了主页功能的开发"
命令 - 运行
git push -u origin index
命令 - 运行
git checkout master
命令 - 运行
git merge index
命令 - 运行
git push
命令 - 运行
git checkout -b user
命令
4. 用户管理
4.1. 基本资料
4.1.1. 创建基本资料对应的页面
在根目录下新建
/user/user_info.html
并初始化如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-基本资料</title>
<!-- 导入layui样式 -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/user/userInfo.css">
</head>
<body>
用户资料
</body>
</html>新建
/assets/css/user/userInfo.css
并初始化如下:1
2
3
4
5
6
7
8
9
10html,
body{
margin: 0;
padding: 0;
}
body{
background-color: #f2f3f5;
padding: 15px;
}修改
index.html
中基本资料
对应<a>
1
2
3
4<a href="./user/userInfo.html" target="fm">
<i class="layui-icon layui-icon-form"></i>
基本资料
</a>
4.1.2. 绘制基本资料对应的表单
编写如下的表单结构:
采用layui的卡片面板绘制表单
https://layuion.com/docs/element/panel.html#card
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-基本资料</title>
<!-- 导入layui样式 -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/user/userInfo.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">修改用户信息</div>
<div class="layui-card-body">
<form class="layui-form" action="">
<div class="layui-form-item">
<label class="layui-form-label">登录名称</label>
<div class="layui-input-block">
<input type="text" name="username" required lay-verify="required" placeholder="请输入登录名称" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" required lay-verify="required" placeholder="请输入用户昵称" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">用户邮箱</label>
<div class="layui-input-block">
<input type="text" name="email" required lay-verify="required|email" placeholder="请输入用户邮箱" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">提交修改</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>在页面底部导入如下的脚本:
1
2
3
4
5
6<!-- 导入layui.js -->
<script src="../assets/lib/layui/layui.js"></script>
<!-- 导入jquery.js -->
<script src="../assets/lib/jquery.js"></script>
<!-- 导入自定义js -->
<script src="../assets/js/user/userInfo.js"></script>在
user_info.js
中编写如下的代码:1
2
3
4
5
6
7
8
9var form = layui.form;
form.verify({
nickname: function(value){
if(value.length>6){
return '昵称长度必须在 1 ~ 6 个字符之间!';
}
}
})
4.1.3. 获取用户的基本信息
导入
baseAPI
:1
<script src="/assets/js/baseAPI.js"></script>
在
user_info.js
中定义并调用initUserInfo
函数:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15initUserInfo();
// 初始化用户信息
function initUserInfo(){
$.ajax({
method: "GET",
url: "/my/userinfo",
success: (result)=>{
if(result.status==1){
return layer.msg(result.message);
}else{
// TODO:填充到表单中
}
}
})
}
4.1.4. 使用form.val方法快速为表单赋值
为表单指定
lay-filter
属性:form.val('filter', object);
用于给指定表单集合的元素赋值和取值https://layuion.com/docs/modules/form.html#val
1
<form class="layui-form" lay-filter="formUserInfo"></form>
调用
form.val()
方法为表单赋值:1
form.val('formUserInfo', res.data);
使用隐藏域保存用户的
id
值:1
2
3
4
5
6
7<!-- form 表单区域 -->
<form class="layui-form" lay-filter="formUserInfo">
<!-- 这是隐藏域 -->
<input type="hidden" name="id" value="" />
<!-- 省略其他代码 -->
</form>
4.1.5. 实现表单的重置效果
阻止表单的默认重置行为,再重新获取用户信息即可
1 | // 重置按钮 |
4.1.6. 发起请求更新用户的信息
阻止表单的默认提交行为,并发起数据请求
1 | // 监听表单的提交事件 |
4.2. 重置密码
4.2.1. 渲染重置密码的页面结构
在
/user/userPwd.html
页面中编写如下的结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-重置密码</title>
<!-- 导入layui样式 -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/user/userPwd.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">修改密码</div>
<div class="layui-card-body">
<form class="layui-form" action="" lay-filter="formUserInfo">
<!-- 隐藏用户id -->
<input type="hidden" name="id" value="">
<div class="layui-form-item">
<label class="layui-form-label">原密码</label>
<div class="layui-input-block">
<input type="password" name="oldPwd" required lay-verify="required" placeholder="请输入原密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" name="newPwd" required lay-verify="required" placeholder="请输入新密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="rePwd" required lay-verify="required" placeholder="请确认新密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">修改密码</button>
<button type="reset" class="layui-btn layui-btn-primary" id="btnReset">重置</button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>在
/assets/css/user/userPwd.css
中编写如下的样式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15html,
body{
margin: 0;
padding: 0;
width: 100%;
}
body{
padding: 15px;
background-color: #f2f3f5;
}
.layui-card{
width: 50%;
}
4.2.2. 为密码框定义校验规则
在 body 结束标签之前导入如下的
script
标签:1
2
3
4
5
6
7
8<!-- 导入layui.js -->
<script src="../assets/lib/layui/layui.js"></script>
<!-- 导入jquery.js -->
<script src="../assets/lib/jquery.js"></script>
<!-- 导入baseAPI.js -->
<script src="../assets/js/baseAPI.js"></script>
<!-- 导入自定义js -->
<script src="../assets/js/user/userInfo.js"></script>在
userPwd.js
中定义如下的三个校验规则1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var form = layui.form;
var layer = layui.layer;
form.verify({
pwd: [/^[\S]{6,12}$/,"密码必须6到12位,且不能出现空格"],
samePwd: function(val){
if(val== $(".layui-form [name=oldPwd").val()){
return '新旧密码不能相同!';
}
},
rePwd: function(val){
if(val!= $(".layui-form [name=newPwd").val()){
return '两次密码不一致!';
}
}
})为密码框分别添加对应的校验规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28<form class="layui-form" action="" lay-filter="formUserInfo">
<!-- 隐藏用户id -->
<input type="hidden" name="id" value="">
<div class="layui-form-item">
<label class="layui-form-label">原密码</label>
<div class="layui-input-block">
<input type="password" name="oldPwd" required lay-verify="required|pwd" placeholder="请输入原密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新密码</label>
<div class="layui-input-block">
<input type="password" name="newPwd" required lay-verify="required|pwd|samePwd" placeholder="请输入新密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">确认密码</label>
<div class="layui-input-block">
<input type="password" name="rePwd" required lay-verify="required|pwd|rePwd" placeholder="请确认新密码" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">修改密码</button>
<button type="reset" class="layui-btn layui-btn-primary" id="btnReset">重置</button>
</div>
</div>
</form>
4.2.3. 发起请求实现重置密码的功能
1 | // 提交密码 |
4.3. 更换头像
4.3.1. 初步渲染更换头像页面的结构
创建
/user/userAvatar.html
页面:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-更换头像</title>
<!-- 导入layui.css -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义css -->
<link rel="stylesheet" href="../assets/css/user/userAvatar.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">更换头像</div>
<div class="layui-card-body">
</div>
</div>
</body>
</html>在
assets/css/user/userAvatar.css
中美化基本样式:1
2
3
4
5
6
7
8
9
10html,
body {
margin: 0;
padding: 0;
}
body {
padding: 15px;
background-color: #f2f3f5;
}修改
index.html
中对应链接的属性:1
2
3
4<a href="./user/userAvatar.html" target="fm">
<i class="layui-icon layui-icon-picture"></i>
更换头像
</a>
4.3.2. cropper 基本用法
文档 https://github.com/fengyuanchen/jquery-cropper
官网 https://fengyuanchen.github.io/jquery-cropper/
在
<head>
中导入cropper.css
样式表:1
<link rel="stylesheet" href="/assets/lib/cropper/cropper.css" />
在
<body>
的结束标签之前,按顺序导入如下的 js 脚本:1
2
3<script src="/assets/lib/jquery.js"></script>
<script src="/assets/lib/cropper/Cropper.js"></script>
<script src="/assets/lib/cropper/jquery-cropper.js"></script>在卡片的
layui-card-body
主体区域中,定义如下的 HTML 结构:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<!-- 第一行的图片裁剪和预览区域 -->
<div class="row1">
<!-- 图片裁剪区域 -->
<div class="cropper-box">
<!-- 这个 img 标签很重要,将来会把它初始化为裁剪区域 -->
<img id="image" src="/assets/images/sample.jpg" />
</div>
<!-- 图片的预览区域 -->
<div class="preview-box">
<div>
<!-- 宽高为 100px 的预览区域 -->
<div class="img-preview w100"></div>
<p class="size">100 x 100</p>
</div>
<div>
<!-- 宽高为 50px 的预览区域 -->
<div class="img-preview w50"></div>
<p class="size">50 x 50</p>
</div>
</div>
</div>
<!-- 第二行的按钮区域 -->
<div class="row2">
<button type="button" class="layui-btn">上传</button>
<button type="button" class="layui-btn layui-btn-danger">确定</button>
</div>美化的样式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61/* 设置卡片主体区域的宽度 */
.layui-card {
width: 50%;
}
.row1{
overflow: hidden;
}
/* 设置裁剪区域的样式 */
.cropper-box {
float: left;
width: 350px;
height: 350px;
background-color: cyan;
overflow: hidden;
}
/* 设置 preview-box 区域的的样式 */
.preview-box {
float: left;
margin-left: 10%;
height: 350px;
}
/* 设置第一个预览区域的样式 */
.w100 {
width: 100px;
height: 100px;
background-color: gray;
}
/* 设置第二个预览区域的样式 */
.w50 {
width: 50px;
height: 50px;
background-color: gray;
margin-top: 50px;
margin-left: 25%;
}
/* 设置预览区域下方文本的样式 */
.size {
font-size: 12px;
color: gray;
text-align: center;
}
/* 设置 img-preview 区域的样式 */
.img-preview {
overflow: hidden;
border-radius: 50%;
}
/* 设置按钮行的样式 */
.row2 {
margin-top: 20px;
margin-left: 70%;
}实现基本裁剪效果:
1
2
3
4
5
6
7
8
9
10
11
12
13// 1.获取裁剪区域的 DOM 元素
var img = $("#image");
// 2.配置选项
const options = {
// 纵横比
aspectRatio: 1,
// 指定预览区域
preview: '.img-preview'
}
// 3.创建裁剪区域
img.cropper(options);
4.3.3. 实现裁剪区域图片的替换
userAvatar.html
中添加上传文件的按钮1
2
3
4
5
6<!-- 第二行的按钮区域 -->
<div class="row2">
<input type="file" name="" id="file">
<button type="button" class="layui-btn" id="btnFile">上传</button>
<button type="button" class="layui-btn layui-btn-danger" id="btnUpload">确定</button>
</div>隐藏按钮。在
userAvatar.css
中添加样式1
2
3#file{
display: none;
}上传按钮模拟点击文件上传。在
userAvatar.js
中添加1
2
3
4
5
6
7// 上传按钮
$("#btnFile").on("click",function(e){
e.preventDefault();
// 模拟点击上传文件
$("#file").click();
});为文件选择框绑定 change 事件
1 | $("#file").on("change",function(e){ |
4.3.4. 将裁剪后的头像上传到服务器
1 | // 确定按钮 |
4.3.5. base64
https://www.css-js.com/tools/base64.html
DataURI 允许在HTML文档中嵌入小文件,可以使用 img 标签或 CSS 嵌入转换后的 Base64 编码,减少 HTTP 请求,加快小图像的加载时间。
经过Base64 编码后的文件体积一般比源文件大 30% 左右。
4.3.6. 设置头部区域的快捷方式
打开 index.html
,在头部 个人中心
中添加id属性如下
1 | <dl class="layui-nav-child" id="top-user"> |
对应的侧边栏用户管理,添加 id="nav-user"
1 | <li class="layui-nav-item"> |
让头部个人中心点击事件直接触发侧边栏的点击事件
1 | // 顶部个人中心下拉菜单 |
4.4. 提交user分支的代码到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成了用户管理功能的开发"
命令 - 运行
git push -u origin user
命令 - 运行
git checkout master
命令 - 运行
git merge user
命令 - 运行
git push
命令 - 运行
git checkout -b article
命令
5. 文章管理
5.1. 文章类别
5.1.1. 创建并显示文章分类
创建
/article/art_cate.html
页面,并初始化如下的UI结构:采用layui表格布局
https://layuion.com/docs/element/table.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-文章分类</title>
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/article/art_cate.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">
<span>文章类别管理</span>
<button type="button" class="layui-btn layui-btn-normal">添加类别</button>
</div>
<div class="layui-card-body">
<table class="layui-table">
<colgroup>
<!-- 定义列宽度,不加数字的为自适应 -->
<col>
<col>
<col width="200">
</colgroup>
<thead>
<tr>
<th>分类名称</th>
<th>分类别名</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>贤心</td>
<td>2016-11-29</td>
<td>
<button class="layui-btn">编辑</button>
<button class="layui-btn layui-btn-danger">删除</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>定义
/assets/css/article/art_cate.css
美化样式:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19html,
body {
margin: 0;
padding: 0;
}
body {
padding: 15px;
background-color: #f2f3f5;
}
.layui-card-header span{
float: left;
}
.layui-card-header button{
float: right;
margin-top: 10px;
}修改
index.html
中对应的<a>
链接:1
2
3
4<a href="./aticle/art_cate.html" target="fm">
<i class="layui-icon layui-icon-app"></i>
文章类别
</a>
5.1.2. 获取并使用模板引擎渲染表格的数据
在
/article/art_cate.html
页面底部导入模板引擎:1
2
3
4
5
6
7
8
9
10<!-- 导入layui.js -->
<script src="../assets/lib/layui/layui.js"></script>
<!-- 导入jquery -->
<script src="../assets/lib/jquery.js"></script>
<!-- 导入自己封装的 baseAPI -->
<script src="../assets/js/baseAPI.js"></script>
<!-- 导入模板引擎 -->
<script src="../assets/lib/template-web.js"></script>
<!-- 导入自定义js -->
<script src="../assets/js/article/art_cate.js"></script>在
/article/art_cate.html
页面中定义模板:1
2
3
4
5
6
7
8
9
10
11
12
13<!-- 表格数据的模板 -->
<script type="text/html" id="cate_table">
{{each data}}
{{$value.name}}</td>
{{$value.alias}}</td>
{{/each}}
</script>发起请求获取数据。在
assets/js/article/art_cate.js
中添加:1
2
3
4
5
6
7
8
9
10
11
12
13
14getAricleCate();
function getAricleCate(){
$.ajax({
method: 'GET',
url: '/my/article/cates',
success: function(res) {
// console.log(res);
var htmlStr = template('cate_table', res)
$('tbody').html(htmlStr);
}
})
}
5.1.3. 使用layer.open实现弹出层效果
layui的弹出层:https://layuion.com/docs/modules/layer.html
在
assets/js/article/art_cate.js
中导入layer
:1
var layer = layui.layer
在
/article/art_cate.html
页面中为按钮添加id
属性:1
<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" id="btnAddCate">添加类别</button>
在按钮的点击事件中,通过
layer.open()
展示弹出层:1
2
3
4
5
6
7// 为添加类别按钮绑定点击事件
$('#btnAddCate').on('click', function() {
layer.open({
title: '在线调试'
,content: '配置各种参数,试试效果'
});
})
5.1.4. 在弹出层中渲染form表单结构
在页面中定义如下的
script
标签:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<!-- 添加类别表单 -->
<script type="text/html" id="dialog-add">
<form class="layui-form" id="form-add">
<div class="layui-form-item">
<label class="layui-form-label">分类名称</label>
<div class="layui-input-block">
<input type="text" name="name" required lay-verify="required" placeholder="请输入分类名称" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">分类别名</label>
<div class="layui-input-block">
<input type="text" name="alias" required lay-verify="required|alias" placeholder="请输入分类别名" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit lay-filter="formDemo">确认添加</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
</script>通过
content
属性指定内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14// 添加类别按钮
$("#btnAddCates").on("click",function(e){
e.preventDefault();
layer.open({
// 0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type: 1,
// area - 宽高
area:['500px','250px'],
title: '添加文章分类',
// content不仅可以传入普通的html内容,还可以指定DOM
content: $("#dialog-add").html()
});
})为别名定义校验规则:
1
2
3
4
5// 文章分类规则
var form = layui.form;
form.verify({
alias: [/^[a-zA-Z0-9]$/,"别名必须是字母或数字!"]
});
5.1.5. 实现添加文章分类的功能
预先定义弹出层的索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 定义弹出层的索引
var indexAdd = null;
// 添加类别按钮
$("#btnAddCates").on("click",function(e){
e.preventDefault();
indexAdd = layer.open({
// 0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type: 1,
// area - 宽高
area:['500px','250px'],
title: '添加文章分类',
// content不仅可以传入普通的html内容,还可以指定DOM
content: $("#dialog-add").html()
});
})发起ajax请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 通过代理的形式,为 form-add 表单绑定 submit 事件
$("body").on("submit","#form-add",function(e){
e.preventDefault();
$.ajax({
method: 'POST',
url: '/my/article/addcates',
data: {
name: $("#form-add [name=name]").val(),
alias: $("#form-add [name=alias]").val()
},
success: function(res) {
if (res.status !== 0) {
return layer.msg(res.message);
}
// 刷新表格
getAricleCate();
layer.msg(res.message);
// 根据索引,关闭对应的弹出层
layer.close(indexAdd);
}
});
});
5.1.6. 点击编辑按钮展示修改文章分类的弹出层
为编辑按钮添加
btn-edit
类名如下:1
<button type="button" class="layui-btn layui-btn-xs btn-edit">编辑</button>
定义
修改分类
的弹出层:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<!-- 修改表单 -->
<script type="text/html" id="dialog-edit">
</script>通过
代理
的形式,为btn-edit
按钮绑定点击事件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 修改弹出层
// 定义弹出层的索引
var indexEdit= null;
$("tbody").on("click",".btn-edit",function(e){
e.preventDefault();
indexEdit = layer.open({
// 0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type: 1,
// area - 宽高
area:['500px','250px'],
title: '修改文章分类',
// content不仅可以传入普通的html内容,还可以指定DOM
content: $("#dialog-edit").html()
});
})
5.1.7. 为修改文章分类的弹出层填充表单数据
为编辑按钮绑定
data-id
自定义属性:1
<button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.id}}">编辑</button>
在展示弹出层之后,根据 id 的值发起请求获取文章分类的数据,并填充到表单中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 修改弹出层
// 定义弹出层的索引
var indexEdit= null;
$("tbody").on("click",".btn-edit",function(e){
e.preventDefault();
indexEdit = layer.open({
// 0(信息框,默认)1(页面层)2(iframe层)3(加载层)4(tips层)
type: 1,
// area - 宽高
area:['500px','250px'],
title: '修改文章分类',
// content不仅可以传入普通的html内容,还可以指定DOM
content: $("#dialog-edit").html()
});
// 填充表单
const id = $(this).data("id");
// console.log(id);
$.ajax({
method: 'GET',
url: '/my/article/cates/' + id,
success: function(res) {
// console.log(res);
// 与form的lay-filter相联系
form.val('form-edit', res.data);
}
})
});
5.1.8. 更新文章分类的数据
通过代理的形式,为修改分类的表单绑定 submit 事件
1 | // 通过代理的形式,为 form-edit 表单绑定 submit 事件 |
5.1.9. 删除文章分类
为删除按钮绑定
btn-delete
类名,并添加data-id
自定义属性:1
<button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.id}}">删除</button>
通过代理的形式,为删除按钮绑定点击事件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 删除按钮
$("tbody").on("click",".btn-delete",function(e){
e.preventDefault();
// 填充表单
const id = $(this).data("id");
layer.confirm('确认删除?', { icon: 3, title: '提示' },
function(index) {
$.ajax({
method: 'GET',
url: '/my/article/deletecate/'+id,
success: function(res) {
if (res.status !== 0) {
return layer.msg(res.message);
}
// 刷新表格
getAricleCate();
layer.msg(res.message);
// 根据索引,关闭对应的弹出层
layer.close(index);
}
});
});
});
5.2. 文章列表
5.2.1. 创建文章列表页面
新建
/article/art_list.html
页面结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-文章列表</title>
<!-- layui样式 -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/article/art_list.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">
文章列表
</div>
<div class="layui-card-body">
<!-- 筛选区域 -->
<!-- 列表区域 -->
<table class="layui-table">
<colgroup>
<!-- 定义列宽度,不加数字的为自适应 -->
<col>
<col width="150" />
<col width="180" />
<col width="150" />
<col width="150" />
</colgroup>
<thead>
<tr>
<th>文章标题</th>
<th>分类</th>
<th>发表时间</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<!-- 分页区域 -->
</div>
</div>
<!-- 导入layui.js -->
<script src="../assets/lib/layui/layui.js"></script>
<!-- 导入jquery -->
<script src="../assets/lib/jquery.js"></script>
<!-- 导入自己封装的 baseAPI -->
<script src="../assets/js/baseAPI.js"></script>
<!-- 导入模板引擎 -->
<script src="../assets/lib/template-web.js"></script>
<!-- 导入自定义js -->
<script src="../assets/js/article/art_list.js"></script>
</body>
</html>新建
/assets/css/article/art_list.css
样式表如下:1
2
3
4
5
6
7
8
9
10html,
body {
margin: 0;
padding: 0;
}
body {
padding: 15px;
background-color: #f2f3f5;
}新建
/assets/js/article/art_list.js
脚本文件修改
index.html
中对应的<a>
链接:1
2
3
4<a href="./aticle/art_list.html" target="fm">
<i class="layui-icon layui-icon-list"></i>
文章列表
</a>
5.2.2. 定义查询参数对象
在 /assets/js/article/art_list.js
定义一个查询的参数对象如下:
1 | // 定义一个查询的参数对象,将来请求数据的时候, |
5.2.3. 请求文章列表数据并使用模板引擎渲染列表结构
/assets/js/article/art_list.js
中定义获取文章列表数据的方法如下:
1 | initTable(); |
/article/art_list.html
定义列表数据的模板结构:
1 | <script type="text/html" id="article-table"> |
5.2.4. 绘制筛选区域的UI结构
1 | <!-- 筛选区域 --> |
5.2.5. 发起请求获取并渲染文章分类的下拉选择框
定义
initCate
函数请求文章分类的列表数据:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var form = layui.form;
initCate();
// 筛选区域 - 所有文章分类
function initCate(){
$.ajax({
method: 'GET',
url: '/my/article/cates',
success: function(res) {
if (res.status !== 0) {
return layer.msg(res.message);
}
// console.log(res);
// 使用模板引擎渲染页面的数据
var htmlStr = template('article-cate', res);
$('.layui-form [name=cate_id]').html(htmlStr);
// 通过 layui 重新渲染表单区域的UI结构
form.render();
}
});
}定义分类可选项的模板结构:
1
2
3
4
5
6
7<!-- 文章分类模板 -->
<script type="text/html" id="article-cate">
{{each data}}
{{$value.id}}">{{$value.name}}</option>
{{/each}}
</script>
5.2.6. 实现筛选的功能
为筛选表单绑定 submit 事件
1 | // 筛选表单提交事件 |
5.2.7. 定义渲染分页的 renderPage 方法
定义渲染分页的方法:
1
2
3function renderPage(total) {
console.log(total)
}在
initTable
中调用renderPage
方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function initTable(){
$.ajax({
method: 'GET',
url: '/my/article/list',
data: obj,
success: function(res) {
if (res.status !== 0) {
return layer.msg(res.message);
}
// 使用模板引擎渲染页面的数据
var htmlStr = template('article-table', res);
$('tbody').html(htmlStr);
// 调用渲染分页的方法
renderPage(res.total);
}
})
}
5.2.8. 调用 laypage.render 方法渲染分页的基本结构
https://layuion.com/docs/modules/laypage.html
在页面中定义分页的区域:
1
2<!-- 分页区域 -->
<div id="pageBox"></div>调用 laypage.render() 方法来渲染分页的结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 分页函数
function renderPage(total) {
// console.log(total);
var laypage = layui.laypage;
//执行一个laypage实例
laypage.render({
//注意,这里的 test1 是 ID,不用加 # 号
elem: 'pageBox',
//数据总数,从服务端得到
count: total,
// 每页显示几条数据
limit: obj.pagesize,
// 设置默认被选中的分页
curr: obj.pagenum
});
}
5.2.9. 在jump回调函数中通过obj.curr获取到最新的页码值
1 | // 分页函数 |
5.2.10. 自定义分页的功能项
添加 layout
和 limits
属性
1 | // 分页函数 |
5.2.11. 删除文章
为删除按钮绑定
btn-delete
类名和data-id
自定义属性:1
<button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id={{$value.id}}>删除</button>
通过代理的形式,为删除按钮绑定点击事件处理函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35// 删除按钮
$("tbody").on("click",".btn-delete",function(e){
e.preventDefault();
// 获取删除按钮的个数
var len = $('.btn-delete').length;
const id = $(this).data("id");
layer.confirm('确认删除?', { icon: 3, title: '提示' },
function(index) {
$.ajax({
method: 'GET',
url: '/my/article/delete/'+id,
success: function(res) {
if (res.status !== 0) {
return layer.msg(res.message);
}
layer.msg(res.message);
// 当数据删除完成后,需要判断当前这一页中,是否还有剩余的数据
// 如果没有剩余的数据了,则让页码值 -1 之后,
// 再重新调用 initTable 方法
// 4
if (len == 1) {
// 如果 len 的值等于1,证明删除完毕之后,页面上就没有任何数据了
// 页码值最小必须是 1
obj.pagenum = obj.pagenum === 1 ? 1 : obj.pagenum - 1
}
initTable();
}
});
layer.close(index);
});
});
5.3. 发布文章
5.3.1. 创建文章发布页面的基本结构
新建
/article/art_pub.html
页面结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>大事件后台管理系统-发布文章</title>
<!-- layui样式 -->
<link rel="stylesheet" href="../assets/lib/layui/css/layui.css">
<!-- 导入自定义样式 -->
<link rel="stylesheet" href="../assets/css/article/art_pub.css">
</head>
<body>
<div class="layui-card">
<div class="layui-card-header">
发布文章
</div>
<div class="layui-card-body">
<form class="layui-form" id="form-edit" lay-filter="form-edit">
<div class="layui-form-item">
<label class="layui-form-label">文章标题</label>
<div class="layui-input-block">
<input type="text" name="title" required lay-verify="required" placeholder="请输入文章标题" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文章类别</label>
<div class="layui-input-block" style="width:15%;">
<select name="cate_id" lay-verify="required"></select>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">文章内容</label>
<!-- 为富文本编辑器外部的容器设置高度 -->
<div class="layui-input-block" style="height: 400px;">
<!-- 重要:将来这个 textarea 会被初始化为富文本编辑器 -->
<textarea name="content" id="articleContent"></textarea>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn" lay-submit>发布</button>
<button class="layui-btn layui-btn-primary" lay-submit>存为草稿</button>
</div>
</div>
</form>
</div>
</div>
<!-- 导入layui.js -->
<script src="../assets/lib/layui/layui.js"></script>
<!-- 导入jquery -->
<script src="../assets/lib/jquery.js"></script>
<!-- 导入自己封装的 baseAPI -->
<script src="../assets/js/baseAPI.js"></script>
<!-- 导入模板引擎 -->
<script src="../assets/lib/template-web.js"></script>
<!-- 导入自定义js -->
<script src="../assets/js/article/art_pud.js"></script>
</body>
</html>新建
/assets/css/article/art_pub.css
样式文件如下:1
2
3
4
5
6
7
8
9
10html,
body{
margin: 0;
padding: 0;
}
body{
margin: 0 15px;
background-color: #f2f3f5;
}新建
/assets/js/article/art_pub.js
脚本文件修改
index.html
中对应的<a>
链接:1
2
3
4<a href="./aticle/art_pub.html" target="fm">
<i class="layui-icon layui-icon-edit"></i>
发布文章
</a>
5.3.2. 渲染文章类别对应的下拉选择框结构
在
/article/art_pub.html
中 定义模板结构1
2
3
4
5
6
7<!-- 下拉选框 -->
<script type="text/html" id="article_cates">
{{each data}}
{{$value.id}}>{{$value.name}}</option>
{{/each}}
</script>在
/assets/js/article/art_pub.js
中定义 initCate 方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16initCate();
var layer = layui.layer;
var form = layui.form;
// 下拉文章分类列表
function initCate(){
$.ajax({
method: "GET",
url: "/my/article/cates",
success: function(res){
const htmlStr = template("article_cates",res);
$("[name=cate_id]").html(htmlStr);
form.render();
}
})
}
5.3.3. 渲染富文本编辑器
TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器 http://tinymce.ax-z.cn/
导入富文本必须的
script
脚本:1
2
3<!-- 富文本 -->
<script src="../assets/lib/tinymce/tinymce.min.js"></script>
<script src="../assets/lib/tinymce/tinymce_setup.js"></script>让TinyMCE关联页面的
textarea
1
2
3
4
5
6
7function initEditor() {
tinymce.init({
//选择id为articleContent的标签作为编辑器
selector: '#articleContent',
// TODO: 其他事务
})
}在
/assets/js/article/art_pub.js
中调用initEditor()
方法,初始化富文本编辑器:1
initEditor();
5.3.4. 渲染封面裁剪区域
在
<head>
中导入cropper.css
样式表:1
2<!-- 导入裁剪样式 -->
<link rel="stylesheet" href="../assets/lib/cropper/cropper.css">在
<body>
的结束标签之前,按顺序导入如下的 js 脚本1
2
3<!-- 导入裁剪js -->
<script src="../assets/lib/cropper/Cropper.js"></script>
<script src="../assets/lib/cropper/jquery-cropper.js"></script>在表单中,添加如下的表单行结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<div class="layui-form-item">
<label class="layui-form-label">文章封面</label>
<div class="layui-input-block" id="img-box">
<!-- 第一行的图片裁剪和预览区域 -->
<div class="row1">
<!-- 图片裁剪区域 -->
<div class="cropper-box">
<!-- 这个 img 标签很重要,将来会把它初始化为裁剪区域 -->
<img id="image" src="../assets/images/sample.jpg" />
</div>
<!-- 图片的预览区域 -->
<div class="preview-box">
<div>
<!-- 宽高为 200px 的预览区域 -->
<div class="img-preview w200"></div>
<p class="size">200 x 100</p>
</div>
</div>
</div>
<!-- 第二行的按钮区域 -->
<div class="row2">
<!-- 选择封面按钮 -->
<button type="button" class="layui-btn layui-btn-danger" id="btnFile">选择封面</button>
</div>
</div>
</div>美化的样式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53/* 设置裁剪区域的样式 */
.cropper-box {
float: left;
width: 600px;
height: 300px;
background-color: cyan;
overflow: hidden;
}
/* 设置 preview-box 区域的的样式 */
.preview-box {
float: right;
}
/* 设置第一个预览区域的样式 */
.w200 {
width: 200px;
height: 100px;
background-color: gray;
}
/* 设置预览区域下方文本的样式 */
.size {
font-size: 12px;
color: gray;
text-align: center;
}
/* 设置 img-preview 区域的样式 */
.img-preview {
overflow: hidden;
}
/* 设置按钮行的样式 */
.row2 {
position: absolute;
bottom: 0;
right: 0;
}
/* 上传文件按钮 */
#file{
display: none;
}
/* 裁剪图片div */
#img-box{
width: 70%;
position: relative;
margin-bottom: 20px;
}在
/assets/js/article/art_pub.js
中实现基本裁剪效果:1
2
3
4
5
6
7
8
9// 1. 初始化图片裁剪器
var img = $("#image");
// 2. 裁剪选项
var options = {
aspectRatio: 600 / 300,
preview: '.img-preview'
}
// 3. 初始化裁剪区域
img.cropper(options);
5.3.5. 点击选择封面按钮打开文件选择框
修改 UI 结构,为
选择封面
按钮添加id
,并且在按钮后面添加文件选择框
:1
2
3
4
5
6
7<!-- 第二行的按钮区域 -->
<div class="row2">
<!-- 隐藏的文件选择框 -->
<input type="file" name="" id="file" accept="image/png,image/jpeg,image/gif">
<!-- 选择封面按钮 -->
<button type="button" class="layui-btn layui-btn-danger" id="btnFile">选择封面</button>
</div>为选择封面的按钮,绑定点击事件处理函数:
1
2
3
4
5$("#btnFile").on("click",function(e){
e.preventDefault();
$("#file").click();
})
5.3.6. 将选择的图片设置到裁剪区域中
监听 file
的 change
事件,获取用户选择的文件列表:
1 | // 更换裁剪的图片 |
5.3.7. 分析发布文章的实现步骤
为
存为草稿
和发布
按钮添加id
属性:1
2<button class="layui-btn btn-pub" lay-submit>发布</button>
<button class="layui-btn layui-btn-primary btn-draft" lay-submit>存为草稿</button>确定文章的发布状态:
1
2
3
4
5
6
7
8// 文章状态保存
var articleState;
$(".btn-pub").on("click",function(e){
articleState = "已发布";
})
$(".btn-draft").on("click",function(e){
articleState = "草稿";
})
5.3.8. 基于Form表单创建FormData对象
当文章内容无输入时,应该有判断
1 | // 得到富文本内容 |
富文本中的数据同步到textarea
http://tinymce.ax-z.cn/advanced/some-example.php
1 | tinyMCE.editors["articleContent"].save(); |
为表单绑定 submit 提交事件
1 | // 发布文章form |
5.3.9. 发起Ajax请求实现发布文章的功能
定义一个发布文章的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25function publishArticle(obj) {
$.ajax({
method: 'POST',
url: '/my/article/add',
data: obj,
// 注意:如果向服务器提交的是 FormData 格式的数据,
// 必须添加以下两个配置项
contentType: false,
processData: false,
success: function(res) {
if (res.status == 1) {
return layer.msg(res.message);
}
layer.msg(res.message);
// 发布文章成功后,跳转到文章列表页面
// 跳转至文章列表页
var url = location.href;
url = url.substring(0,url.lastIndexOf("/"));
// console.log(url);
location.href=url+'/art_list.html';
// 点击左边框的文章列表按钮
$("#artList",window.parent.document).click();
}
})
}其中的
$("#artList")
是侧边栏的文章列表的id在
index.html
中为文章列表添加 id1
2
3
4<a href="./aticle/art_list.html" target="fm">
<i class="layui-icon layui-icon-list" id="artList"></i>
文章列表
</a>
5.3.10. 编辑文章
定义
getArticle
函数,获取文章art_pub.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 根据id获取文章
function getArticle(id){
$.ajax({
method: "get",
url: "/my/article/"+id,
success: function(res){
if(res.status==1){
return layer.msg(res.message);
}
form.val("form-edit",res.data);
img
// 销毁旧的裁剪区域
.cropper('destroy')
// 重新设置图片路径
.attr('src', "http://127.0.0.1:3007"+res.data.cover_img)
// 重新初始化裁剪区域
.cropper(options);
}
})
}通过路由判断页面采用发布还是更新
art_pub.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23addOrUpdate(location.href);
// 判断为发布文章还是更新文章
var flag;
var id;
// 当链接中带有id时说明是更新
function addOrUpdate(url){
// 路由中存在 ?id=1
var index = url.indexOf("?id=");
if(index!=-1){
// 更新
flag = false;
// console.log(url.substring(index+4));
// 获取路由中的id值
id = Number(url.substring(index+4));
getArticle(id);
// console.log($("[name=content]").val());
}
else{
// 发布
flag = true;
}
}修改表单的ajax请求,融合发布和更新
art_pub.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// 发布文章函数
function publishArticle(obj,id) {
var url = 'add';
if(!flag){
obj.append("id",id);
url = 'edit';
}
$.ajax({
method: 'POST',
url: '/my/article/'+url,
data: obj,
// 注意:如果向服务器提交的是 FormData 格式的数据,
// 必须添加以下两个配置项
contentType: false,
processData: false,
success: function(res) {
if (res.status == 1) {
return layer.msg(res.message);
}
layer.msg(res.message);
// 发布文章成功后,跳转到文章列表页面
// 跳转至文章列表页
var url = location.href;
url = url.substring(0,url.lastIndexOf("/"));
// console.log(url);
location.href=url+'/art_list.html';
// 点击左边框的文章列表按钮
$("#artList",window.parent.document).click();
}
})
}修改
art_list.html
中的编辑按钮1
<button type="button" class="layui-btn layui-btn-xs btn-edit" data-id={{$value.id}}>编辑</button>
添加编辑按钮点击事件
art_list.js
1
2
3
4
5
6
7
8
9
10
11
12
13// 编辑按钮
$("tbody").on("click",".btn-edit",function(e){
e.preventDefault();
// 跳转至文章编辑页
var url = location.href;
url = url.substring(0,url.lastIndexOf("/"));
// console.log(url);
location.href=url+'/art_pub.html?id='+$(this).data("id");
// 点击左边框的发布文章按钮
$("#artPub",window.parent.document).parent().parent().addClass("layui-this");
$("#artPub",window.parent.document).parent().parent().siblings().removeClass("layui-this");
});最后两行对应
index.html
中的发布文章
和文章列表
1
2
3
4
5
6
7
8
9
10
11
12<dd>
<a href="./aticle/art_list.html" target="fm" >
<i class="layui-icon layui-icon-list" id="artList"></i>
文章列表
</a>
</dd>
<dd >
<a href="./aticle/art_pub.html" target="fm">
<i class="layui-icon layui-icon-edit" id="artPub"></i>
发布文章
</a>
</dd>
5.3.11. 将开发完成的项目代码推送到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成了文章功能的开发"
命令 - 运行 `git push -u origin article命令
- 运行
git checkout master
命令 - 运行
git merge article
命令 - 运行
git push
命令