6. layui大事件项目
文件位置:1.Node.js零基础入门教程\node.js—资料\day8\素材\大事件项目
在assets/js/baseAPI.js
中修改统一请求根路径
6.1 调整接口名称
纯粹是因为之前本人手贱,故意修改名称与端口所致的。
在assets/js/login.js
中修改注册的post接口
6.2 express启动
先在VSCode的扩展中加上express插件先
接着启动之前的api_server
后端项目
nodemon app.js
然后再回到前端项目,按住ctrl+shift+p
调出Express: Host Current Workspace and Open in Browser
6.3 最终效果
输入我的数据库信息(因人而异):
- 账号:ks
- 密码:123456
6.4 Layui布局问题6.4.1 文章类别列表删除失效问题
打开assets/js/article/art_cate.js
,找到删除文章类别的异步处理函数,通过console.log控制台打印命令发现,之所以不能删除是因为没有返回status,没返回它则是因为找不到id,因为它返回为空。
而造成这个问题的原因则是因为前端找不到这个属性名ID,但我们数据库写的是id。aricle/art_cate.html
6.4.2 文章类别列表的编辑失效问题
因为上一节的更新文章类别的校验规则对象body参数里面定义了我们数据库的id为Id,但是我们的前端只能找数据库的存在的信息,而不是跑去后端验证,所以出现跟上面一样的问题。
更改schema/artcate.js
的更新分类校验对象。
// 校验规则对象 - 更新分类exports.update_cate_schema = {body: {id,name,alias,},}
更改router_handler/artcate.js
里面的更新文章处理分类对象的body校验对象的Id为id。
// 更新文章分类的处理函数exports.updateCateById = (req, res) => {// const sql = `select * from ev_article_cate where name=? or alias=?`const sql = `select * from ev_article_cate where id != ? and (name=? or alias=?)`// 执行查重操作db.query(sql,[req.body.id, req.body.name, req.body.alias],(err, results) => {// 执行 SQL 语句失败if (err) return res.cc(err)// 判断 分类名称 和 分类别名 是否被占用if (results.length === 2)return res.cc('分类名称与别名被占用,请更换后重试!')if (results.length === 1 &&results[0].name === req.body.name &&results[0].alias === req.body.alias)return res.cc('分类名称与别名被占用,请更换后重试!')if (results.length === 1 && results[0].name === req.body.name)return res.cc('分类名称被占用,请更换后重试!')if (results.length === 1 && results[0].alias === req.body.alias)return res.cc('分类别名被占用,请更换后重试!')// 更新文章分类const sql = `update ev_article_cate set ? where id=?`db.query(sql, [req.body, req.body.id], (err, results) => {// 执行 SQL 语句失败if (err) return res.cc(err)// console.log(results)// SQL 语句执行成功,但是影响行数不等于 1if (results.affectedRows !== 1)return res.cc('更新文章分类失败!')// 更新文章分类成功res.cc('更新文章分类成功!', 0)})})// res.send('ok')}
之后通过测试软件进行接口测试是没问题,这里就懒得展示了。
但是即便这点击编辑后,弹出修改表单窗口也没多大的关系,它会提示Id必须为Number,这就很奇怪了。
回到我们前端的编辑问题上,编辑要依靠id绑定了btn-edit
和form-edit
经过的接口有两个,第一个是根据id获取文章分类,绑定点击事件click的异步操作,看到之前把$value.Id
改为了$value.id
,控制台显示的data数据没有问题。
可是当点击修改弹窗的修改表单时,即到第二个接口updatacate
,控制台打印的信息却是:
这就很令人困惑了,明明都通过接口测试了,控制台却说没把第一个接口的data.id
值传给了第二个接口?也许真的没有传到,查看修改类别的this对象,可以看到控制台输出的data值没有id,而是Id。
这也正好说明了之前Id必须为Number的怪相。
后面在aricle/art_cate.html
的form表单修改隐藏域的Id为id即可:
后面拿个alter也可以看到数据没问题了
6.4.3 文章发布的类别下拉框问题
方案一:改用input(垃圾的方案)
在文章发布那块,使用layui的select组件后,尽管能够方便下拉显示数据库中文章分类的内容,但是无论怎么填写都会提示这里是必填项,要么选择去掉select,要么改成input项,完全不清楚发生了什么bug?
方案二:改Id为id。
在art_pub.html
。
6.4.4 文章列表不能显示分类的内容
原因:因为数据库本身的数据都没有分类名,只有分类id而已。art_list.html
6.5 改进页面6.5.1 注册、重置密码页面添加密码强度1) 重置密码页面效果
代码
拿来博客:注册密码/修改密码之密码强度判断user/user_pwd.html
点击查看代码
Document 修改密码<!-- 弱中强
-->修改密码重置user_pwd.js
:
点击查看代码
$(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 '两次密码不一致!'}},})$('.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()},})})})//密码强度判断function passwordChangeStatuss(pwd) {if (pwd == '' || pwd == null) {$('.pwd-item label').attr('class', 'layui-btn layui-btn-primary')} else {S_level = checkStrong(pwd)switch (S_level) {case 0:$('.pwd-item label').attr('class','layui-btn layui-btn-primary')case 1:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-primary')$('#h').attr('class', 'layui-btn layui-btn-primary')breakcase 2:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn layui-btn-primary')breakdefault:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn')}}}//判断输入密码的类型function CharMode(iN) {if (iN >= 48 && iN = 65 && iN = 97 && iN <= 122)//小写return 4else return 8}//bitTotal函数//计算密码模式function bitTotal(num) {modes = 0for (i = 0; i >>= 1}return modes}//返回强度级别function checkStrong(sPW) {if (sPW.length <= 8) return 0 //密码太短Modes = 0for (i = 0; i < sPW.length; i++) {//密码模式Modes |= CharMode(sPW.charCodeAt(i))}return bitTotal(Modes)}
2) 注册页面效果
代码
assets/login.css
点击查看代码
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: 350px; 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;}.reg-box { display: none;}.layui-form { padding: 0 30px;}.links { display: flex; justify-content: flex-end;}.links a { font-size: 12px;}.layui-form-item { position: relative;}.layui-icon { position: absolute; left: 10px; top: 10px;}.layui-input { padding-left: 32px;}.warn{ display: inline-block; width:22px; height:22px; background: url("../images/paywarn.png"); background-repeat: no-repeat; background-size:22px 22px; vertical-align: top;}
login.html
点击查看代码
LinFeng后台-登录/注册 登录去注册账号注册去登录assets/js/login.js
:
点击查看代码
$(function () {// 点击“去注册账号”的链接$('#link_reg').on('click', function () {$('.login-box').hide()$('.reg-box').show()})// 点击“去登录”的链接$('#link_login').on('click', function () {$('.login-box').show()$('.reg-box').hide()})// 从 layui 中获取 form 对象var form = layui.formvar layer = layui.layer// 通过 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 '两次密码不一致!'}},})// 监听注册表单的提交事件$('#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('/api/register', data, function (res) {if (res.status !== 0) {return layer.msg(res.message)}layer.msg('注册成功,请登录!')// 模拟人的点击行为$('#link_login').click()})})// 监听登录表单的提交事件$('#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'},})})})//密码强度判断function passwordChangeStatuss(pwd) {if (pwd == '' || pwd == null) {$('.pwd-item label').attr('class', 'layui-btn layui-btn-primary')} else {S_level = checkStrong(pwd)switch (S_level) {case 0:$('.pwd-item label').attr('class','layui-btn layui-btn-primary')case 1:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-primary')$('#h').attr('class', 'layui-btn layui-btn-primary')breakcase 2:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn layui-btn-primary')breakdefault:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn')}}}//判断输入密码的类型function CharMode(iN) {if (iN >= 48 && iN = 65 && iN = 97 && iN <= 122)//小写return 4else return 8}//bitTotal函数//计算密码模式function bitTotal(num) {modes = 0for (i = 0; i >>= 1}return modes}//返回强度级别function checkStrong(sPW) {if (sPW.length <= 8) return 0 //密码太短Modes = 0for (i = 0; i < sPW.length; i++) {//密码模式Modes |= CharMode(sPW.charCodeAt(i))}return bitTotal(Modes)}
6.5.2 在登录页面添加随机校验码——(SVG-CAPTCHA库)
基本上就是直接拿别人写好的随便改
1)遇到的问题——Cannot set property ‘captcha’ of undefined
参考博客:项目中遇到的bug、问题总结
拿了别人的代码没认真看,出现了问题,挺尴尬的。
app.js
添加session包(这个不用添加,这是个天坑,不用 VUE 你会很痛苦)
//为了验证码能通过,则需要导入session组件const session = require('express-session')app.use(session({secret: 'keyboard cat',resave: false,saveUninitialized: true,}))
2) 编写获取校验码接口与验证码验证接口
参考博客:
下面这个是用session的,在后端判断是没有问题,但是如果搞到前端就要面临不同接口的不同session问题,网上有大量关于Vue的处理,但是没有layui的,我也找不到,所以一定要慎重考虑:
案例分享–NodeJs制作随机验证码
下面的这个则是用通过id选择器通过点击事件替换,只用考虑前端而不用管后端怎么样,非常方便。
使用node生成验证码图片,并进行验证
router/user.js
:定义获取校验码与验证码验证路由
// 定义获取验证码路由router.get('/getCaptcha', userHandler.getCaptcha)//定义验证码验证路由//router.get('/verifyCaptcha', userHandler.verifyCaptcha)
router_handler/user.js
:实现获取校验码与验证码验证的处理函数
const captcha = require('svg-captcha') //1.引入的模块//获取验证码处理函数exports.getCaptcha = (req, res) => {const cap = captcha.create({size: 4, //长度ignoreChars: '0o1il', //排除字符noise: 3, //干扰线条数width: 120, // 宽度height: 36, // 高度color: true, // 验证码字符是否有颜色,默认是没有,如果设置了背景颜色,那么默认就是有字符颜色background: '#fff', // 背景色 可以自己改})// req.session.captcha = cap.text// console.log(req.session)// res.type('svg') //响应类型res.send(cap)}
接口测试
如果要搞session后台判断的话,则需要弄个验证码验证接口(但是我搞不成)。
3) 修改login.html页面
login.html
<!-- --> 点击获取验证码assets/js/login.js
:
先判断完验证码,再接上登录的ajax操作
点击查看代码
$(function () {// 点击“去注册账号”的链接$('#link_reg').on('click', function () {$('.login-box').hide()$('.reg-box').show()})// 点击“去登录”的链接$('#link_login').on('click', function () {$('.login-box').show()$('.reg-box').hide()})// 从 layui 中获取 form 对象var form = layui.formvar layer = layui.layer// 通过 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 '两次密码不一致!'}},})// 监听注册表单的提交事件$('#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('/api/register', data, function (res) {if (res.status !== 0) {return layer.msg(res.message)}layer.msg('注册成功,请登录!')// 模拟人的点击行为$('#link_login').click()})})let validation = ''//点击更换验证码$('#codeImg').on('click', function () {/*在请求获得验证码那块:(该方案弃用,狗都不用,还是Vue方便) src在启动layui模板后,它认为的端口号是80端口,但是后端开的是8080,如果两个改成一样的, 就会端口占用,所以就需要在baseAPI.js设置ajax能跨域的端口, 因此需要通过attr修改成我们最终的请求接口,再通过prob设置验证码点击更换。 */// var cp = $(this).attr('current_port')// $(this).prop('src', cp + '/api/getCaptcha?=t' + Date.now())$.get('/api/getCaptcha', (res) => {// console.log(res)validation = res.textcodeImg.innerHTML = res.data})})//验证验证码,这个后端相应的接口应该要写入到login里面去$('#codeInput').on('blur', function () {if ($(this).val().length == 4 &&$(this).val().toLowerCase() == validation.toLowerCase()) {// layer.msg('验证码正确')// 监听登录表单的提交事件$('#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'},})})} else {layer.msg('验证码输入错误')}})})//密码强度判断function passwordChangeStatuss(pwd) {if (pwd == '' || pwd == null) {$('.pwd-item label').attr('class', 'layui-btn layui-btn-primary')} else {S_level = checkStrong(pwd)switch (S_level) {case 0:$('.pwd-item label').attr('class','layui-btn layui-btn-primary')case 1:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-primary')$('#h').attr('class', 'layui-btn layui-btn-primary')breakcase 2:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn layui-btn-primary')breakdefault:$('#l').attr('class', 'layui-btn layui-btn-danger')$('#m').attr('class', 'layui-btn layui-btn-warm')$('#h').attr('class', 'layui-btn')}}}//判断输入密码的类型function CharMode(iN) {if (iN >= 48 && iN = 65 && iN = 97 && iN <= 122)//小写return 4else return 8}//bitTotal函数//计算密码模式function bitTotal(num) {modes = 0for (i = 0; i >>= 1}return modes}//返回强度级别function checkStrong(sPW) {if (sPW.length <= 8) return 0 //密码太短Modes = 0for (i = 0; i < sPW.length; i++) {//密码模式Modes |= CharMode(sPW.charCodeAt(i))}return bitTotal(Modes)}
任务清单
1、重置密码、注册页面:密码强度显示(完成)
2、登录页面有校验码,虽然有点丑(完成)
为什么我要改进这个项目?
当然不是什么程序员之间的革命情谊啦,何况黑马程序员也没给我钱。
主观原因: 想整属于我自己的个人项目,我希望可以在前端这块有我的痕迹,所以我选择魔改这个项目,没想到吧,
以后如果要告我侵权,请黑马程序员手下留情,当然我也不太可能商用的,我也不会选择贩卖它,
如果未来有一天我这个项目受欢迎,然后又像套娃一样,被人魔改然后贩卖。
请提醒我,让我们伟大的开源精神、名气与汗水卷死他们。
客观原因:被老师质疑我的能力,在综合实训那天被骂得狗血淋头
我的指导老师谈大事件本身就是个铭感词(也怪我选词想都没想就拿这个项目进行综合实训的答辩),
并且也谈到这个项目是不完善的,没有网站基本改有的功能,并且还问到我这个项目的研究目的是什么?
我当时非常的摆烂,直接说是整着来玩的,结果把老师气得。
他们直接把这个项目能找的缺点、我个人操作的问题能说的都说了。
我全程低头红豆泥私密马赛,你说的对,我改。。。,
其实挺好笑的,大三实习要写论文,队伍对我组长的任务分配也是基本不愿执行,非得等到最后答辩几天才肯帮忙,
结果还怪我最后对他们不理不问,挺搞笑的,简直是把我当保姆。
其余答辩的队伍,则是都选择了曾经华为的比赛项目——本质就是数据报表高级版。
图弄得花里胡哨,把我给秀到了,看到我这个大反面教材,老师也是都看不下去了。