京东投票项目开发笔记

京东投票项目开发笔记

  1. 打开项目
    $yarn install / $ npm install: 跑环境(把项目依赖的插件进行安装)
    $node admin.js: 启服务(把自己的计算机作为服务器,创建一个指定端口的服务,来管理后台程序->后台程序会根据客户端请求的需求,把对应的数据和业务逻辑实现)

  2. API.TXT: API接口文档
    真实项目中,后台开发人员会给前端开发人员提供一个技术文档(接口文档),文档中描述了前端需要调取后台的某些接口实现的某些功能,并且标注了请求的地址、请求方式、传递给服务器的内容、以及服务器返回的结果等信息

    这就是前后端分离: 前端开发者不需要考虑后台是基于什么技术怎么实现的,我们只需要按照API文档中提供的信息,去发送请求传递内容即可,这样就可以获取我们需要的数据(API文档就是约束前端和后台的规范文档)

面试题:有一万条数据,想让其绑定到页面中,怎么做好一些?

  1. 文档碎片: 遍历数据,把对应的数据和结构都添加到文档碎片中,在把文档碎片扎入到页面中(优势∶减少了DOM的回流=>基于字符串拼接也可以)

  2. 虚拟DOM:类似于REACT框架,基于虚拟DOM以及DIFF算法,也可以优化数据绑定

  3. 其实本质来讲怎么做都不是最好的,我们不应该出现1万条这种大数据量的绑定
    ->从服务器获取1万条消耗很多时间
    ->页面渲染1万条也会消耗很多时间

异步数据加载(分页加载)

「需要服务器端做支持]

  1. 客户端向服务器端发送一个GET请求,传递给服务器:每页展示的条数,当前要展示的页数等信息,例如传递的是?limit=20&page=1(每页展示20条,当前展示第一页)
  2. 服务器端接受到请求后,在所有的数据中把第一页的20条数据返回给客户端
  3. 当用户下拉加载更多或者点击第二页等页码按钮等时候,重复第一步,把对应要展示的页码传递给服务器,服务器返回对应页码中的数据

最终实现效果图

通过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 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})
    };
    

二、首页前端

首先把首页写出来(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("请先登录!!!");
      }
    });
    

    到这里,基本的投票功能也已经能实现了,如下效果

: 200,
message: “点赞成功”,
datas,
});
} else {
console.log(“点赞失败”);
}
}
);
}
});
});


- 首先是前端点击投票a标签,然后通过Ajax发送给后端,后端接收到数据后,从数据库进行查找,每点击一次投票数(voteNum)加一,然后 后端会把这个结果返回给前端,前端可以使用这个数据,来重新绘制HTML页面

- 前端ajax请求如下

  ```javascript
  // 投票
  // 因为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("请先登录!!!");
    }
  });

到这里,基本的投票功能也已经能实现了,如下效果

猜你喜欢

转载自blog.csdn.net/Cool_breeze_/article/details/108562110