小项目-模仿一个京东投票系统

2024-02-29 03:18

本文主要是介绍小项目-模仿一个京东投票系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

项目准备

启动项目步骤:

  1. 安装依赖

    yarn install 
    ## 或者 npm i
    

    npm可能会警告一些东西,但无所谓。

    image-20200908102905293

    推荐yarn

    image-20200908103658139

  2. 运行项目

    node admin.js
    
  3. 前端开发

    参考接口文档,进行前端进行开发。

首页开发

首页需要展示较多数据,但一次性加载完全部数据则会及其消耗性能,因此需要进行分页处理。

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

  • 一种方案

    文档碎片,遍历数据,把对应的数据和结构都添加到文档碎片中(或基于字符串拼串),再把文档碎片扎入到页面中(优势:减少了DOM的回流)

  • 另一种方案

    虚拟DOM,类似于REACT架构,基于虚拟DOM以及DIFF算法

  • 第三种方案

    进行分页异步加载数据

分页加载思路

如果想实现分页,那么后端需要支持。如果后端不支持,那么无法完成。

步骤说明客户端服务端
第一步请求数据携带每页展示的条数和页数像服务端发送请求数据服务端接收响应
第二步接收服务端传回来的数据根据前端传来的需求,进行数据查询
第三步将数据渲染到页面

快速开始

进入首页,首先我们应该显示出待投票的人,如下图所示:

image-20200908151913484

根据真实情况,我们请求到后端接口后,后端会将数据返回给我们,我们只需要将这些数据渲染成HTML元素即可。

但在这之前,我们需要发送出请求,才能进行数据的”可视化“操作。

在首页的JS逻辑中,采用单例模式进行编写JS代码。在编写逻辑之前,我们要先配置一下axios的默认配置,以便后期更方便的发送请求。

if (typeof axios !== "undefined") {// 请求基于地址axios.defaults.baseURL = "http://localhost:8000";// 允许跨域请求// axios.defaults.withCredentials = true;// 将请求数据转换成URLENCODED格式axios.defaults.transformRequest = (data) => {let str = ``;if (data && typeof data === "object") {for (let attr in data) {if (data.hasOwnProperty(attr)) {str += `${attr}=${data[attr]}&`;}}}return str.substring(0, str.length - 1);};// 默认请求头axios.defaults.headers["Content-Type"] = "x-www-form-urlencoded";// 拦截器,只返回服务器返回的结果axios.interceptors.response.use((result) => result.data);
}

编写首页的逻辑框架。通过一个init函数进行初始化,在初始化的函数中进行数据的获取(初始化)。初始化主要涉及到两个逻辑:获取数据、数据”可视化“。

// 创建单例模式
let matchRender = (function ($) {// 获取显示用户的容器let $userList = $(".userList"),// 找到无序列表容器$wrapper = $userList.find("ul"),// 如果没有用户时提示的文字容器$tip = $userList.find(".tip");// 每页显示条数let limit = 10,// 页数page = 1,// 搜索内容search = "";// 获取数据let queryDate = function queryDate() {axios.get("/getMatchList", {params: {limit,page,search,},}).then(bindHTML);};return {init: function init() {queryDate();},};
})(Zepto);matchRender.init();
  1. 获取数据

    获取数据很简单,无非是一个请求,发送后将结果传入then方法中,在此方法中进行数据的"可视化"。

  2. ”数据可视化“

    这里即将数据转换成HTML元素,并添加到页面,让用户看到。由于数据”可视化“代码量较为复杂,因此为了后期维护以及美观新增一个方法用于数据绑定即bindHTML方法。

    // 数据绑定
    let bindHTML = function bindHTML(result) {let { code, list = [] } = result;if (parseFloat(code) !== 0) {// 获取的数据并不是想要的$wrapper.css("display", "none");$tip.css("display", "block");return;}// 获取的数据是想要的$wrapper.css("display", "block");$tip.css("display", "none");let $frg = $(document.createDocumentFragment());list.forEach((item, index) => {console.log(item);let { id, name, picture, sex, matchId, slogan, voteNum, isVote } = item;$frg.append(`<li>
    <a href="detail.html?userId=${id}">
    <img src="${picture}" alt="${name}" class="picture">
    <p class="title">
    <span>${name}</span>
    |
    <span>编号 #${matchId}</span>
    </p>
    <p class="slogan">${slogan}</p>
    </a>
    <div class="vote">
    <span class="voteNum">${voteNum}</span>
    ${// 根据是否投过票,判断是否显示 "投他一票" 按钮parseFloat(isVote) === 0? `<a href="javascript:;" class="voteBtn">投他一票</a>`: ""}</div>
    </li>`);});$wrapper.append($frg);$frg = null;
    };
    

处理完成后上方的逻辑,在HTML页面中引入我们相关的JS代码并启动后台程序即可看到效果。

<!--IMPORT JS-->
<script src="js/zepto.min.js"></script>
<script src="js/axios.min.js"></script>
<!-- 用于设置默认配置项的文件 -->
<script src="js/axios_default.js"></script>
<!-- <script src="js/component/nav.js"></script> -->
<script src="js/index.js"></script>

image-20200908151913484

滑动相关事件

下拉加载更多

下拉刷新的规则即(一屏幕的高度-卷去的高度>=页面的真实高度)那么则将触发刷新的逻辑。

下拉刷新即分页加载,也就是当下拉时,会请求下一页的数据并添加到页面。

为了控制当前页数及总量,应在全局在添加两个变量,用于控制当前页数等。

let limit = 10,// 总页数pageNum = 1,// 总数total = 0,// 页数page = 1,// 搜索内容search = "",// 是否执行的标志isRun = false;

接下来便是在进行数据绑定之前获取到服务端返回的结果,并提取其总数量与总页数。

// 获取数据
let queryDate = function queryDate() {axios.get("/getMatchList", {params: {limit,page,search,},}).then((result) => {// 处理总页数条数等pageNum = parseFloat(result.pageNum);total = parseFloat(result.total);return result;}).then(bindHTML);
};

最后只需要在滚动事件中进行数据处理即可。

$(window).on("scroll", () => {let {clientHeight,scrollTop,scrollHeight,} = document.documentElement;if (clientHeight + scrollTop + 100 >= scrollHeight) {// 即将到达页面底部// 如果正在加载中,那么不加载数据if (isRun) return;// 如果所有数据都加载完成了,那么不在加载if (page >= pageNum) {$(".none").css("display", "block");return;}isRun = true;page++;queryDate();}
});

搜索

因为queryDate方法已经拼接了search参数,因此只需要为按钮绑定事件后,获取其搜索的值,然后重新执行此方法即可。

$searchBtn.tap(() => {if (isRun) return;isRun = true;// 获取按钮上方的input框的值search = $searchBtn.prev("input").val().trim();page = 1;// 清空之前的内容$wrapper.html("");queryDate();
});

导航插件

对于登陆回转(从哪里跳转到登录页,那么登陆成功后应该跳回哪个页面),为了解决这个问题可以在进入登录页时传递一个参数,这个参数的值代表来自哪个页面。

同时由于很多页面都包含导航栏,因此将其写为一个插件。通过在需要的页面引入JS文件即可使用导航栏。

进入页面后,首先应该检查是否已经登陆,如果已经登陆,那么显示的是个人信息,否则显示登陆与注册的信息。

axios.get("/checkLogin").then((result) => {//=>控制导航的显示let code = parseFloat(result.code);// 根据是否登陆 添加不同的内容。$mainBox.prepend(`<nav class="navBox">
<a href="index.html">首页</a>
${code === 0? `<a href="javascript:;">登录</a><a href="javascript:;">注册</a>`: `<a href="detail.html"></a><a href="javascript:;">退出</a>`}
</nav>`);$navBox = $mainBox.find(".navBox");$navList = $navBox.find("a");// 把结果返回交给下一个thenreturn code;
})

将code进行return操作,在下一个then中进行判断,如果已经登陆了,那么获取其信息。否则也就不用再继续执行了。

.then((code) => {//=>如果已经登录:获取登录用户的用户信息if (code === 0) return;// 获取已经登陆的用户信息return axios.get("/getUser");
})

关于事件绑定,由于元素是动态插入的,因此需要采用事件委托的方式进行数据绑定。为了记录是在哪一个页面进入的登陆页,需要在请求地址拼接一个参数,用于表示请求地址。

.then(() => {//=>基于事件委托给NAV-BOX中的A绑定点击事件$navBox.tap((ev) => {let target = ev.target,tarTAG = target.tagName,tarINN = target.innerHTML;if (tarTAG !== "A") return;if (tarINN === "登录") {//=>window.location.href既可以实现页面跳转也可以基于这个属性获取当前页面的URL地址(一定要编码,否则特殊字符会和跳转的地址冲突)window.location.href = `login.html?fromURL=${encodeURIComponent(window.location.href)}`;return;}if (tarINN === "注册") {window.location.href = `register.html?fromURL=${encodeURIComponent(window.location.href)}`;return;}if (tarINN === "退出") {axios.get("/exitLogin");window.location.href = window.location.href; //=>页面刷新return;}});
});

登陆页面

登陆页面同样采用单例模式

let loginRender = (function ($) {return {init: function init() {}}
})(Zepto);
loginRender.init();

同时为了简化操作,采用工具库的方式,将地址解析的方法写入到这个文件。

let utils = (function anonymous() {//=>URL地址解析let queryURLParams = function (url = window.location.href) {let obj = {},reg = /([^?=&#]+)=([^?=&#]+)/g;url.replace(reg, (...arg) => {let [, key, value] = arg;obj[key] = value;});return obj;};return {queryURLParams}
})();

image-20200909185409518

let loginRender = (function ($) {let $userName = $("#userName"),$userPass = $("#userPass"),$submit = $("#submit");// 获取参数传递的URLlet fromURL = utils.queryURLParams()["fromURL"];fromURL ? (fromURL = decodeURIComponent(fromURL)) : (fromURL = "index.html");let submitFn = function submitFn() {axios.post("/login", {// 用户名name: $userName.val().trim(),//=>HEX_MD5把一个字符串进行MD5加密处理password: hex_md5($userPass.val().trim()),}).then((result) => {let code = parseFloat(result.code);if (code === 0) {//=>登录成功window.location.href = fromURL;return;}alert("请检查用户名密码,登录失败了!");});};return {init: function init() {$submit.tap(submitFn);},};
})(Zepto);
loginRender.init();

关于跨域问题

当使用VSCODE的Live service插件进行打开服务器时无法携带Cookie进行发送请求,因此使用web storm进行替换。

携带Cookie发送需要将Axios的withCredentials配置开启。

axios.defaults.withCredentials = true;

本项目代码参考:https://github.com/changeclass/Tzk/tree/master/2020-09/09/code

这篇关于小项目-模仿一个京东投票系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/757408

相关文章

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

配置springboot项目动静分离打包分离lib方式

《配置springboot项目动静分离打包分离lib方式》本文介绍了如何将SpringBoot工程中的静态资源和配置文件分离出来,以减少jar包大小,方便修改配置文件,通过在jar包同级目录创建co... 目录前言1、分离配置文件原理2、pom文件配置3、使用package命令打包4、总结前言默认情况下,

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

IDEA运行spring项目时,控制台未出现的解决方案

《IDEA运行spring项目时,控制台未出现的解决方案》文章总结了在使用IDEA运行代码时,控制台未出现的问题和解决方案,问题可能是由于点击图标或重启IDEA后控制台仍未显示,解决方案提供了解决方法... 目录问题分析解决方案总结问题js使用IDEA,点击运行按钮,运行结束,但控制台未出现http://

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ