6. layui大事件項目 文件位置:1.Node.js零基礎入門教程\node.js—資料\day8\素材\大事件項目 在assets/js/baseAPI.js中修改統一請求根路徑 6.1 調整介面名稱 純粹是因為之前本人手賤,故意修改名稱與埠所致的。 在assets/js/login.js中 ...
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 語句執行成功,但是影響行數不等於 1
if (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
點擊查看代碼
<!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|pwd"
placeholder="請輸入原密碼"
autocomplete="off"
class="layui-input"
/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" for="psd">新密碼</label>
<div class="layui-input-block">
<input
onKeyUp="javascript:passwordChangeStatuss(this.value);"
onBlur="javascript:passwordChangeStatuss(this.value);"
type="password"
name="newPwd"
required
lay-verify="required|pwd|samePwd"
placeholder="請輸入新密碼"
autocomplete="off"
class="layui-input"
/>
<span class="psdInfo"></span>
</div>
<!-- <div class="strong">
<p class="fl">
<span class="hover">弱</span>
<span class="">中</span>
<span class="">強</span>
</p>
</div> -->
</div>
<div class="layui-form-item">
<label class="layui-form-label">密碼強度</label>
<div class="layui-btn-group pwd-item">
<label id="l" class="layui-btn layui-btn-primary"
>低</label
>
<label id="m" class="layui-btn layui-btn-primary"
>中</label
>
<label id="h" class="layui-btn layui-btn-primary"
>高</label
>
</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"
/>
<span class="psd1Info"></span>
</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>
<!-- 導入 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>
</body>
</html>
user_pwd.js
:
點擊查看代碼
$(function () {
var form = layui.form
form.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')
break
case 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')
break
default:
$('#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 <= 57)
//數字
return 1
if (iN >= 65 && iN <= 90)
//大寫
return 2
if (iN >= 97 && iN <= 122)
//小寫
return 4
else return 8
}
//bitTotal函數
//計算密碼模式
function bitTotal(num) {
modes = 0
for (i = 0; i < 4; i++) {
if (num & 1) modes++
num >>>= 1
}
return modes
}
//返回強度級別
function checkStrong(sPW) {
if (sPW.length <= 8) return 0 //密碼太短
Modes = 0
for (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
點擊查看代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LinFeng後臺-登錄/註冊</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 -->
<div class="login-box">
<!-- 登錄的表單 -->
<form class="layui-form" id="form_login">
<!-- 用戶名 -->
<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|pwd"
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>
<!-- 註冊的div -->
<div class="reg-box">
<!-- 註冊的表單 -->
<form class="layui-form" id="form_reg">
<!-- 用戶名 -->
<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
onKeyUp="javascript:passwordChangeStatuss(this.value);"
onBlur="javascript:passwordChangeStatuss(this.value);"
type="password"
name="password"
required
lay-verify="required|pwd"
placeholder="請輸入密碼"
autocomplete="off"
class="layui-input"
/>
</div>
<div class="layui-form-item">
<label class="layui-form-label"
><i class="warn"></i>密碼強度</label
>
<div class="layui-btn-group pwd-item">
<label id="l" class="layui-btn layui-btn-primary"
>低</label
>
<label id="m" class="layui-btn layui-btn-primary"
>中</label
>
<label id="h" class="layui-btn layui-btn-primary"
>高</label
>
</div>
</div>
<!-- 密碼確認框 -->
<div class="layui-form-item">
<i class="layui-icon layui-icon-password"></i>
<input
type="password"
name="repassword"
required
lay-verify="required|pwd|repwd"
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>
</div>
<!-- 導入 Layui 的JS文件 -->
<script src="/assets/lib/layui/layui.all.js"></script>
<!-- 導入 JQuery -->
<script src="/assets/lib/jquery.js"></script>
<!-- 導入自己封裝的 baseAPI.js -->
<script src="/assets/js/baseAPI.js"></script>
<!-- 導入自己的 JavaScript 腳本 -->
<script src="/assets/js/login.js"></script>
</body>
</html>
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.form
var 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')
break
case 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')
break
default:
$('#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 <= 57)
//數字
return 1
if (iN >= 65 && iN <= 90)
//大寫
return 2
if (iN >= 97 && iN <= 122)
//小寫
return 4
else return 8
}
//bitTotal函數
//計算密碼模式
function bitTotal(num) {
modes = 0
for (i = 0; i < 4; i++) {
if (num & 1) modes++
num >>>= 1
}
return modes
}
//返回強度級別
function checkStrong(sPW) {
if (sPW.length <= 8) return 0 //密碼太短
Modes = 0
for (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包
//為了驗證碼能通過,則需要導入session組件
const session = require('express-session')
app.use(
session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
})
)
2) 編寫獲取校驗碼介面與驗證碼驗證介面
參考博客:案例分享--NodeJs製作隨機驗證碼
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
res.type('svg') //響應類型
res.send(cap.data)
}
//驗證碼驗證處理函數
exports.verifyCaptcha = (req, res) => {
console.log('驗證碼:', req.query.code, req.session.captcha)
if (req.query.code.toLowerCase() == req.session.captcha.toLowerCase()) {
res.json({
msg: '驗證碼是對的',
code: 200,
})
} else {
res.json({
msg: '驗證碼錯誤',
code: 1001,
})
}
}
介面測試
POST介面就不知道怎麼整了。
3) 修改login.html頁面
login.html
<!-- 驗證碼區域 -->
<div class="layui-inline input-group">
<div class="layui-input-inline" style="width: 135px">
<input
type="text"
class="layui-input"
placeholder="輸入驗證碼"
id="codeInput"
/>
</div>
<img
src=""
current_port="http://localhost:8080"
alt="點擊獲取驗證碼"
id="codeImg"
/>
</div>
assets/js/login.js
在請求獲得驗證碼那塊:
src
在啟動layui模板後,它認為的埠號是80埠,但是後端開的是8080,如果兩個改成一樣的,就會埠占用,所以就需要在baseAPI.js
設置ajax
能跨域的埠,因此需要通過attr
修改成我們最終的請求介面,再通過prob
設置驗證碼點擊更換。