前端基础第三天项目 大事件后台管理系统
0. 资源地址
- 线上 DEMO 项目地址:http://www.escook.cn:8086/
- 项目的 API 接口地址: https://www.showdoc.cc/escook?page_id=3707158761215217
1. 项目前期的准备工作
1.1 初始化项目结构
- 将
素材
目录下的assets
和home
文件夹,拷贝到code
目录下 - 在
code
目录下新建login.html
和index.html
页面
1.2 使用GitHub管理大事件的项目
- 在
code
目录中运行git init
命令 - 在
code
目录中运行git add .
命令 - 在
code
目录下运行git commit -m "init project"
命令 - 新建 Github 仓库
web_bigevent
- 将本地仓库和Github仓库建立关联关系
- 将本地仓库的代码推送到Github仓库中
- 运行
git checkout -b login
命令,创建并切换到login
分支
1.3 安装VSCode的Live Server插件辅助开发
- 在插件市场,搜索
Live Server
并安装 - 在页面上鼠标右键,选择
Open With Live Server
即可快速使用 http 协议访问页面
2. 登录注册
2.1 绘制login页面的基本结构
编写 HTML 结构:
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><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/login.css" /></head><body><!-- 头部的 Logo 区域 --><div class="layui-main"><img src="/assets/images/logo.png" alt="" /></div><!-- 登录注册区域 --><div class="loginAndRegBox"><div class="title-box"></div></div></body> </html>
美化样式:
html, body {margin: 0;padding: 0;height: 100%;width: 100%;background: url('/assets/images/login_bg.jpg') no-repeat center;background-size: cover; }.loginAndRegBox {width: 400px;height: 310px;background-color: #fff;position: absolute;left: 50%;top: 50%;transform: translate(-50%, -50%); }.title-box {height: 60px;background: url('/assets/images/login_title.png') no-repeat center; }
2.2 实现登录和注册的按需切换
编写 HTML 结构:
<!-- 登录注册区域 --><div class="loginAndRegBox"><div class="title-box"></div><!-- 登录的div --><div class="login-box"></div><!-- 注册的div --><div class="reg-box"></div></div>
编写样式:
.reg-box {display: none; }
编写 JavaScript 代码:
$(function() {// 点击“去注册账号”的链接$('#link_reg').on('click', function() {$('.login-box').hide()$('.reg-box').show()})// 点击“去登录”的链接$('#link_login').on('click', function() {$('.login-box').show()$('.reg-box').hide()}) })
2.3 绘制登录表单的基本结构
编写 HTML 结构:
<!-- 登录的div --><div class="login-box"><!-- 登录的表单 --><form class="layui-form" action=""><!-- 用户名 --><div class="layui-form-item"><i class="layui-icon layui-icon-username"></i><input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input" /></div><!-- 密码 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input" /></div><!-- 登录按钮 --><div class="layui-form-item"><!-- 注意:表单提交按钮和普通按钮的区别,就是 lay-submit 属性 --><button class="layui-btn layui-btn-fluid layui-btn-normal" lay-submit>登录</button></div><div class="layui-form-item links"><a href="javascript:;" id="link_reg">去注册账号</a></div></form></div>
2.4 美化登录表单的样式
编写样式:
.layui-form {padding: 0 30px; }.links {display: flex;justify-content: flex-end; }.links a {font-size: 12px; }
2.5 绘制文本框前面的小图标
在用户名的文本框之前,添加如下的标签结构:
<i class="layui-icon layui-icon-username"></i>
在密码框之前,添加如下的标签结构:
<i class="layui-icon layui-icon-password"></i>
美化样式:
.layui-form-item {position: relative; }.layui-icon {position: absolute;left: 10px;top: 10px; }.layui-input {padding-left: 32px; }
2.6 快速绘制注册的表单
将登录的表单复制一份,并修改为注册的表单即可:
<!-- 注册的div --><div class="reg-box"><!-- 注册的表单 --><form class="layui-form" action=""><!-- 用户名 --><div class="layui-form-item"><i class="layui-icon layui-icon-username"></i><input type="text" name="username" required lay-verify="required" placeholder="请输入用户名" autocomplete="off" class="layui-input" /></div><!-- 密码 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="password" required lay-verify="required" placeholder="请输入密码" autocomplete="off" class="layui-input" /></div><!-- 密码确认框 --><div class="layui-form-item"><i class="layui-icon layui-icon-password"></i><input type="password" name="repassword" required lay-verify="required" placeholder="再次确认密码" autocomplete="off" class="layui-input" /></div><!-- 注册按钮 --><div class="layui-form-item"><!-- 注意:表单提交按钮和普通按钮的区别,就是 lay-submit 属性 --><button class="layui-btn layui-btn-fluid layui-btn-normal" lay-submit>注册</button></div><div class="layui-form-item links"><a href="javascript:;" id="link_login">去登录</a></div></form></div>
2.7 实现登录表单的验证
导入 layui 的 js 文件:
<script src="/assets/lib/layui/layui.all.js"></script>
为需要验证的表单项添加
lay-verify
属性,同时指定具体的校验规则即可。
2.8 自定义校验规则
从 layui 中获取 form 对象:
var form = layui.form
通过 form.verify() 函数自定义校验规则:
form.verify({// 自定义了一个叫做 pwd 校验规则pwd: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格'],// 校验两次密码是否一致的规则repwd: function(value) {// 通过形参拿到的是确认密码框中的内容// 还需要拿到密码框中的内容// 然后进行一次等于的判断// 如果判断失败,则return一个提示消息即可var pwd = $('.reg-box [name=password]').val()if (pwd !== value) {return '两次密码不一致!'}}})
按需为表单项添加校验规则:
<input type="password" name="repassword" required lay-verify="required|pwd|repwd" placeholder="再次确认密码" autocomplete="off" class="layui-input" />
2.9 发起注册用户的Ajax请求
为注册表单添加Id:
<!-- 注册的表单 --> <form class="layui-form" id="form_reg"></form>
监听提交事件:
// 监听注册表单的提交事件$('#form_reg').on('submit', function(e) {// 1. 阻止默认的提交行为e.preventDefault()// 2. 发起Ajax的POST请求var data = {username: $('#form_reg [name=username]').val(),password: $('#form_reg [name=password]').val()}$.post('http://ajax.frontend.itheima.net/api/reguser', data, function(res) {if (res.status !== 0) {return layer.msg(res.message)}layer.msg('注册成功,请登录!')// 模拟人的点击行为$('#link_login').click()})})
2.10 使用layer提示消息
导入 layer:
var layer = layui.layer
调用
layer.msg()
提示消息:layer.msg('注册成功,请登录!')
2.11 发起登录的Ajax请求
为登录表单添加id:
<form class="layui-form" id="form_login"></form>
监听提交事件:
// 监听登录表单的提交事件$('#form_login').submit(function(e) {// 阻止默认提交行为e.preventDefault()$.ajax({url: '/api/login',method: 'POST',// 快速获取表单中的数据data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('登录失败!')}layer.msg('登录成功!')// 将登录成功得到的 token 字符串,保存到 localStorage 中localStorage.setItem('token', res.token)// 跳转到后台主页location.href = '/index.html'}})})
2.12 在ajaxPrefilter中统一拼接请求的根路径
在
/assets/js
目录中新建baseAPI.js
编写如下代码:
// 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候, // 会先调用 ajaxPrefilter 这个函数 // 在这个函数中,可以拿到我们给Ajax提供的配置对象 $.ajaxPrefilter(function(options) {// 在发起真正的 Ajax 请求之前,统一拼接请求的根路径options.url = 'http://ajax.frontend.itheima.net' + options.url })
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 官方文档中粘贴布局的主要代码,并修改如下:
<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>后台主页</title><!-- 导入 layui 的样式表 --><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /></head><body class="layui-layout-body"><div class="layui-layout layui-layout-admin"><div class="layui-header"><div class="layui-logo"><img src="/assets/images/logo.png" alt="" /></div><!-- 头部区域(可配合layui已有的水平导航) --><ul class="layui-nav layui-layout-right"><li class="layui-nav-item"><a href="javascript:;"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" />个人中心</a><dl class="layui-nav-child"><dd><a href="">基本资料</a></dd><dd><a href="">更换头像</a></dd><dd><a href="">重置密码</a></dd></dl></li><li class="layui-nav-item"><a href="">退出</a></li></ul></div><div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-filter="test"><li class="layui-nav-item layui-nav-itemed"><a class="" href="javascript:;">所有商品</a><dl class="layui-nav-child"><dd><a href="javascript:;">列表一</a></dd><dd><a href="javascript:;">列表二</a></dd><dd><a href="javascript:;">列表三</a></dd><dd><a href="">超链接</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">解决方案</a><dl class="layui-nav-child"><dd><a href="javascript:;">列表一</a></dd><dd><a href="javascript:;">列表二</a></dd><dd><a href="">超链接</a></dd></dl></li><li class="layui-nav-item"><a href="">云市场</a></li><li class="layui-nav-item"><a href="">发布商品</a></li></ul></div></div><div class="layui-body"><!-- 内容主体区域 --><div style="padding: 15px;">内容主体区域</div></div><div class="layui-footer"><!-- 底部固定区域 -->© layui.com - 底部固定区域</div></div><!-- 导入 layui 的JS文件 --><script src="/assets/lib/layui/layui.all.js"></script></body> </html>
3.2 修改侧边栏的结构
<div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree"><li class="layui-nav-item"><a href="/">首页</a></li><li class="layui-nav-item"><a class="" href="javascript:;">文章管理</a><dl class="layui-nav-child"><dd><a href="javascript:;">文章类别</a></dd><dd><a href="javascript:;">文章列表</a></dd><dd><a href="javascript:;">发布文章</a></dd></dl></li><li class="layui-nav-item"><a href="javascript:;">个人中心</a><dl class="layui-nav-child"><dd><a href="javascript:;">基本资料</a></dd><dd><a href="javascript:;">更换头像</a></dd><dd><a href="javascript:;">重置密码</a></dd></dl></li></ul></div></div>
3.3 使用lay-shrink实现左侧菜单互斥效果
<div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-shrink="all"><!-- 省略其他代码 --></ul></div></div>
3.4 为菜单项添加图标
导入第三方的图标库:
<!-- 导入第三方图标库 --> <link rel="stylesheet" href="/assets/fonts/iconfont.css" />
修改左侧菜单的结构:
<div class="layui-side layui-bg-black"><div class="layui-side-scroll"><!-- 左侧导航区域(可配合layui已有的垂直导航) --><ul class="layui-nav layui-nav-tree" lay-shrink="all"><li class="layui-nav-item"><a href=""><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-app"></i>文章列表</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></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-app"></i>基本资料</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>更换头像</a></dd><dd><a href="javascript:;"><i class="layui-icon layui-icon-app"></i>重置密码</a></dd></dl></li></ul></div></div>
修改头部“退出”按钮的结构:
<li class="layui-nav-item"><a href=""><span class="iconfont icon-tuichu"></span>退出</a> </li>
导入自己的样式表文件:
<link rel="stylesheet" href="/assets/css/index.css" />
编写自己的样式:
.layui-footer {text-align: center;font-size: 12px; }.iconfont {margin-right: 8px; }.layui-icon {margin-right: 8px;margin-left: 20px; }
3.5 使用iframe标签在内容主体区域显示网页内容
在页面主体的 div 中添加
iframe
:<div class="layui-body"><!-- 内容主体区域 --><iframe name="fm" src="" frameborder="0"></iframe></div>
为
首页
链接添加href
和target
属性:<a href="/home/dashboard.html" target="fm"><span class="iconfont icon-home"></span>首页</a>
美化样式:
iframe {width: 100%;height: 100%; }.layui-body {overflow: hidden; }
3.6 解决3个小问题
为
iframe
指定默认页面:<iframe name="fm" src="/home/dashboard.html" frameborder="0"></iframe>
为
首页
对应的导航 Item 项添加layui-this
属性:<li class="layui-nav-item layui-this"><a href="/home/dashboard.html" target="fm"><span class="iconfont icon-home"></span>首页</a> </li>
强制清除
<a>
链接的 CSS3 动画:a {transition: none !important; }
3.7 渲染图片头像和文字头像
修改头部区域的的头像结构如下:
<a href="javascript:;" class="userinfo"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" /><span class="text-avatar">A</span>个人中心 </a>
在左侧导航区域的
ul
之前添加如下头像结构:<div class="userinfo"><img src="http://t.cn/RCzsdCq" class="layui-nav-img" /><span class="text-avatar">A</span><span id="welcome">欢迎 ***</span> </div>
添加样式美化 UI 结构:
.userinfo {height: 60px;line-height: 60px;text-align: center;font-size: 12px;user-select: none; }.layui-side-scroll .userinfo {border-bottom: 1px solid #282b33; }.layui-nav-img {width: 40px;height: 40px; }.text-avatar {display: inline-block;width: 40px;height: 40px;background-color: #009688;border-radius: 50%;line-height: 40px;text-align: center;font-size: 20px;color: #fff;position: relative;top: 4px;margin-right: 10px; }
1. 后台主页
1.1 获取用户的基本信息
导入需要的脚本:
<!-- 导入 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 函数:
// 获取用户的基本信息 function getUserInfo() {$.ajax({method: 'GET',url: '/my/userinfo',// headers 就是请求头配置对象headers: {Authorization: localStorage.getItem('token') || ''},success: function(res) {if (res.status !== 0) {return layui.layer.msg('获取用户信息失败!')}// 调用 renderAvatar 渲染用户的头像renderAvatar(res.data)}}) }
1.2 渲染用户头像
定义 renderAvatar 函数:
// 渲染用户的头像 function renderAvatar(user) {// 1. 获取用户的名称var name = user.nickname || user.username// 2. 设置欢迎的文本$('#welcome').html('欢迎 ' + name)// 3. 按需渲染用户的头像if (user.user_pic !== null) {// 3.1 渲染图片头像$('.layui-nav-img').attr('src', user.user_pic).show()$('.text-avatar').hide()} else {// 3.2 渲染文本头像$('.layui-nav-img').hide()var first = name[0].toUpperCase()$('.text-avatar').html(first).show()} }
1.3 统一为有权限的接口设置headers请求头
在 baseAPI的
ajaxPrefilter
中添加如下代码:// 统一为有权限的接口,设置 headers 请求头if (options.url.indexOf('/my/') !== -1) {options.headers = {Authorization: localStorage.getItem('token') || ''}}
1.4 实现退出功能
修改退出的
<a>
链接如下:<a href="javascript:;" id="btnLogout"><span class="iconfont icon-tuichu"></span>退出</a>
实现退出功能:
var layer = layui.layer// 点击按钮,实现退出功能$('#btnLogout').on('click', function() {// 提示用户是否确认退出layer.confirm('确定退出登录?', { icon: 3, title: '提示' }, function(index) {//do something// 1. 清空本地存储中的 tokenlocalStorage.removeItem('token')// 2. 重新跳转到登录页面location.href = '/login.html'// 关闭 confirm 询问框layer.close(index)})})
1.5 控制用户的访问权限
在调用有权限接口的时候,指定
complete
回调函数:// 不论成功还是失败,最终都会调用 complete 回调函数complete: function(res) {// console.log('执行了 complete 回调:')// console.log(res)// 在 complete 回调函数中,可以使用 res.responseJSON 拿到服务器响应回来的数据if (res.responseJSON.status === 1 && res.responseJSON.message === '身份认证失败!') {// 1. 强制清空 tokenlocalStorage.removeItem('token')// 2. 强制跳转到登录页面location.href = '/login.html'}}
1.6 优化权限控制的代码
将权限控制的代码,从每个请求中,抽离到
ajaxPrefilter
中:// 注意:每次调用 $.get() 或 $.post() 或 $.ajax() 的时候, // 会先调用 ajaxPrefilter 这个函数 // 在这个函数中,可以拿到我们给Ajax提供的配置对象 $.ajaxPrefilter(function(options) {// 在发起真正的 Ajax 请求之前,统一拼接请求的根路径options.url = 'http://ajax.frontend.itheima.net' + options.url// 统一为有权限的接口,设置 headers 请求头if (options.url.indexOf('/my/') !== -1) {options.headers = {Authorization: localStorage.getItem('token') || ''}}// 全局统一挂载 complete 回调函数options.complete = function(res) {// console.log('执行了 complete 回调:')// console.log(res)// 在 complete 回调函数中,可以使用 res.responseJSON 拿到服务器响应回来的数据if (res.responseJSON.status === 1 && res.responseJSON.message === '身份认证失败!') {// 1. 强制清空 tokenlocalStorage.removeItem('token')// 2. 强制跳转到登录页面location.href = '/login.html'}} })
2. 基本资料
2.1 创建基本资料对应的页面
新建
/user/user_info.html
并初始化如下:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><!-- 导入 layui 的样式 --><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><!-- 导入自己的样式 --><link rel="stylesheet" href="/assets/css/user/user_info.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">修改用户信息</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div></body> </html>
新建
/assets/css/user/user_info.css
并初始化如下:html, body {margin: 0;padding: 0; }body {background-color: #f2f3f5;padding: 15px; }
修改
index.html
中对应的<a>
链接:<a href="/user/user_info.html" target="fm"><i class="layui-icon layui-icon-app"></i>基本资料</a>
2.2 绘制基本资料对应的表单
编写如下的表单结构:
<!-- form 表单区域 --><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" readonly /></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|nickname" 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>
在页面底部导入如下的脚本:
<!-- 导入 layui 的 js --><script src="/assets/lib/layui/layui.all.js"></script><!-- 导入 jquery --><script src="/assets/lib/jquery.js"></script><!-- 导入自己的 js --><script src="/assets/js/user/user_info.js"></script>
在
user_info.js
中编写如下的代码:$(function() {var form = layui.formform.verify({nickname: function(value) {if (value.length > 6) {return '昵称长度必须在 1 ~ 6 个字符之间!'}}}) })
2.3 获取用户的基本信息
导入
baseAPI
:<script src="/assets/js/baseAPI.js"></script>
在
user_info.js
中定义并调用initUserInfo
函数:initUserInfo()// 初始化用户的基本信息function initUserInfo() {$.ajax({method: 'GET',url: '/my/userinfo',success: function(res) {if (res.status !== 0) {return layer.msg('获取用户信息失败!')}console.log(res)}})}
2.4 使用form.val方法快速为表单赋值
为表单指定
lay-filter
属性:<form class="layui-form" lay-filter="formUserInfo"></form>
调用
form.val()
方法为表单赋值:form.val('formUserInfo', res.data)
使用隐藏域保存用户的
id
值:<!-- form 表单区域 --> <form class="layui-form" lay-filter="formUserInfo"><!-- 这是隐藏域 --><input type="hidden" name="id" value="" /><!-- 省略其他代码 --> </form>
2.5 实现表单的重置效果
阻止表单的默认重置行为,再重新获取用户信息即可:
// 重置表单的数据$('#btnReset').on('click', function(e) {// 阻止表单的默认重置行为e.preventDefault()initUserInfo()})
2.6 发起请求更新用户的信息
阻止表单的默认提交行为,并发起数据请求:
// 监听表单的提交事件$('.layui-form').on('submit', function(e) {// 阻止表单的默认提交行为e.preventDefault()// 发起 ajax 数据请求$.ajax({method: 'POST',url: '/my/userinfo',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('更新用户信息失败!')}layer.msg('更新用户信息成功!')// 调用父页面中的方法,重新渲染用户的头像和用户的信息window.parent.getUserInfo()}})})
注意:
<iframe>
中的子页面,如果想要调用父页面中的方法,使用window.parent
即可。
3. 重置密码
3.1 渲染重置密码的页面结构
在
/user/user_pwd.html
页面中编写如下的结构:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/user/user_pwd.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">修改密码</div><div class="layui-card-body"><form class="layui-form"><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">重置</button></div></div></form></div></div></body> </html>
在
/assets/css/user/user_pwd.css
中编写如下的样式:html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }.layui-form {width: 500px; }
3.2 为密码框定义校验规则
定义如下的三个校验规则:
$(function() {var form = layui.formform.verify({pwd: [/^[\S]{6,12}$/, '密码必须6到12位,且不能出现空格'],samePwd: function(value) {if (value === $('[name=oldPwd]').val()) {return '新旧密码不能相同!'}},rePwd: function(value) {if (value !== $('[name=newPwd]').val()) {return '两次密码不一致!'}}}) })
在 body 结束标签之前导入如下的
script
标签:<!-- 导入 layui 的 js --> <script src="/assets/lib/layui/layui.all.js"></script> <!-- 导入 jQuery --> <script src="/assets/lib/jquery.js"></script> <!-- 导入 baseAPI --> <script src="/assets/js/baseAPI.js"></script> <!-- 导入自己的 js --> <script src="/assets/js/user/user_pwd.js"></script>
为密码框分别添加对应的校验规则:
<form class="layui-form"><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">重置</button></div></div> </form>
3.3 发起请求实现重置密码的功能
$('.layui-form').on('submit', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/updatepwd',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layui.layer.msg('更新密码失败!')}layui.layer.msg('更新密码成功!')// 重置表单$('.layui-form')[0].reset()}})})
4. 更换头像
4.1 初步渲染更换头像页面的结构
创建
/user/user_avatar.html
页面:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><link rel="stylesheet" href="/assets/lib/layui/css/layui.css" /><link rel="stylesheet" href="/assets/css/user/user_avatar.css" /></head><body><!-- 卡片区域 --><div class="layui-card"><div class="layui-card-header">更换头像</div><div class="layui-card-body">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div></body> </html>
美化基本样式:
html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
修改
index.html
中对应链接的属性:<a href="/user/user_avatar.html" target="fm"><i class="layui-icon layui-icon-app"></i>更换头像</a>
4.2 实现裁剪区域图片的替换
// 为文件选择框绑定 change 事件$('#file').on('change', function(e) {// 获取用户选择的文件var filelist = e.target.filesif (filelist.length === 0) {return layer.msg('请选择照片!')}// 1. 拿到用户选择的文件var file = e.target.files[0]// 2. 将文件,转化为路径var imgURL = URL.createObjectURL(file)// 3. 重新初始化裁剪区域$image.cropper('destroy') // 销毁旧的裁剪区域.attr('src', imgURL) // 重新设置图片路径.cropper(options) // 重新初始化裁剪区域})
4.3 将裁剪后的头像上传到服务器
// 为确定按钮,绑定点击事件$('#btnUpload').on('click', function() {// 1. 要拿到用户裁剪之后的头像var dataURL = $image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 100,height: 100}).toDataURL('image/png') // 将 Canvas 画布上的内容,转化为 base64 格式的字符串// 2. 调用接口,把头像上传到服务器$.ajax({method: 'POST',url: '/my/update/avatar',data: {avatar: dataURL},success: function(res) {if (res.status !== 0) {return layer.msg('更换头像失败!')}layer.msg('更换头像成功!')window.parent.getUserInfo()}})})
4.4 设置头部区域的快捷方式
打开
index.html
,修改头部个人中心
下的三个快捷方式如下:<dl class="layui-nav-child"><dd><a href="/user/user_info.html" target="fm">基本资料</a></dd><dd><a href="/user/user_avatar.html" target="fm">更换头像</a></dd><dd><a href="/user/user_pwd.html" target="fm">重置密码</a></dd> </dl>
5. 文章分类
5.1 创建并显示文章分类页面
创建
/article/art_cate.html
页面,并初始化如下的UI结构:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</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 layui-btn-sm">添加类别</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>人生就像是一场修行</td></tr><tr><td>许闲心</td><td>2016-11-28</td><td>于千万人之中遇见你所遇见的人,于千万年之中,时间的无涯的荒野里…</td></tr></tbody></table></div></div></body> </html>
定义
/assets/css/article/art_cate.css
美化样式:html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }.layui-card-header {display: flex;justify-content: space-between;align-items: center; }
修改
index.html
中对应的<a>
链接:<a href="/article/art_cate.html" target="fm"><i class="layui-icon layui-icon-app"></i>文章类别</a>
5.2 获取并使用模板引擎渲染表格的数据
在页面底部导入模板引擎:
<script src="/assets/lib/template-web.js"></script>
定义模板:
<!-- 表格数据的模板 --><script type="text/html" id="tpl-table">{{each data}}<tr><td>{{$value.name}}</td><td>{{$value.alias}}</td><td><button type="button" class="layui-btn layui-btn-xs">编辑</button><button type="button" class="layui-btn layui-btn-danger layui-btn-xs">删除</button></td></tr>{{/each}}</script>
发起请求获取数据:
initArtCateList()// 获取文章分类的列表function initArtCateList() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)}})}
5.3 使用layer.open实现弹出层效果
导入
layer
:var layer = layui.layer
为按钮添加
id
属性:<button type="button" class="layui-btn layui-btn-normal layui-btn-sm" id="btnAddCate">添加类别</button>
在按钮的点击事件中,通过
layer.open()
展示弹出层:// 为添加类别按钮绑定点击事件$('#btnAddCate').on('click', function() {layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: 'ABC'})})
5.4 在弹出层中渲染form表单结构
在页面中定义如下的
script
标签:<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" 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
属性指定内容:layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: $('#dialog-add').html()})
5.5 实现添加文章分类的功能
发起Ajax请求:
// 通过代理的形式,为 form-add 表单绑定 submit 事件$('body').on('submit', '#form-add', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/article/addcates',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('新增分类失败!')}initArtCateList()layer.msg('新增分类成功!')// 根据索引,关闭对应的弹出层layer.close(indexAdd)}})})
预先保存弹出层的索引:
// 为添加类别按钮绑定点击事件var indexAdd = null$('#btnAddCate').on('click', function() {indexAdd = layer.open({type: 1,area: ['500px', '250px'],title: '添加文章分类',content: $('#dialog-add').html()})})
1. 文章类别
1.1 点击编辑按钮展示修改文章分类的弹出层
为编辑按钮添加
btn-edit
类名如下:<button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">编辑</button>
定义
修改分类
的弹出层:<script type="text/html" id="dialog-edit"><form class="layui-form" id="form-edit" lay-filter="form-edit"><!-- 隐藏域,保存 Id 的值 --><input type="hidden" name="Id"><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" 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></div></div></form></script>
通过
代理
的形式,为btn-edit
按钮绑定点击事件:var indexEdit = null$('tbody').on('click', '.btn-edit', function() {// 弹出一个修改文章分类信息的层indexEdit = layer.open({type: 1,area: ['500px', '250px'],title: '修改文章分类',content: $('#dialog-edit').html()})})
1.2 为修改文章分类的弹出层填充表单数据
为编辑按钮绑定
data-id
自定义属性:<button type="button" class="layui-btn layui-btn-xs btn-edit" data-id="{{$value.Id}}">编辑</button>
在展示弹出层之后,根据 id 的值发起请求获取文章分类的数据,并填充到表单中:
var id = $(this).attr('data-id') // 发起请求获取对应分类的数据 $.ajax({method: 'GET',url: '/my/article/cates/' + id,success: function(res) {form.val('form-edit', res.data)} })
1.3 更新文章分类的数据
通过代理的形式,为修改分类的表单绑定 submit 事件:
$('body').on('submit', '#form-edit', function(e) {e.preventDefault()$.ajax({method: 'POST',url: '/my/article/updatecate',data: $(this).serialize(),success: function(res) {if (res.status !== 0) {return layer.msg('更新分类数据失败!')}layer.msg('更新分类数据成功!')layer.close(indexEdit)initArtCateList()}}) })
1.4 删除文章分类
为删除按钮绑定
btn-delete
类名,并添加data-id
自定义属性:<button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
通过代理的形式,为删除按钮绑定点击事件:
$('tbody').on('click', '.btn-delete', function() {var id = $(this).attr('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('删除分类失败!')}layer.msg('删除分类成功!')layer.close(index)initArtCateList()}})}) })
2. 文章列表
2.1 创建文章列表页面
新建
/article/art_list.html
页面结构如下:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><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"></div></div><!-- 导入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 导入自己的 JS 脚本 --><script src="/assets/js/article/art_list.js"></script></body> </html>
新建
/assets/css/article/art_list.css
样式表如下:html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
新建
/assets/js/article/art_list.js
脚本文件。
2.2 定义查询参数对象q
定义一个查询的参数对象如下:
// 定义一个查询的参数对象,将来请求数据的时候,// 需要将请求参数对象提交到服务器var q = {pagenum: 1, // 页码值,默认请求第一页的数据pagesize: 2, // 每页显示几条数据,默认每页显示2条cate_id: '', // 文章分类的 Idstate: '' // 文章的发布状态}
2.3 请求文章列表数据并使用模板引擎渲染列表结构
定义获取文章列表数据的方法如下:
initTable() // 获取文章列表数据的方法 function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('获取文章列表失败!')}// 使用模板引擎渲染页面的数据var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)}}) }
在页面中添加表格结构如下:
<!-- 列表区域 --> <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>
定义列表数据的模板结构:
<script type="text/html" id="tpl-table">{{each data}}<tr><td>{{$value.title}}</td><td>{{$value.cate_name}}</td><td>{{$value.pub_date|dataFormat}}</td><td>{{$value.state}}</td><td><button type="button" class="layui-btn layui-btn-xs">编辑</button><button type="button" class="layui-btn layui-btn-danger layui-btn-xs">删除</button></td></tr>{{/each}}</script>
2.4 定义美化时间格式的过滤器
通过
template.defaults.imports
定义过滤器:// 定义美化时间的过滤器template.defaults.imports.dataFormat = function(date) {const dt = new Date(date)var y = dt.getFullYear()var m = padZero(dt.getMonth() + 1)var d = padZero(dt.getDate())var hh = padZero(dt.getHours())var mm = padZero(dt.getMinutes())var ss = padZero(dt.getSeconds())return y + '-' + m + '-' + d + ' ' + hh + ':' + mm + ':' + ss}// 定义补零的函数function padZero(n) {return n > 9 ? n : '0' + n}
在模板引擎中使用过滤器:
<td>{{$value.pub_date|dataFormat}}</td>
2.5 绘制筛选区域的UI结构
绘制 UI 结构:
<!-- 筛选区域 --> <form class="layui-form" id="form-search"><div class="layui-form-item layui-inline"><select name="cate_id"></select></div><div class="layui-form-item layui-inline"><select name="state"><option value="">所有状态</option><option value="已发布">已发布</option><option value="草稿">草稿</option></select></div><div class="layui-form-item layui-inline"><button class="layui-btn" lay-submit lay-filter="formDemo">筛选</button></div> </form>
2.6 发起请求获取并渲染文章分类的下拉选择框
定义
initCate
函数请求文章分类的列表数据:initCate()// 初始化文章分类的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('获取分类数据失败!')}// 调用模板引擎渲染分类的可选项var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 通过 layui 重新渲染表单区域的UI结构form.render()}})}
定义分类可选项的模板结构:
<script type="text/html" id="tpl-cate"><option value="">所有分类</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</script>
2.7 实现筛选的功能
为筛选表单绑定 submit 事件:
$('#form-search').on('submit', function(e) {e.preventDefault()// 获取表单中选中项的值var cate_id = $('[name=cate_id]').val()var state = $('[name=state]').val()// 为查询参数对象 q 中对应的属性赋值q.cate_id = cate_idq.state = state// 根据最新的筛选条件,重新渲染表格的数据initTable() })
3. 分页
3.1 定义渲染分页的 renderPage 方法
定义渲染分页的方法:
function renderPage(total) {console.log(total) }
在
initTable
中调用renderPage
方法:function initTable() {$.ajax({method: 'GET',url: '/my/article/list',data: q,success: function(res) {if (res.status !== 0) {return layer.msg('获取文章列表失败!')}// 使用模板引擎渲染页面的数据var htmlStr = template('tpl-table', res)$('tbody').html(htmlStr)// 调用渲染分页的方法renderPage(res.total)}}) }
3.2 调用 laypage.render 方法渲染分页的基本结构
在页面中定义分页的区域:
<!-- 分页区域 --> <div id="pageBox"></div>
调用 laypage.render() 方法来渲染分页的结构:
// 定义渲染分页的方法 function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum // 设置默认被选中的分页}) }
3.3 在jump回调函数中通过obj.curr获取到最新的页码值
// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页// 分页发生切换的时候,触发 jump 回调jump: function(obj) {console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr}})
}
3.4 解决 jump 回调函数发生死循环的问题
// 定义渲染分页的方法function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})}
3.5 自定义分页的功能项
// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})
}
3.6 实现切换每页展示多少条数据的功能
// 定义渲染分页的方法
function renderPage(total) {// 调用 laypage.render() 方法来渲染分页的结构laypage.render({elem: 'pageBox', // 分页容器的 Idcount: total, // 总数据条数limit: q.pagesize, // 每页显示几条数据curr: q.pagenum, // 设置默认被选中的分页layout: ['count', 'limit', 'prev', 'page', 'next', 'skip'],limits: [2, 3, 5, 10],// 分页发生切换的时候,触发 jump 回调// 触发 jump 回调的方式有两种:// 1. 点击页码的时候,会触发 jump 回调// 2. 只要调用了 laypage.render() 方法,就会触发 jump 回调jump: function(obj, first) {// 可以通过 first 的值,来判断是通过哪种方式,触发的 jump 回调// 如果 first 的值为 true,证明是方式2触发的// 否则就是方式1触发的console.log(first)console.log(obj.curr)// 把最新的页码值,赋值到 q 这个查询参数对象中q.pagenum = obj.curr// 把最新的条目数,赋值到 q 这个查询参数对象的 pagesize 属性中q.pagesize = obj.limit// 根据最新的 q 获取对应的数据列表,并渲染表格// initTable()if (!first) {initTable()}}})
}
4. 删除文章
4.1 实现删除文章的功能
为删除按钮绑定
btn-delete
类名和data-id
自定义属性:<button type="button" class="layui-btn layui-btn-danger layui-btn-xs btn-delete" data-id="{{$value.Id}}">删除</button>
通过代理的形式,为删除按钮绑定点击事件处理函数:
$('tbody').on('click', '.btn-delete', function() {// 获取到文章的 idvar id = $(this).attr('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('删除文章失败!')}layer.msg('删除文章成功!')initTable()}})layer.close(index)}) })
4.2 解决删除文章时的小 Bug
$('tbody').on('click', '.btn-delete', function() {// 获取删除按钮的个数var len = $('.btn-delete').length// 获取到文章的 idvar id = $(this).attr('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('删除文章失败!')}layer.msg('删除文章成功!')// 当数据删除完成后,需要判断当前这一页中,是否还有剩余的数据// 如果没有剩余的数据了,则让页码值 -1 之后,// 再重新调用 initTable 方法// 4if (len === 1) {// 如果 len 的值等于1,证明删除完毕之后,页面上就没有任何数据了// 页码值最小必须是 1q.pagenum = q.pagenum === 1 ? 1 : q.pagenum - 1}initTable()}})layer.close(index)})
})
5. 发布文章
5.1 创建文章发布页面的基本结构
新建
/article/art_pub.html
页面结构如下:<!DOCTYPE html> <html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Document</title><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">卡片式面板面板通常用于非白色背景色的主体内<br />从而映衬出边框投影</div></div><!-- 导入第三方的 JS 插件 --><script src="/assets/lib/layui/layui.all.js"></script><script src="/assets/lib/jquery.js"></script><script src="/assets/js/baseAPI.js"></script><!-- 导入自己的 JS --><script src="/assets/js/article/art_pub.js"></script></body> </html>
新建
/assets/css/article/art_pub.css
样式文件如下:html, body {margin: 0;padding: 0; }body {padding: 15px;background-color: #f2f3f5; }
新建
/assets/js/article/art_pub.js
脚本文件如下:$(function() { })
5.2 新建基本的表单结构
<!-- 发布文章的表单 -->
<form class="layui-form"><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>
</form>
5.3 渲染文章类别对应的下拉选择框结构
定义 UI 结构:
<!-- 第二行 --><div class="layui-form-item"><label class="layui-form-label">文章类别</label><div class="layui-input-block"><select name="cate_id" lay-verify="required"></select></div></div>
导入 art-template:
<script src="/assets/lib/template-web.js"></script>
定义模板结构:
<script type="text/html" id="tpl-cate"><option value="">请选择文章类别</option>{{each data}}<option value="{{$value.Id}}">{{$value.name}}</option>{{/each}}</script>
定义
initCate
方法:$(function() {var layer = layui.layervar form = layui.forminitCate()// 定义加载文章分类的方法function initCate() {$.ajax({method: 'GET',url: '/my/article/cates',success: function(res) {if (res.status !== 0) {return layer.msg('初始化文章分类失败!')}// 调用模板引擎,渲染分类的下拉菜单var htmlStr = template('tpl-cate', res)$('[name=cate_id]').html(htmlStr)// 一定要记得调用 form.render() 方法form.render()}})} })
5.4 渲染富文本编辑器
参考
素材/富文本和封面.md
中的实现步骤
5.5 渲染封面裁剪区域
参考
素材/富文本和封面.md
中的实现步骤
5.6 渲染提交按钮区域
<!-- 第五行 --><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>
5.7 点击选择封面按钮打开文件选择框
修改 UI 结构,为
选择封面
按钮添加id
,并且在按钮后面添加文件选择框
:<!-- 选择封面按钮 --> <button type="button" class="layui-btn layui-btn-danger" id="btnChooseImage">选择封面</button> <!-- 隐藏的文件选择框 --> <input type="file" id="coverFile" style="display: none;" accept="image/png,image/jpeg,image/gif" />
为选择封面的按钮,绑定点击事件处理函数:
$('#btnChooseImage').on('click', function() {$('#coverFile').click() })
5.8 将选择的图片设置到裁剪区域中
监听
coverFile
的change
事件,获取用户选择的文件列表:// 监听 coverFile 的 change 事件,获取用户选择的文件列表$('#coverFile').on('change', function(e) {// 获取到文件的列表数组var files = e.target.files// 判断用户是否选择了文件if (files.length === 0) {return}// 根据文件,创建对应的 URL 地址var newImgURL = URL.createObjectURL(files[0])// 为裁剪区域重新设置图片$image.cropper('destroy') // 销毁旧的裁剪区域.attr('src', newImgURL) // 重新设置图片路径.cropper(options) // 重新初始化裁剪区域})
5.9 分析发布文章的实现步骤
为
存为草稿
按钮添加id
属性:<button class="layui-btn layui-btn-primary" lay-submit id="btnSave2">存为草稿</button>
定义文章的发布状态:
var art_state = '已发布'
为存为草稿按钮,绑定点击事件处理函数:
$('#btnSave2').on('click', function() {art_state = '草稿' })
5.10 基于Form表单创建FormData对象
为发布文章的 Form 表单添加
id
属性:<form class="layui-form" id="form-pub"></form>
为表单绑定 submit 提交事件:
$('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)})
5.11 将裁剪后的封面追加到FormData对象中
// 为表单绑定 submit 提交事件$('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)// 4. 将封面裁剪过后的图片,输出为一个文件对象$image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 400,height: 280}).toBlob(function(blob) {// 将 Canvas 画布上的内容,转化为文件对象// 得到文件对象后,进行后续的操作// 5. 将文件对象,存储到 fd 中fd.append('cover_img', blob)// 6. 发起 ajax 数据请求})})
5.12 发起Ajax请求实现发布文章的功能
定义一个发布文章的方法:
function publishArticle(fd) {$.ajax({method: 'POST',url: '/my/article/add',data: fd,// 注意:如果向服务器提交的是 FormData 格式的数据,// 必须添加以下两个配置项contentType: false,processData: false,success: function(res) {if (res.status !== 0) {return layer.msg('发布文章失败!')}layer.msg('发布文章成功!')// 发布文章成功后,跳转到文章列表页面location.href = '/article/art_list.html'}}) }
把裁剪的图片追加到
FormData
对象中之后,调用publishArticle
方法:// 为表单绑定 submit 提交事件 $('#form-pub').on('submit', function(e) {// 1. 阻止表单的默认提交行为e.preventDefault()// 2. 基于 form 表单,快速创建一个 FormData 对象var fd = new FormData($(this)[0])// 3. 将文章的发布状态,存到 fd 中fd.append('state', art_state)// 4. 将封面裁剪过后的图片,输出为一个文件对象$image.cropper('getCroppedCanvas', {// 创建一个 Canvas 画布width: 400,height: 280}).toBlob(function(blob) {// 将 Canvas 画布上的内容,转化为文件对象// 得到文件对象后,进行后续的操作// 5. 将文件对象,存储到 fd 中fd.append('cover_img', blob)// 6. 发起 ajax 数据请求publishArticle(fd)}) })
5.13 将开发完成的项目代码推送到GitHub
- 运行
git add .
命令 - 运行
git commit -m "完成文章管理相关功能的开发"
命令 - 运行
git push -u origin article
命令 - 运行
git checkout master
命令 - 运行
git merge article
命令 - 运行
git push
命令
前端基础第三天项目 大事件后台管理系统相关推荐
- 大事件后台管理系统开发实战(下)
文章目录 续前篇:大事件后台管理系统开发实战(中) 1. 文章类别 1.1 点击编辑按钮展示修改文章分类的弹出层 1.2 为修改文章分类的弹出层填充表单数据 1.3 更新文章分类的数据 1.4 删除文 ...
- 大事件后台管理系统开发实战(上)
文章目录 前言 0. 资源地址 1. 项目前期的准备工作 1.1 初始化项目结构 1.2 使用GitHub管理大事件的项目 1.3 安装VSCode的Live Server插件辅助开发 2. 登录注册 ...
- 大事件后台管理系统——个人中心
1.创建验证规则函数 个人中心--基本资料:用来修改用户信息 针对表单不同类型的数据需要设定验证规则函数,只有输入正确才能提交表单 form.verify({nickname: function(va ...
- 大事件后台管理系统——文章管理
1.文章类别模块 1.1获取文章分类的列表 利用模版引擎快速渲染表格数据 <!-- 表格数据的模板 --><script type="text/html" id= ...
- 大事件后台管理系统开发实战(中)
文章目录 3. 后台主页 3.8 获取用户的基本信息 3.9 渲染用户头像 3.10为有权限的接口统一设置headers请求头 3.11 实现退出功能 3.12 控制用户的访问权限 3.13 优化权限 ...
- 第三代半导体项目大事件盘点
如果说以硅为代表的第一代半导体是集成电路的基石,第二代半导体如砷化镓促成了信息高速公路的崛起的话,那么第三代半导体材料技术正在成为抢占下一代信息技术.节能减排及国防安全制高点的最佳途径之一,是战略性新 ...
- 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框
文章目录 目标 代码 0.结构 1.按钮-删除 2.按钮-编辑 3.debug 4.样式 5.分页Pagination:功能 6.分页Pagination:样式 7.搜索框:功能 8.搜索框:样式 总 ...
- 【JavaWeb】JavaWeb项目实战——品牌后台管理系统
JavaWeb项目实战--品牌后台管理系统 项目概述 功能介绍 成果展示 项目实现 使用Maven构建项目 Maven介绍 具体操作 使用Mybatis封装对数据库的操作 在Mysql中建表,并添加数 ...
- 【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出
文章目录 目标 代码 0.页面结构 1.新增按钮和弹出表单:结构 2.新增按钮和弹出表单:点击新增弹出表单 3.表单样式 4.表单验证 5.表单的提交和取消功能:接口.mock相关准备 6.表单的提交 ...
最新文章
- Fedora 15 安装与配置一览
- SQLLite (一)基本介绍
- 我们再也看不到“Win 10 破解版下载”
- 查询mysql临时表空间_查看临时表空间使用情况
- vue中cookie的使用——将cookie放在请求头header中
- linux服务器学习笔记:linux忘记密码怎么办?
- 连接服务器打印机文件名无效,excel服务器-办公室常识——共享服务器文件报错,共享打印机无法打印的解决办法(解决word、excel不能打印))...
- R语言及Rstudio入门小建议(一)
- 计算机审计中级培训班,计算机审计中级培训心得体会
- 代码编辑器CodeMirror及其简单的配置
- excel删除无尽空白行_批量删除空白行其实很简单,这3中方法都能快速搞定,简单易学...
- 10015---技术栈
- WeWork上演宫斗大戏,这个市还上吗?
- 关于外卖骑手被困在算法里的问题解决方法浅析
- 7-2 后序+中序序列构造二叉树
- java校验商品价格的正则表达式
- i html设置为不倾斜,css如何不让字体倾斜?
- a15仿生芯片和骁龙8gen1 哪个好
- PLC学习第一篇:PLC程序架构
- codesign想要访问您的钥匙串中的密钥
热门文章
- 目标检测模型——One stage(YOLO v5的模型解析及应用)
- 常用遥感卫星数据汇总
- 关于能连上网却打不开网页的问题
- 复数计算 [(8+6i)*(4+3i)]/[(8+6i)+(4+3i)]= ?
- 关于jsp中java代码的使用;
- chocolatey 在国内使用
- 移动互联网系统架构特点及实践--手机凤凰网
- linux服务器校对和手动修改时间
- “藤”缠“树”,腾讯安全与青藤云安全发力主机安全
- 学习随记三十一——递归实现二叉查找树