打开项目
$yarn install / $ npm install
: 跑环境(把项目依赖的插件进行安装)
$node admin.js
: 启服务(把自己的计算机作为服务器,创建一个指定端口的服务,来管理后台程序->后台程序会根据客户端请求的需求,把对应的数据和业务逻辑实现)
API.TXT: API接口文档
真实项目中,后台开发人员会给前端开发人员提供一个技术文档(接口文档),文档中描述了前端需要调取后台的某些接口实现的某些功能,并且标注了请求的地址、请求方式、传递给服务器的内容、以及服务器返回的结果等信息
这就是前后端分离: 前端开发者不需要考虑后台是基于什么技术怎么实现的,我们只需要按照API文档中提供的信息,去发送请求传递内容即可,这样就可以获取我们需要的数据(API文档就是约束前端和后台的规范文档)
文档碎片: 遍历数据,把对应的数据和结构都添加到文档碎片中,在把文档碎片扎入到页面中(优势∶减少了DOM的回流=>基于字符串拼接也可以)
虚拟DOM:类似于REACT框架,基于虚拟DOM以及DIFF算法,也可以优化数据绑定
其实本质来讲怎么做都不是最好的,我们不应该出现1万条这种大数据量的绑定
->从服务器获取1万条消耗很多时间
->页面渲染1万条也会消耗很多时间
「需要服务器端做支持]
最终实现效果图
通过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 | 渲染参赛页 |
需要引入第三方模块
npm i express
npm i ejs
npm i cookie-parser
npm i body-parser
npm i mongoose
npm 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})
};
完全手撸的
<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页面
<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>
效果如下:
<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: "数据库内部错误",
});
});
});
页面效果如下
注册即可,其中用户名为必填项,手机号码为必填项,密码为必填项,确认密码为必填项,性别为必填项
点击“提交注册信息”即可注册成功,我们会发现在数据库里就多了一条数据,相对而言,首页也就会多出这条数据,如下:
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<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 + "~ 欢迎你");
}
顺便就把个人主页写出来了
<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 = `- ${
data.username}
">
${
data.picture}" alt="" />
${
data.username} | 编号# ${
data.matchId}
${
data.slogan}
${
data.voteNum}
注意:该操作必须登录
效果如下:
// 投票
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("请先登录!!!");
}
});
到这里,基本的投票功能也已经能实现了,如下效果