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-editform-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、登录页面有校验码,虽然有点丑(完成)

为什么我要改进这个项目?

当然不是什么程序员之间的革命情谊啦,何况黑马程序员也没给我钱。

主观原因: 想整属于我自己的个人项目,我希望可以在前端这块有我的痕迹,所以我选择魔改这个项目,没想到吧,

以后如果要告我侵权,请黑马程序员手下留情,当然我也不太可能商用的,我也不会选择贩卖它,
如果未来有一天我这个项目受欢迎,然后又像套娃一样,被人魔改然后贩卖。
请提醒我,让我们伟大的开源精神、名气与汗水卷死他们。

客观原因:被老师质疑我的能力,在综合实训那天被骂得狗血淋头

我的指导老师谈大事件本身就是个铭感词(也怪我选词想都没想就拿这个项目进行综合实训的答辩),

并且也谈到这个项目是不完善的,没有网站基本改有的功能,并且还问到我这个项目的研究目的是什么?

我当时非常的摆烂,直接说是整着来玩的,结果把老师气得。

他们直接把这个项目能找的缺点、我个人操作的问题能说的都说了。

我全程低头红豆泥私密马赛,你说的对,我改。。。,

其实挺好笑的,大三实习要写论文,队伍对我组长的任务分配也是基本不愿执行,非得等到最后答辩几天才肯帮忙,
结果还怪我最后对他们不理不问,挺搞笑的,简直是把我当保姆。

其余答辩的队伍,则是都选择了曾经华为的比赛项目——本质就是数据报表高级版。

图弄得花里胡哨,把我给秀到了,看到我这个大反面教材,老师也是都看不下去了。