京东投票项目开发笔记

Posted 码小余の博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了京东投票项目开发笔记相关的知识,希望对你有一定的参考价值。

京东投票项目开发笔记

  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参数是否需要登录备注
/indexGET渲染首页
/registerGET渲染注册页
/registerPOSTusername、phone、password、passwordtrue、slogan、sex处理注册页
/loginGET渲染登录页
/loginPOSTphone、password处理登录页
/aboutGET渲染个人主页
/logoutGET退出登录
/searchGETusername搜索功能
/voteGETusername投票功能
/matchGET渲染参赛页

项目构建

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;

页面样式如下: