Node.js + Vue.js 开发王者荣耀手机端官网和管理后台

全栈王者荣耀手机端官网和管理后台日志

Posted by page on December 19, 2020

开发日志

初始化项目

项目环境

  • nodeJs环境
    • 服务端npm包
      • express
      • mongoose
      • cors
      • inflection 命名转换
      • multer 写入上传文件
      • bcrypt hash加密
      • jsonwebtoken json转token串
      • http-assert http错误响应
      • require-all
    • 前端npm包
      • vue CLI
      • element-ui
      • axios
      • vue-router
      • vue2-editor 富文本编辑
      • dayjs
  • MongoDB数据库

项目根目录

  • server 服务端项目
  • web web客户端项目
  • admin 后台界面项目

初始化操作

安装mongoDB

Vue CLI 创建前端项目

vue create web
vue create admin

server初始化

  1. 初始化 npm

    npm init -y
    
  2. 安装 nodemon

    npm install -g nodemon
    

    Nodemon会持续监视您的目录或文件系统,当发现任何更改时,它会自动重新启动节点应用程序服务器。取代node命令修改源文件后需要重启server

  3. package.json添加node命令

    "scripts": {
     "serve": "nodemon index.js",
    }
    

admin初始化

配置vue-router

ElementUI使用

  1. 安装npm包

    npm install element-ui --save
    
  2. plugins/element.js安装插件

    import Vue from 'vue'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css';
    Vue.use(ElementUI);
    
  3. main.js

    import './plugins/element.js'
    
  4. 使用ElementUI的后台管理组件

    • 创建views/Main.vue作为后台管理主页
    • router/index.js配置Main.vue路由

admin与serve开发

Main.vue开发

  • 左侧每个el-menu-item切换至各自子路由,router-view在el-main内显示
  • 路由功能
    • el-menu添加router属性,el-menu-item的index属性值设为路由path
    • router.js下为Main.vue添加子路由配置
    • 开发子路由视图
  • axios请求
    • 安装axios并配置network/request.js
    • 项目中使用request函数
      1. main.js中在Vue.prototype上全局绑定request方法
      2. network独立各个views组件的请求方法,本项目使用该方式
  • serve接口
    • 安装express,mongoose,cors包
    • 配置express,如post参数处理
    • routes/admin配置’/admin/api’路径下的路由处理
    • plugins/db.js配置MongoDB数据库连接
    • models/新建mongoose模型,routes/admin声明对模型的处理
  • admin的views请求数据
    • network/声明各种request方法的请求参数
    • views/视图组件引入请求方法并调用方法发送增删改查请求
子分类功能
  • 父级分类是固定的,Categoryd/Edit.vue是编辑子分类
  • 数据库设计:
    • 父子分类记录都以Category模型存储在数据库
    • 子分类的记录多一个parent属性关联父分类的id
    • 操作:在category的schema上声明一个parent字段,值为ObjectId类型
  • 新建子分类
    • 查询所有父分类作为可选项
    • 提交时,子分类的parent参数即为数据库存储时parent的关联id
  • 编辑子分类
    • 由于mongoDB的记录与双向绑定的model内部相互统一
  • 查询子分类
    • List.vue中每个子分类需显示其所属父分类
    • mongoDB支持populate(‘parent’)返回集合关联id的记录,即父分类记录
CURD通用接口
  • 简单的重复的增删改查操作可以合并为一个CURD通用接口

  • 原理:请求路径名,如’/categories’,crud操作模型名,如’Category’。按照规则命名

  • 因而通用接口只需把路径名转换为对应命名规则的操作模型名,对其crud即可

  • 实现步骤:

    1. 通用接口监听的路由路径为’/admin/api/reset/:resource’,resource参数用于匹配实际请求路径

    2. 核心:

      • app.use插入中间件处理,通过第三方inflection模块将resource参数转为符合命名规则的modelName,即操作模型名称
      • 引入操作模型对象,将其暂存至req.Model属性
    3. 已监听router子路由的操作处理会在req.Model上对正确的模型进行CRUD

    4. 拓展部分

      get请求处理判断modelName为’Category’时,增加populate处理

图片上传
  • 使用ElementUI的upload组件,设置图片上传至服务器的地址
  • 当用户选择文件后,ElementUI内部自动向声明的地址上传binary格式图片
  • server端接口接收post的binar数据,使用multer中间件保存至/uploads目录,将图片信息对象返回前端
  • 前端声明图片上传完成执行afterUpload处理,接收图片信息,设置src显示图片
  • 此时服务端应添加静态资源托管,自动响应图片的请求

编辑Hero

  • 先定义Hero的Schema,声明部分属性与另一Schema。ObjectId关联

  • edit视图需请求与Hero关联模型的所有记录作为选项

  • 编辑完成后,选中选项的id即关联Schema的值

  • 技能编辑

    • UI组件默认绑定model.skills数据
    • 第一次编辑时,skills为空,通过添加按钮push空对象至skills,添加一个待编辑技能
    • 技能删除:每个技能编辑组件下的添加删除按钮,执行对skills删除当前索引项

编辑Article

  • 富文本编辑
    • 本项目使用第三方npm包’vue2-editor’
    • 安装至admin目录后在ArticleEdit使用标签
    • 在视图引入vue2-editor,组件’vue-editor’上双向绑定v-model
  • 文章图片上传
    • 富文本编辑器的图片是通过base64编码(粘贴的图片则引用src地址)直接保存在数据库
    • 通过vue2-editor的API可以定义在图片编辑时自动上传至指定url地址,将图片转为src链接保存

管理员管理

password密码

  • serve端保存管理员密码时,使用bcrypt工具Hash加密
  • 操作:定义AdminUser的schema模型在时在password字段添加set方法处理
  • serve仅允许admin编辑新密码覆盖旧密码,不允许直接向serve查询密码;
  • 操作:定义AdminUser的schema模型在时在password字段添加select: false不可查询

Login.vue开发

serve接收登录请求,执行登录校验

  1. 查找用户名
    • 对表单的用户名参数在AdminUser模型中查找对应数据记录
    • 查找结果不存在则返回错误码与错误message至admin,否则执行下一步
  2. 密码校验
    • 使用bcrypt工具对比表单的password参数和数据记录的password
    • 由于设置了数据记录的password默认不可直接查询,此处查找数据记录时需添加select(‘+password’)
    • 检验布尔值为false,返回错误码与message至admin,否则执行下一步
  3. 生成token并返回
    • 验证通过,使用jsonwebtoken工具将自定义的json数据转为token串返回至admin
    • 前端admin将返回的token存储至sessionStorage,并跳转路由至admin’/’根目录 - 错误统一处理 + serve对于前端无效访问返回错误代码422,响应内容为{message: ‘错误信息’} + admin的axios.interceptors拦截器监听服务端返回非200代码时,将error.response.data.message作为响应数据返回

服务端校验token

  1. admin添加axios.interceptors.request拦截器,发送任何请求前将token串添加至请求头
  2. 为serve通用CRUD接口与uoload接口添加检验token中间件处理,检验未通过使用assert方法返回错误信息
  3. 添加app.use(err,req,res,next)错误处理中间件,向admin响应message数据对象
  4. admin响应拦截器判断错误status,为401时跳转至login界面

前端admin路由限制

  • 目前仅在请求后端admin/api接口时校验token,前端依旧可以直接访问admin项目的文件
  • 实际开发应当在admin后端添加校验token处理,此处采用路由导航beforeEach限制没有token访问时跳转登录
    • 上传图片请求的token
  • upload图片采用ElementUI默认的formData请求,需在请求头添加token值至后端
  • 通过maxin混合,在具有upload功能视图引入mixinsUpload对象,添加upload请求头授权参数method
  • upload组件添加:headers=”getAuthHeader()”

移动端web开发

项目准备

  1. 样式采用sass编写,安装sass,sass-loder –save-dev
  2. 引入reset.scss用于初始化页面css
  3. 声明网站主要的color,font-size等值作为变量,使用sass遍历生成对应快捷样式类
  4. 生成文本对齐,flex布局,padding、margin边距等可复用的辅助类

首页开发

  • vue add router引入并配置router

  • topbar组件开发

  • navbar组件开发

  • home.vue开发

    • swipper轮播组件
      1. npm install swiper
      2. 根据API文档引入依赖模块与配置options
      3. swipper组件为轮播容器,swipperSlide为轮播项组件
      4. 在home引入swipper、swipperSlide组件,swipperSlide插槽内插入轮播内容
      5. 为初始化页面多个swiper区别开,每个swiper组件实例绑定swiper属性值作为初始化时指定类名的元素
    • 图标列表导航
      1. 图标使用sprite图定位,(spritecow)[http://www.spritecow.com/]网站工具快速划分每个sprite的css大小位置
      2. 声明sprite类名为同一sprite图icon的公共类,设置同一背景图与大小,在各个icon添加独立类名,如sprite-icon用于添加该icon的背景位置
      3. 先保证px单位的正确css样式,再将css根据比例转rem单位实现图标自适配
      4. 一些独立的icon背景图使用background-size: cover或百分比适配
    • home-card组件
      1. home页内容区由3个卡片组成,封装card组件,包括card-header栏和card-body
      2. home页面下card的card-body内容包括一个nav和swiper,封装为home-card组件于childCompos/homeCard,使用card-body的插槽插入nav和swiper
      3. home.vue使用home-card组件,传入title、icon、categories等props至组件,实现自定义card的头部,card的nav与轮播数据
      4. 其中轮播的swiperSlide内容通过home-card的插槽在home页插入单个slide内容
    • 后台新闻数据录入
      1. 提取官网数据:chrome支持\((".class")语法获取元素,如\)(“.class”).map(v => v.innerHTML);返回所有指定DOM元素的数据
      2. server后台添加一次录入初始数据的接口,该接口路由执行插入初始数据处理
      3. router/web/index.js引入Category、Article模型,取得所有article分类为“新闻分类”的子类目数组,官网新闻标题数据定义为title数组
      4. 将自类目数组,title数组对应关系通过map方法组成新闻标题数组,insertMany一次插入至Article模型中
    • 新闻分类数据接口
      • populate+schema.virtual虚拟字段实现,但是无法控制仅查询5个
      • aggregate+pipe管道查询
    • swiper与card-nav相互响应
      • 初始化swiper时绑定slideChange事件,轮播项改变后设置$refs.nav的activeIndex改变
      • 监听nav的handleClick事件,nav切换时设置swiper切换至对应索引轮播项
    • 后台英雄数据
      1. 官网数组nav-list,hero-list两层数组循环生成web端所需英雄数据格式
      2. aggreate对英雄分类下职业分类与heroes联表查询所有英雄数据以正确格式返回
  • article文章详情开发

    • 配置router
    • server添加’/article/:id’接口,返回指定id的文章数据
    • 查询当前article数据的下两条记录作为相关文章数据
  • hero详情页开发

    • 配置router
    • server添加’/hero/:id’接口,返回指定id的英雄数
    • 对测试的英雄记录补全hero页面所需的基本数据
    • 对于缺乏的字段,在Hero模型中添加字段,更新admin端使其支持编辑新字段

vue add 和 npm install 区别

es6中asnyc-await和promise都可用于异步,区别是?

  1. promise可以判断错误/成功预定义不同处理
  2. async-await会阻塞函数内部,函数外部依旧正常执行

注意

vue常见问题

  1. 一般情况下视图对其data存在依赖,当依赖一个数据对象的未初始化属性时,会报错

    依赖数据对象的属性,应当在数据对象声明默认值;或者显式赋值

  2. 在对v-for循环的item执行操作,相对于写在methods添加接受item参数的处理方法 也可以直接在v-for内直接编写处理逻辑

  3. 当后端传递的数据直接赋予data的某个数据对象的属性时,视图不会及时响应

    对于响应对象的未声明的属性,视图是不会对属性值进行响应的,此时需要显式赋值

  4. 数据绑定细节:list查询所有数据表时,将关联id的数据记录也返回;当查询单个记录时 ,只查询关联的id,通过查询其所有数据记录集自动匹配到值

  5. 添加Vue插件,调用全局vue的方法应通过vue.prototype上访问/调用

  6. 不要一昧使用:model=”变量名”数据绑定,对于固定的数据,直接title=”新闻”绑定,只有在绑定值为变量或后端数据时使用v-bind绑定

  7. router-view中同一组件的不同路由之间跳转,默认路由不更新,需绑定:key=”$route.path”声明path为更新键

  8. 子组件修改父组件传递的props报错,解决:data中新建一个属性将props值赋值后单独保存

目前写死的值有

  1. ItemEdit.vue的uploadUrl图片上传地址
  2. server端upload.js接口,file.url即返回图片的src值

admin前端没有对服务端操作失败导致进行处理

关于服务端错误

  1. 一种是代码执行错误,仅在服务端报错
  2. 另一种是响应请求错误,会返回前端
  3. 错误对象包含错误name和错误message,我们可以根据错误name的值判断,向前端响应自定义的错误数据

Sass语法

  1. $colors: (….)声明数组或map
  2. @each $key,$val in $list 遍历
  3. map-get($map,”$var”) 获取list/map值
  4. map-get获取颜色名为颜色关键字时加引号

css技巧

  • 网站各个主体部分间使用margin-top分隔,主体与之主体内子元素使用padding与margin-bottom结合布局
  • space-between布局时,如果最后一行未占满会以分离方式布局, 解决:父元素不设置space-between布局产生空隙,改为子元素添加margin-right产生空隙
  • 行布局要求行左右贴紧块的文字时,但元素块有左右padding,或固定宽,使用space-between无法解决,可为父元素左右添加负margin解决;
  • fixed定位元素100%宽会溢出,父元素添加overflow-x: hidden解决
  • 不同行内大小元素对齐:float+line-height

js技巧

  • 数组的map方法可以跳过数组的某些项返回数组

vue cli4配置

  1. 关于模块打包的浏览器支持配置在package.json下最后browserslist数组
  2. CLI4天生支持postcss,只需新建postcss.config.js配置autoprefixer即可
  3. 不同loader包版本配置时使用的方法可能不同,如sass loader配置全局变量,v8版本使用prependData,最新版使用additionalData
  4. label

mongoose数据库

  1. 在db.js连接数据库时,引入所有model模型文件,之后可通过mongoose,model(‘模型名’)快速引用模型
  2. 对查询完成的数据记录对象添加自定义字段前,需对数据对象调用lean方法转为json

swiper踩坑

  1. 准备swiper:安装swiper,引入附加功能模块

  2. 配置参数,如autoplay、loop、请求后台数据作为内容添加observe,

  3. mounted周期new Swiper初始化轮播

  4. 注意区分一个页面上多个swiper,即使配置一样,定义不同类名产生不同轮播实例

关于vue UI库

element ui pc端库,可做简单的pc页面与后台

vurtify 移动pc都支持,可自由组合的组件

iview pc后台专用

vant 移动端库,适用商城业务

vux 移动端库,类似微信界面UI,年轻的新框架,也有一些待完善的坑

quasar 支持spa,pwa,electron等各种形态,各端的web应用