京東投票專案開發筆記
-
打開專案
$yarn install / $ npm install: 跑環境(把專案依賴的插件進行安裝)
$node admin.js: 啟服務(把自己的計算機作為服務器,創建一個指定埠的服務,來管理后臺程式->后臺程式會根據客戶端請求的需求,把對應的資料和業務邏輯實作) -
API.TXT: API介面檔案
真實專案中,后臺開發人員會給前端開發人員提供一個技術檔案(介面檔案),檔案中描述了前端需要調取后臺的某些介面實作的某些功能,并且標注了請求的地址、請求方式、傳遞給服務器的內容、以及服務器回傳的結果等資訊這就是前后端分離: 前端開發者不需要考慮后臺是基于什么技術怎么實作的,我們只需要按照API檔案中提供的資訊,去發送請求傳遞內容即可,這樣就可以獲取我們需要的資料(API檔案就是約束前端和后臺的規范檔案)
面試題:有一萬條資料,想讓其系結到頁面中,怎么做好一些?
-
檔案碎片: 遍歷資料,把對應的資料和結構都添加到檔案碎片中,在把檔案碎片扎入到頁面中(優勢∶減少了DOM的回流=>基于字串拼接也可以)
-
虛擬DOM:類似于REACT框架,基于虛擬DOM以及DIFF演算法,也可以優化資料系結
-
其實本質來講怎么做都不是最好的,我們不應該出現1萬條這種大資料量的系結
->從服務器獲取1萬條消耗很多時間
->頁面渲染1萬條也會消耗很多時間
異步資料加載(分頁加載)
「需要服務器端做支持]
- 客戶端向服務器端發送一個GET請求,傳遞給服務器:每頁展示的條數,當前要展示的頁數等資訊,例如傳遞的是?limit=20&page=1(每頁展示20條,當前展示第一頁)
- 服務器端接受到請求后,在所有的資料中把第一頁的20條資料回傳給客戶端
- 當用戶下拉加載更多或者點擊第二頁等頁碼按鈕等時候,重復第一步,把對應要展示的頁碼傳遞給服務器,服務器回傳對應頁碼中的資料
最終實作效果圖

通過AJAX請求來獲取JSON檔案中的資料,只有在登錄情況下才能投票和參賽,并且每個人只能投一票,如果沒有資料會顯示當前沒有資料,登錄的密碼需要用MD5加密等等,
一、首頁后端
目錄結構
|-- node_modules 第三方包
|-- public 公共的靜態資源
|-- app.js 子應用檔案
|-- package.json 包描述檔案
|-- package-lock.json 第三方包版本鎖定檔案(npm 5 以后才有)
|-- router.js 路由介面檔案
路由設計
| 路徑 | 方法 | get引數 | post引數 | 是否需要登錄 | 備注 |
|---|---|---|---|---|---|
| /index | GET | 渲染首頁 | |||
| /register | GET | 渲染注冊頁 | |||
| /register | POST | username、phone、password、passwordtrue、slogan、sex | 處理注冊頁 | ||
| /login | GET | 渲染登錄頁 | |||
| /login | POST | phone、password | 處理登錄頁 | ||
| /about | GET | 渲染個人主頁 | |||
| /logout | GET | 退出登錄 | |||
| /search | GET | username | 搜索功能 | ||
| /vote | GET | username | 投票功能 | ||
| /match | GET | 渲染參賽頁 |
專案構建
app.js 檔案的基本配置
-
需要引入第三方模塊
npm i expressnpm i ejsnpm i cookie-parsernpm i body-parsernpm i mongoosenpm i multer -
路由檔案(router.js)
// 引入第三方服務器模塊 const express = require("express"); // 路由物件 const router = express.Router(); router.get("/", (req, res) => { res.send("Hello World"); }); module.exports = router; -
app.js
// 引入寫服務器的第三方模塊 const express = require("express"); // 引入用來決議的插件 const bodyParser = require("body-parser"); // 引入mongoose插件 const mongoose = require("mongoose"); // 引入router.js const router = require("./router"); // 創建服務器 var app = express(); // 模板引擎的設定 app.set("view engine", "html"); app.set("views", `${__dirname}/views`); app.engine("html", require("ejs").renderFile); // 用ejs模板渲染html // 加載到沒有掛載路徑的中間件 app.use(bodyParser.urlencoded({ extended: false })); // 靜態資源配置 app.use(express.static(__dirname + "/public")); // 使用router, router.js檔案中的所有路由都可以使用 app.use(router); // 連接資料庫和開啟服務器 /* * localhost - 本地地址 * jdvotes - mongodb資料庫 */ mongoose.connect( "mongodb://localhost/jdvotes", { useNewUrlParser: true, useUnifiedTopology: true, }, function (err) { if (err) { console.log("資料庫連接失敗"); } else { console.log("資料庫連接成功"); app.listen(8888, function () { console.log("服務器開啟成功 -- 8888"); }); } } ); -
需要用到MondoDB,所以需要配置以下表結構檔案
/* MongoDB資料庫模型檔案 */ // 引入mongoose插件 const mongogose = require("mongoose"); // 通過mongoose定義介面 Schema var Schema = mongogose.Schema; // 生成表結構 // 操作users表(集合) 定義一個Schema Schema里面的物件和資料庫表里面的欄位需要一一對應 var mySchema = new Schema({ // name: { type: String, default: "zhangsan" }, name: String, }); // 把Schema匯出 module.exports = mySchema; -
然后再訪問資料庫模型
// 引入mongoose插件 const mongoose = require("mongoose"); // 引入 schema.js 檔案(MongoDB資料庫表結構檔案) const mySchema = require("./schema"); // 定義資料庫模型 /* model里面的第一個引數 要注意: 1.首字母大寫 2.要和資料庫表(集合)名稱對應 這個模型會和模型名稱相同的復數的資料庫表建立連接 */ // 把這個資料庫模型匯出 module.exports = mongoose.model("User", mySchema); -
最后在寫路由,在對應路由上查詢對應的資料回傳給頁面即可
/* 路由檔案 */ // 引入第三方服務器模塊 const express = require("express"); // 引入model.js檔案(資料庫模型檔案) const USER = require("./model"); // 路由物件 const router = express.Router(); // 首頁 router.get("/", (req, res) => { USER.find({}, (err, docs) => { // docs.forEach // 如果查詢成功 if (err === null) { console.log(docs); } }); res.send("Hello"); }); module.exports = router;瀏覽器訪問
127.0.0.1:8888,得到結果[ { _id: 5f5ad635994e3f8f4923d1cd, name: 'zhangsan' } ] -
創建資料
for(var i=1;i<=150;i++){ db.users.insert({"id":i,"name":"張"+i,"picture":"https://cdn.jsdelivr.net/gh/extheor/images/Ajax%E5%9B%BE%E7%89%87/man.png","phone":"10377771223","sex":0,"password":"123456","bio":"Live beautifully, dream passionately, love completely","time":1506090072369,"isMatch":1,"matchId":i<10?"00"+i:i<100?"0"+i:i,"slogan":"你是唯一的,你是非常獨特的,你就是你生命中的第一名","voteNum":1}) };
二、首頁前端
首先把首頁寫出來(views/index.html)
完全手擼的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>首頁</title>
<link rel="stylesheet" href="css/index.css" />
</head>
<body>
<div class="app">
<header>
<a href="/index">首頁</a>
<a href="/login" class="login">登錄</a>
<a href="/register">注冊</a>
</header>
<div class="header">
<img class="img" src="img/title.png" alt="" />
<div class="myToMacth">
<a href="/match">我要參賽</a>
</div>
<div class="search">
<input type="text" class="searchInput" placeholder="輸入用戶名查找" />
<input type="button" class="searchButton" value="搜索" />
</div>
</div>
<div class="content">
<ul class="userul">
<% datas.forEach(data => { %>
<li class="<%= data.phone %>">
<div class="left">
<img src="<%= data.picture %> " alt="" />
</div>
<div class="center">
<div><%= data.username %> | 編號# <%= data.matchId %></div>
<div><%= data.slogan %></div>
</div>
<div class="right">
<div class="voteNum"><%= data.voteNum %></div>
<div><button>投他一票</button></div>
</div>
</li>
<% }) %>
</ul>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="js/index.js"></script>
</body>
</html>
CSS樣式在這里
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: yellowgreen;
}
.app {
width: 450px;
height: 800px;
background: red;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
a {
text-decoration: none;
}
/* 首頁、登錄、注冊 */
header {
position: fixed;
right: 10px;
top: 10px;
font-weight: 800;
}
header > a {
color: #000;
margin-left: 20px;
}
.header {
width: 100%;
height: 50%;
background: #31a5de;
}
/* 投起來 */
.header > .img {
position: relative;
left: 50%;
top: 40%;
transform: translate(-50%, -50%);
}
/* 我要參賽 */
.myToMacth {
position: absolute;
left: 50%;
top: 38%;
transform: translate(-50%, -50%);
padding: 10px 20px;
background: #eb713b;
box-shadow: 5px 2px 15px rgb(90, 38, 38);
border-radius: 20px;
}
.myToMacth > a {
color: #fff;
}
/* 搜索 */
.search {
position: absolute;
left: 52%;
top: 45%;
transform: translate(-50%, -50%);
width: 250px;
height: 30px;
/* border: 1px solid #000; */
/* border-radius: ; */
}
.searchInput,
.searchButton {
height: 30px;
border-radius: 30px;
border: none;
outline: none;
}
.searchInput {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
padding-left: 15px;
}
.searchButton {
width: 50px;
background: #007ec3;
color: #fff;
position: relative;
right: 5px;
top: 1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/* 串列 */
.content {
height: 50%;
background: #ccc;
}
.content > ul {
list-style: none;
margin: 0;
padding: 0;
width: 450px;
}
.content > ul > li {
height: 100px;
background: #fff;
}
.content > ul > li > .left {
float: left;
width: 100px;
height: 100px;
}
.content > ul > li > .left > img {
width: 80%;
border-radius: 50%;
margin-left: 10px;
margin-top: 10px;
}
.content > ul > li > .center {
float: left;
height: 100px;
width: 250px;
margin-top: 20px;
}
.content > ul > li > .center > div:nth-child(1) {
margin-bottom: 10px;
}
.content > ul > li > .right {
float: right;
width: 100px;
height: 100px;
margin-top: 20px;
}
.content > ul > li > .right > div:nth-child(1) {
margin-bottom: 10px;
text-align: center;
color: rgb(156, 92, 92);
}
.content > ul > li > .right > div:nth-child(2) {
margin-left: 10px;
}
.content > ul > li > .right > div:nth-child(2) > button {
/* width: 60px;
height: 30px; */
padding: 5px 10px;
border: none;
background: #0081cd;
color: #fff;
border-radius: 15px;
}
頁面樣式如下:

-
接下來需要把從資料庫獲取到的資料渲染到HTML頁面當中去
-
從路由檔案中獲取到資料
/* 路由檔案 */ // 引入第三方服務器模塊 const express = require("express"); // 引入model.js檔案(資料庫模型檔案) const USER = require("./model"); // 路由物件 const router = express.Router(); // 首頁 router.get("/index", (req, res) => { USER.find({}, (err, datas) => { // docs.forEach // 如果查詢成功 if (err === null) { // console.log(datas); res.render("index", { // es6語法:物件解構賦值, // 相當于datas:datas datas, }); } }); }); module.exports = router; -
渲染到HTML頁面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>首頁</title> <link rel="stylesheet" type="text/css" href="css/index.css" /> </head> <body> <div class="app"> <header> <a href="#">首頁</a> <a href="/login">登錄</a> <a href="/register">注冊</a> </header> <div class="header"> <img class="img" src="img/title.png" alt="" /> <div class="myToMacth"> <a href="/match">我要參賽</a> </div> <div class="search"> <input type="text" class="searchInput" placeholder="輸入用戶名查找" /> <input type="button" class="searchButton" value="搜索" /> </div> </div> <div class="content"> <ul> <% datas.forEach(data => { %> <li class="<%= data.id %>"> <div class="left"> <img src="<%= data.picture %> " alt="" /> </div> <div class="center"> <div>張三 | 編號# <%= data.matchId %></div> <div><%= data.slogan %></div> </div> <div class="right"> <div class="voteNum"><%= data.voteNum %></div> <div><button>投他一票</button></div> </div> </li> <% }) %> </ul> </div> </div> </body> </html>效果如下:

-
三、注冊頁前端
首先把注冊頁面寫出來
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>注冊頁</title>
<link rel="stylesheet" href="css/index.css" />
<link rel="stylesheet" href="css/register.css" />
</head>
<body>
<div class="app">
<header>
<a href="#">首頁</a>
<a href="/login">登錄</a>
<a href="/register">注冊</a>
<a href="/logout">退出</a>
</header>
<div class="header">
<img class="img" src="img/title.png" alt="" />
</div>
<form action="#">
用戶名:<input
type="text"
name="username"
id="username"
placeholder="請輸入您的真實姓名"
required
/>
手機號碼:<input
type="text"
name="phone"
id="phone"
placeholder="請填寫您常用的手機號"
required
/>
密碼:<input
type="password"
name="password"
id="password"
placeholder="由6~12位數字和字母組成"
required
/>
確認密碼:
<input type="password" name="passwordtrue" id="password" required />
<div class="introduce">自我描述:</div>
<textarea
cols="54"
rows="6"
placeholder="限制在10~100字之間"
minlength="10"
maxlength="100"
id="descript"
name="descript"
></textarea>
上傳頭像:
<input type="file" id="avatar" name="avatar" />
<div class="sex">性別:</div>
<input type="radio" name="sex" id="man" required /><span>男</span>
<input type="radio" name="sex" id="woman" required /><span>女</span>
<input type="submit" value="提交注冊資訊" class="submit" />
</form>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="js/register.js"></script>
</body>
</html>
.app {
background: #fff;
}
.header {
height: 40%;
}
/* 投起來 */
.header > .img {
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
form {
color: #656e73;
background: #fff;
padding: 20px;
}
form > input {
display: block;
margin-top: 5px;
margin-bottom: 20px;
width: 396px;
height: 30px;
padding: 10px;
}
form > textarea {
padding: 10px;
outline: none;
resize: none;
}
form > #man,
form > #woman {
float: left;
position: absolute;
bottom: -135px;
width: 30px;
}
.sex {
margin-bottom: 10px;
}
form > #man ~ span {
margin-right: 20px;
margin-left: 30px;
}
form > #man {
left: 17px;
}
form > #woman {
left: 89px;
}
form > .submit {
margin-top: 20px;
background: #54abe8;
color: #fff;
font-size: 20px;
height: 60px;
border: none;
outline: none;
cursor: pointer;
border-radius: 3px;
}
前端需要把注冊資訊發送給后端,所以需要用到AJAX
// 當提交表單時觸發
$("form").on("submit", (event) => {
// 阻止默認行為
event.preventDefault();
// console.log($("form")[0]);
/*
serialize() FormData serializeArray()都是序列化表單,實作表單的異步提交
但是serialize()和serializeArray()都是只能序列化表單中的資料,比如input select等的資料,
但是對于檔案上傳就只能用 FormData,
*/
var data = new FormData($("form")[0]);
$.ajax("/register", {
type: "post",
data,
dataType: "json",
// (默認: "application/x-www-form-urlencoded") 發送資訊至服務器時內容編碼型別,默認值適合大多數情況,如果你明確地傳遞了一個content-type給 $.ajax() 那么他必定會發送給服務器(即使沒有資料要發送)
contentType: false,
// processData 默認為true,當設定為true的時候,jquery ajax 提交的時候不會序列化 data,而是直接使用data
processData: false,
success: function (response) {
if (response.code == "200") {
window.location = "/";
}
},
});
});
四、注冊頁后端
// 注冊
router.get("/register", (req, res) => {
res.render("register");
});
// 必須寫上傳檔案
router.post("/register", upload.single("picture"), (req, res) => {
// 獲取前端發送過來的注冊資訊
var { username, phone, password, passwordtrue, slogan, sex } = req.body;
// console.log(username);
var picture;
try {
picture = req.file.filename;
} catch (e) {
picture = undefined;
}
// console.log(picture);
if (password !== passwordtrue) {
res.send({
code: "304",
message: "兩次密碼不一致",
});
return;
}
USER.findOne({ username })
.then((result) => {
// 如果查詢到username存在,則說明該用戶已注冊過
if (result) {
// console.log(result); // 查詢結果
res.send({
code: 304,
message: "該用戶已存在",
});
}
// 否則該用戶不存在,則添加到表(集合)中去
else {
console.log("用戶注冊~~~");
// 如果用戶上傳了圖片
// 創建一個資料集合(物件)
var myUser = new USER({
username,
phone,
password,
picture,
slogan,
// sex,
});
// console.log(myUser);
// 把這個資料集合插入到表(集合)中
USER.insertMany(myUser)
.then((result) => {
// console.log(result);
// 插入成功
res.send({
code: 200,
message: "注冊成功",
});
})
.catch((err) => {
// console.log(err);
res.send({
code: 304,
message: "注冊失敗",
});
});
}
})
.catch((err) => {
res.send({
code: 500,
message: "資料庫內部錯誤",
});
});
});
頁面效果如下

注冊即可,其中用戶名為必填項,手機號碼為必填項,密碼為必填項,確認密碼為必填項,性別為必填項
點擊“提交注冊資訊”即可注冊成功,我們會發現在資料庫里就多了一條資料,相對而言,首頁也就會多出這條資料,如下:

五、登錄頁前端
<!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="css/index.css" />
<link rel="stylesheet" href="css/register.css" />
</head>
<body>
<div class="app">
<header>
<a href="/index">首頁</a>
<a href="/register">注冊</a>
</header>
<div class="header">
<img class="img" src="img/title.png" alt="" />
</div>
<form action="#">
手機號碼:<input
type="text"
name="phone"
id="phone"
placeholder="請填寫您常用的手機號"
required
/>
密碼:<input
type="password"
name="password"
id="password"
placeholder="由6~12位數字和字母組成"
required
/>
<input type="submit" value="提交登錄資訊" class="submit" />
</form>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="js/login.js"></script>
</body>
</html>
六、登錄頁后端
// 登錄
router.get("/login", (req, res) => {
res.render("login");
});
router.post("/login", (req, res) => {
var { username, phone, password } = req.body;
// 去資料庫查找phone和password
USER.findOne({ phone, password })
.then((result) => {
if (phone === result.phone && password === result.password) {
// 如果手機號和密碼都正確,則登錄成功
var id = result._id;
// console.log(id);
res.cookie("phone", phone);
res.cookie("id", id);
res.send({
code: 200,
message: "登錄成功",
data: {
phone,
id,
},
});
} else {
res.send({
code: 304,
message: "手機號或密碼錯誤",
});
}
})
.catch((err) => {
res.send({
code: 500,
message: "資料庫內部錯誤",
});
});
});
登錄用到了cookie,可以通過用后端發送cookie給客戶端,并在客戶端存盤,然后前端可以通過判斷cookie中的phone是否存在,來判斷用戶是否登錄
-
登錄頁ajax請求部分
// 獲取后臺傳送的cookie if (document.cookie.indexOf("phone") >= 0) { // 如果cookie里的phone存在,則把index頁面中的登錄換成用戶名 // 想要獲取當前手機號,可以使用cookie中的phone // console.log(document.cookie); // phone=17692414892; id=j%3A%225f5c9c1f203b5c3b2ca5c27c%22 // 通過 ; 切割字串 // console.log(document.cookie.split(";")); // ["phone=17692414892", " id=j%3A%225f5c9c1f203b5c3b2ca5c27c%22"] // 取第零個 -- 手機號 // console.log(document.cookie.split(";")[0]); // phone=17692414892 // 利用 = 切割字串 // console.log(document.cookie.split(";")[0].split("=")); // ["phone", "17692414892"] // 然后再取第一個就可以了 var phone = document.cookie.split(";")[0].split("=")[1]; // console.log(phone); // 對登錄a標簽進行文本替換,herf地址也換一下,可以換成個人主頁 $(".login").text(phone); $(".login").attr("href", "/about"); // about頁邏輯 $(".about").text(phone + "~ 歡迎你"); }
順便就把個人主頁寫出來了
七、個人主頁前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>關于</title>
<link rel="stylesheet" href="css/index.css" />
<link rel="stylesheet" href="css/about.css" />
</head>
<body>
<div class="app">
<header>
<a href="/index">首頁</a>
<a href="/login" class="login">登錄</a>
<a href="/logout">退出</a>
</header>
<div class="about"></div>
<img
class="seekfocus"
src="https://cdn.jsdelivr.net/gh/extheor/images/%E6%B1%82%E5%85%B3%E6%B3%A8.jpg"
alt=""
/>
</div>
</body>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="js/index.js"></script>
</html>
CSS樣式:
body {
background: #31a5de;
}
.app {
background: #edf1f8;
}
.about {
background: #edf1f8;
width: 80%;
height: 20%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
border-radius: 8px;
box-shadow: 0 4px 8px 6px rgba(7, 17, 27, 0.06);
text-align: center;
line-height: 100px;
font-size: 18px;
}
八、個人主頁后端
// 個人主頁
router.get("/about", (req, res) => {
// 在資料庫中查找到所有的資料進行回傳
USER.find({}, (err, datas) => {
if (err === null) {
res.render("about", {
datas,
});
} else {
res.send({
code: 500,
message: "資料庫內部錯誤",
});
}
});
});
點擊 手機號

即可出現以下頁面

九、退出后端(沒有前端頁面)
// 退出
router.get("/logout", (req, res) => {
// 清除cookie
res.clearCookie("phone");
res.clearCookie("id");
// 重定向
res.writeHead(302, {
Location: "/index",
});
// 結束回應程序
// 用于快速結束沒有任何資料的回應
res.end("");
});
十、搜索后端
// 搜索
router.get("/search", (req, res) => {
// 根據id搜索資訊
var { username } = req.query;
// 把前端傳遞過來的username在資料庫進行查找,然后回傳結果給前端
if (username !== "") {
// 如果用戶名不為空,則查詢對應的用戶
USER.find({ username }, (err, datas) => {
if (err === null) {
res.send({
datas,
});
} else {
res.send({
code: 500,
message: "資料庫內部錯誤",
});
}
});
}
// 如果用戶名不為空,則查詢所有的用戶
else {
USER.find({}, (err, datas) => {
if (err === null) {
res.send({
datas,
});
} else {
res.send({
code: 500,
message: "資料庫內部錯誤",
});
}
});
}
});
-
然后前端發送資料給后端,讓后端在資料庫里查詢想要的結果,然后后端在把結果回傳給前端,前端只需渲染到頁面上即可
// 搜索邏輯 // 按用戶名 -- 搜索 $(".searchButton").on("click", (event) => { if (document.cookie.indexOf("phone") >= 0) { // 如果進入到這里說明用戶已登錄 // 獲取到用戶在搜索框輸入的用戶名 var username = { username: $(".searchInput").val(), }; // 發送ajax請求,后端會傳給前端資料,讓前端進行頁面處理 $.ajax("/search", { type: "get", data: username, success: function (response) { // console.log(response.datas); var result = response.datas; // console.log(result[0].username); if (result[0]) { // 如果查詢到的結果不為空 // 先把ul串列清空 $(".userul").empty(); // 回圈遍歷result $.each(result, (index, data) => { console.log(data); var html = `<li class="${data.username}"> <div class="left"> <img src="${data.picture}" alt="" /> </div> <div class="center"> <div>${data.username} | 編號# ${data.matchId}</div> <div>${data.slogan}</div> </div> <div class="right"> <div class="voteNum">${data.voteNum}</div> <div><button>投他一票</button></div> </div> </li>`; // 然后再把查詢到的所有資料都添加到ul串列中 $(".userul").append(html); }); } else { // 如果查詢到的結果為空 alert("當前沒有該用戶"); } }, }); // var username = datas } else { // 如果進入到這里說明用戶未登錄 alert("請先登錄!!!"); } });注意:該操作必須登錄
效果如下:

十一、投票后端
// 投票
router.get("/vote", (req, res) => {
// 當前端點擊投票按鈕時獲取到前端發送過來的投票數,然后自加
var { username } = req.query;
USER.findOne({ username }, (err, datas) => {
if (err === null) {
// 修改資料庫中vaotNum的值 -- update
// console.log(datas); // 從資料庫查到的資料集合(物件)
// 從資料庫中修改用戶點擊的用戶的投票數
USER.updateOne(
{ username },
{ voteNum: ++datas.voteNum },
(err, voteNum) => {
if (err === null) {
// console.log("點贊成功");
res.send({
code: 200,
message: "點贊成功",
datas,
});
} else {
console.log("點贊失敗");
}
}
);
}
});
});
-
首先是前端點擊投票a標簽,然后通過Ajax發送給后端,后端接收到資料后,從資料庫進行查找,每點擊一次投票數(voteNum)加一,然后 后端會把這個結果回傳給前端,前端可以使用這個資料,來重新繪制HTML頁面
-
前端ajax請求如下
// 投票 // 因為li標簽是動態創建的,所以需要通過事件委托來獲取投票按鈕 $(".userul").delegate(".vote", "click", function () { if (document.cookie.indexOf("phone") >= 0) { var $this = $(this); var username = $this.parents("li").attr("class"); var data = { username, }; $.ajax("/vote", { type: "get", data, success: function (response) { // console.log(response.datas); if (response.code === 200) { // 先獲取到資料庫中該用戶的票數 var voteNum = response.datas.voteNum; console.log(voteNum); // 通過 全域$this 找到voteNum元素 var $voteNum = $this.parents(".right").children(".voteNum"); // 然后把voteNum重新繪制到HTML頁面即可 $voteNum.text(voteNum); } }, }); } else { alert("請先登錄!!!"); } });到這里,基本的投票功能也已經能實作了,如下效果

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/40087.html
標籤:其他
下一篇:求助:HTP ALM的相關問題
