后端使用node写的一个一整套的博客系统javascript
#### 主要功能css
nodehtml
html css js ajax等前端
indexjava
详情页node
后台git
├─models 存放数据库数据模型
├─public 存放静态资源
├─routers 路由文件
├─schemas 数据库Schema表
└─views 静态页面github
│ .gitignore github仓库上传忽略文件
│ app.js 主程序入口文件
│ package-lock.json
│ package.json
│ README.mdajax
使用npm安装项目要使用的包sql
var express = require('express') var mongoose = require('mongoose') var app = express() // 链接数据库 mongoose.connect('mongodb://localhost/node-blog', { useNewUrlParser: true }); app.listen(3000, function () { console.log('http://localhost:3000') })
// 定义模板引擎 app.engine('html', swig.renderFile) // 设置模板文件存放目录 app.set('views', './views') // 注册模板引擎 app.set('view engine', 'html') //设置swig页面不缓存 swig.setDefaults({ allowErrors: false, autoescape: true, cache: false })
// 静态文件托管 app.use('/public', express.static(__dirname + '/public')
知识点1:在 Express 中提供静态文件
为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的
express.static
内置中间件函数。
app.use(express.static('public'));
这样后 咱们就能够访问public文件中的任意目录的任意文件:
http://localhost:3000/images/kitten.jpg http://localhost:3000/css/style.css http://localhost:3000/js/app.js
注意: Express 相对于静态目录查找文件,所以静态目录的名称不是此 URL 的一部分。
能够屡次使用static函数开启多个静态资源入口。
自定义文件目录名称
上面的例子中咱们能够访问 http://localhost:3000/js/app.js
这个目录 可是若是我想经过http://localhost:3000/static/js/app.js
来访问,咱们可使用:
app.use('/static', express.static('public'));
来建立虚拟路径前缀(路径并不实际存在于文件系统中)
固然,在项目中通常使用绝对路径来保证代码的可行性:
app.use('/static', express.static(__dirname + '/public'));
// 链接数据库 mongoose.connect('mongodb://localhost/node-blog' { useNewUrlParser: true });
mongod会在第一个数据建立的时候新建咱们的node-blog数据库,不须要咱们手动建立
后面的一个配置项最好加上。不报错的话可不加。
// 路由 app.use('/admin', require('./routers/admin')) app.use('/api', require('./routers/api')) app.use('/', require('./routers/main'))
知识点2:express.Router的使用
使用
express.Router
类来建立可安装的模块化路由处理程序。Router
实例是完整的中间件和路由系统;所以,经常将其称为“微型应用程序”。
使用express.Router,能够将路由更加模块化
好比:在 routers文件夹下新建 main.js
var express = require('express') var router = express.Router() ... router.get('/', function (req, res, next) { ... } router.get('/view',(req, res) => { ... } module.exports = router
末尾使用module.exports = router 将router对象暴露出去
咱们将其安装在主应用程序app.js的路径中
... app.use('/', require('./routers/main')) ...
此时的 ‘/’ 路径请求的就是 main.js中的 ’/‘
/view --> main.js 中的 '/view'
功能模块开发顺序
编码顺序
新建并编写 schemas/user.js
var mongoose = require('mongoose') // 用户表结构 module.exports = new mongoose.Schema({ username: { type: String }, password: { type: String } })
var mongoose = require('mongoose') var userSchema = require('../schemas/user') module.exports = mongoose.model('User', userSchema)
知识点3:mongoose中的 Schema 和 Model
Mongoose 的一切始于 Schema。每一个 schema 都会映射到一个 MongoDB collection ,并定义这个collection里的文档的构成
定义一个schema
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var blogSchema = new Schema({ title: String, author: String, body: String, comments: [{ body: String, date: Date }], date: { type: Date, default: Date.now }, hidden: Boolean, meta: { votes: Number, favs: Number } });
建立一个model
咱们要把 schema 转换为一个 Model, 使用
mongoose.model(modelName, schema)
函数:
var Blog = mongoose.model('Blog', blogSchema);
Models 是从 Schema
编译来的构造函数。 它们的实例就表明着能够从数据库保存和读取的 documents。 从数据库建立和读取 document 的全部操做都是经过 model 进行的。
第一个参数是跟 model 对应的集合( collection )名字的 单数 形式。 Mongoose 会自动找到名称是 model 名字 复数形式的 collection 。 对于上例,Blog这个 model 就对应数据库中 blogs 这个 collection。.model()
这个函数是对 schema
作了拷贝(生成了 model)。
你要确保在调用
.model()
以前把全部须要的东西都加进schema
里了
一个model就是创造了一个mongoose实例,咱们才能将其操控。
个人片面理解把Schema和model的关系 想成 构造函数和实例之间的关系
注册逻辑
静态页面
处理 前端ajax注册
// 注册 $register.find('.user_register_btn').on('click', function () { $.ajax({ type: 'post', url: 'api/user/register', data: { username: $register.find('[name="username"]').val(), password: $register.find('[name="password"]').val(), repassword: $register.find('[name="repassword"]').val() }, dataType: 'json', success: function (result) { $register.find('.user_err').html(result.message) if (!result.code) { setTimeout(() => { $('.j_userTab span')[0].click() }, 1000) } } }) })
后台api路由
在api.js中编写后台注册相关代码
/* 注册: 注册逻辑 1. 用户名不能为空 2. 密码不能为空 3. 两次密码一致 数据库查询 1. 用户名是否已经被注册 */ router.post('/user/register', function (req, res, next) { var username = req.body.username var password = req.body.password var repassword = req.body.repassword // -------表单简单验证----------- if (username == '') { responseData.code = 1 responseData.message = '不填用户名啊你' res.json(responseData) return } if (password == '') { responseData.code = 2 responseData.message = '密码不填?' res.json(responseData) return } if (password !== repassword ) { responseData.code = 3 responseData.message = '两次密码不一致啊' res.json(responseData) return } // ------------------------------- // -------数据库验证验证----------- User.findOne({ username: username }).then((userInfo) => { if (userInfo) { // 数据库中已有用户 responseData.code = 4 responseData.message = '用户名有了,去换一个' res.json(responseData) return } // 保存用户注册信息 var user = new User({ username: username, password: password }) return user.save() }).then((newUserInfo) => { responseData.message = '耶~ 注册成功' res.json(responseData) }) // ------------------------------- })
后台经过简单的验证,将结果经过 res.json
的方式来返还给 前台 ajax 再经过json信息来处理页面展现。
知识点4:使用body-parser
中间件来处理post请求
使用案例
var express = require('express') var bodyParser = require('body-parser') var app = express() // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })) // parse application/json app.use(bodyParser.json())
经过以上的配置,咱们就能够获取经过 req.body 来获取 post 请求总的参数了
... var username = req.body.username var password = req.body.password var repassword = req.body.repassword ...
知识点5: mongoose中数据库的操做
前段时间总结过一些mongoose的增删查操做笔记:
#### 3.4 登陆
前台ajax
// 登陆 $login.find('.user_login_btn').on('click', function () { $.ajax({ type: 'post', url: 'api/user/login', data: { username: $login.find('[name="username"]').val(), password: $login.find('[name="password"]').val(), }, dataType: 'json', success: function (result) { $login.find('.user_err').html(result.message) // 登陆成功 if (!result.code) { window.location.reload() } } }) })
后台路由处理及数据库查询
// 登陆逻辑处理 router.post('/user/login', (req, res) => { var username = req.body.username var password = req.body.password if (username == '' || password == '') { responseData.code = 1 responseData.message = '去填完再点登陆' res.json(responseData) return } // 查询数据库用户名密码同时存在 User.findOne({ username: username, password: password }).then((userInfo) => { if (!userInfo) { responseData.code = 2 responseData.message = '用户名或密码错啦' res.json(responseData) return } // 正确 登陆成功 responseData.message = '耶~ 登陆成功' responseData.userInfo = { _id: userInfo._id, username: userInfo.username } req.cookies.set('userInfo', JSON.stringify({ _id: userInfo._id, username: escape(userInfo.username) })) res.json(responseData) }) })
上面的案例中,为了记录咱们的登陆状态,咱们使用了第三发包 -- cookies 来存储登陆信息
app 引入 cookies模块
var Cookies = require('cookies')
在 api.js 中获取 cookies
req.cookies.set('userInfo', JSON.stringify({ _id: userInfo._id, username: escape(userInfo.username) }))
在 app.js 中解析登陆用户的cookies
// 设置cookies app.use((req, res, next) => { req.cookies = new Cookies(req, res) // 解析登陆用户的cookies req.userInfo = {} if (req.cookies.get('userInfo')) { try { req.userInfo = JSON.parse(req.cookies.get('userInfo')) // 获取用户是不是管理员 User.findById(req.userInfo._id).then((userInfo) => { req.userInfo.isAdmin = Boolean(userInfo.isAdmin) next() }) } catch (e) { next() } } else { next() } }
用 swig 渲染模板控制 index页面
ajax --》 api.js --> cookies设置为空 -> 刷新页面
登出的实现就比较简单,只需将cookies设置为空便可
前台ajax
// 登出 $('#logout').on('click', function () { $.ajax({ url: '/api/user/logout', success: function(result) { if (!result.code) { window.location.reload() } } }) })
api路由
// 退出登陆 router.get('/user/logout', (req, res) => { req.cookies.set('userInfo', null) res.json(responseData) })
缘由 cookies在存储中午时出现乱码
解决办法 将username进行转码再解码
使用 encode
和 decode
来进 编码和解码
给userInfo 添加 isAdmin 属性
使用swig 选择渲染
公用的继承
{% extends 'layout.html' %}
特殊的重写
{% block main %} <div class="jumbotron"> <h1>Hello, {{userInfo.username}}!</h1> <p>欢迎进入后台管理</p> </div> {% endblock%}
admin 首页
// 首页 router.get('/', (req, res, next) => { res.render('admin/index', { userInfo: req.userInfo }) })
创建静态 user_index.html
处理路由及分页逻辑
// 用户管理 router.get('/user', (req, res) => { /* 从数据库中读取全部的用户数据 limit(number) 限制获取的数据条数 skip(number) 忽略数据的条数 每页显示 5 条 第一页: 1-5 skip:0 -> (当前页 1 - 1) * 每页的条数 第二页: 6-10 skip:5 -> (当前页 2 - 1) * 每页的条数 ... ... User.count() 查询总数据量 */ var page = Number(req.query.page || 1) var pages = 0 var limit = 10 User.count().then((count) => { // 计算总页数 pages = Math.ceil(count / limit) // 取值不能超过 pages page = Math.min(page, pages) // 取值不能小于1 page = Math.max(page, 1) var skip = (page - 1) * limit // 读取数据库中全部用户数据 User.find().limit(limit).skip(skip).then((users) => { res.render('admin/user_index', { userInfo: req.userInfo, users: users, page: page, pages: pages, count: count, limit: limit }) }) }) })
页面展现 --table表格
分页
数据里 limit
skip()
分页原理
/* 从数据库中读取全部的用户数据 limit(number) 限制获取的数据条数 skip(number) 忽略数据的条数 每页显示 5 条 第一页: 1-5 skip:0 -> (当前页 1 - 1) * 每页的条数 第二页: 6-10 skip:5 -> (当前页 2 - 1) * 每页的条数 ... ... */ var page = req.query.page || 1 var limit = 5 var skip = (page - 1) * limit User.find().limit(limit).skip(skip).then((users) => { res.render('admin/user_index', { userInfo: req.userInfo, users: users }) })
客户端实现
<nav aria-label="..."> <ul class="pager"> <li class="previous"><a href="/admin/user?page={{page-1}}"><span aria-hidden="true">←</span>上一页</a></li> <li> 一共有 {{count}} 条数据 || 每页显示 {{limit}} 条数据 || 一共 {{pages}} 页 || 当前第 {{page}} 页 </li> <li class="next"><a href="/admin/user?page={{page+1}}">下一页<span aria-hidden="true">→</span></a></li> </ul> </nav>
服务端代码
/* 从数据库中读取全部的用户数据 limit(number) 限制获取的数据条数 skip(number) 忽略数据的条数 每页显示 5 条 第一页: 1-5 skip:0 -> (当前页 1 - 1) * 每页的条数 第二页: 6-10 skip:5 -> (当前页 2 - 1) * 每页的条数 ... ... User.count() 查询总数据量 */ var page = Number(req.query.page || 1) var pages = 0 var limit = 5 User.count().then((count) => { // 计算总页数 pages = Math.ceil(count / limit) // 取值不能超过 pages page = Math.min(page, pages) // 取值不能小于1 page = Math.max(page, 1) var skip = (page - 1) * limit User.find().limit(limit).skip(skip).then((users) => { res.render('admin/user_index', { userInfo: req.userInfo, users: users, page: page, pages: pages, count: count, limit: limit }) }) })
抽取page 使用 include 语法之后复用
分类首页
category_index.html
添加分类
category_add.html
get 渲染页面
post 提交页面
设计表结构
schemas/categories.js
models/categories.js
相关代码
/* 添加分类页面 */ router.get('/category/add', (req, res) => { res.render('admin/category_add', { userInfo: req.userInfo }) }) /* 添加分类的保存 */ router.post('/category/add', (req, res) => { var name = req.body.name || '' if (name == '') { res.render('admin/error', { userInfo: req.userInfo, message: '名称不能为空' }) return } // 是否已有分类 Category.findOne({ name: name }).then((result) => { if (result) { // 数据库中已经存在 res.render('admin/error', { userInfo: req.userInfo, message: '分类已经存在' }) return Promise.reject() } else { // 数据库中不存在分类 return new Category({ name: name }).save() } }).then((newCategory) => { res.render('admin/success', { userInfo: req.userInfo, message: '分类保存成功', url: '/admin/category' }) }) })
经过判断 渲染 error 或者 success 的页面 两个页面都在 admin/error.html
和 admin/success.html
中
首页展现展现
同用户管理首页展现同样
/* 分类首页 */ router.get('/category', (req, res) => { var page = Number(req.query.page || 1) var pages = 0 var limit = 10 Category.count().then((count) => { // 计算总页数 pages = Math.ceil(count / limit) // 取值不能超过 pages page = Math.min(page, pages) // 取值不能小于1 page = Math.max(page, 1) var skip = (page - 1) * limit Category.find().limit(limit).skip(skip).then((categories) => { res.render('admin/category_index', { userInfo: req.userInfo, categories: categories, page: page, pages: pages, count: count, limit: limit }) }) }) })
分类修改 删除
在渲染的分类首页的分类表格中加入
<td> <a href="/admin/category/edit?id={{category._id.toString()}}" class="btn btn btn-primary">修改</a> <a href="/admin/category/delete?id={{category._id.toString()}}" class="btn btn-danger">删除</a> </td>
经过query的传值分类的id 值 咱们来操做id
修改
get
/* 分类修改 get */ router.get('/category/edit', (req, res) => { // 获取要修改的分类信息 表单形式展示出来 var id = req.query.id || '' // 获取修改的分类信息 Category.findById(id).then((category) => { if (!category) { res.render('admin/error', { userInfo: req.userInfo, message: '分类信息不存在' }) return Promise.reject() } else { res.render('admin/category_edit', { userInfo: req.userInfo, category: category }) } }) })
post
/* 分类修改 post */ router.post('/category/edit', (req, res) => { var id = req.query.id || '' var name = req.body.name || '' Category.findById(id).then((category) => { if (!category) { res.render('admin/error', { userInfo: req.userInfo, message: '分类信息不存在' }) return Promise.reject() } else { // 当前用户没有作任何修改而提交 if (name == category.name) { res.render('admin/success', { userInfo: req.userInfo, message: '修改为功', url: '/admin/category' }) return Promise.reject() } else { // 要修改的分类名称是否已经在数据库中 return Category.findOne({ // id 不等于当前的id _id: {$ne: id}, name: name }) } } }).then((sameCategory) => { if (sameCategory) { res.render('admin/error', { userInfo: req.userInfo, message: '已存在同名分类' }) return Promise.reject() } else { return Category.findByIdAndUpdate(id, { name: name }) } }).then(() => { res.render('admin/success', { userInfo: req.userInfo, message: '修改分类名称成功', url: '/admin/category' }) }) })
删除
/* 分类删除 */ router.get('/category/delete', (req, res) => { // 获取id var id = req.query.id || '' Category.remove({ _id: id }).then(() => { res.render('admin/success', { userInfo: req.userInfo, message: '删除成功', url: '/admin/category' }) }) })
/* 内容首页 */ router.get('/content', (req, res) => { res.render('admin/content_index', { userInfo: req.userInfo }) }) /* 内容添加 */ router.get('/content/add', (req, res) => { Category.find().sort({_id: -1}).then((categories) => { console.log(categories) res.render('admin/content_add', { userInfo: req.userInfo, categories: categories }) }) })
新建 schemas/content.js 和 models/content.js 创建content模型
处理路由
post
后台
// 保存内容到数据库 new Content({ category: req.body.category, title: req.body.title, description: req.body.description, content: req.body.content }).save().then((content) => { res.render('admin/success', { userInfo: req.userInfo, message: '内容保存成功', url: '/admin/content' }) }) })
module.exports = new mongoose.Schema({ title: { type: String }, // 引用 关联字段 category: { type: mongoose.Schema.Types.ObjectId, //引用 另一张表的模型 ref: 'Category' }, description: { type: String, default: '' }, content: { type: String, default: '' } })
咱们在 处理 content 的 category的时候 关联个 另一个结构表
在渲染页面的时候用mongoose 中提供搞得 populate() 方法
知识点6: mongoose中的表关联
Population 能够自动替换 document 中的指定字段,替换内容从其余 collection 获取。 咱们能够填充(populate)单个或多个 document、单个或多个纯对象,甚至是 query 返回的一切对象
简单的说,A表的能够关联B表,经过调用A表的属性数据取到B表内容的值,就像sql的join的聚合操做同样。
var mongoose = require('mongoose'); var Schema = mongoose.Schema; var personSchema = Schema({ _id: Schema.Types.ObjectId, name: String, age: Number, stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }] }); var storySchema = Schema({ author: { type: Schema.Types.ObjectId, ref: 'Person' }, title: String, fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }] }); var Story = mongoose.model('Story', storySchema); var Person = mongoose.model('Person', personSchema);
咱们建立了Story 和 Person两个数据库实例。
Person
model 的 stories
字段设为 ObjectId
数组。 ref
选项告诉 Mongoose 在填充的时候使用哪一个 model,本例中为 Story
model。
接下来咱们使用 Population 来填充使用
Story. findOne({ title: 'Casino Royale' }). populate('author'). exec(function (err, story) { if (err) return handleError(err); console.log('The author is %s', story.author.name); // prints "The author is Ian Fleming" });
更多高级用法: Mongoose Populate
/* 修改内容 */ router.get('/content/edit', (req, res) => { // 获取要修改的内容信息 表单形式展示出来 var id = req.query.id || '' var categories = [] // 获取分类信息 Category.find().sort({ _id: -1 }) .then((result) => { categories = result return Content.findById(id).populate('category') }) .then((content) => { console.log(content) if (!content) { res.render('admin/error', { userInfo: req.userInfo, message: '指定内容不存在' }) return Promise.reject() } else { res.render('admin/content_edit', { userInfo: req.userInfo, content: content, categories: categories }) } })
/* 内容修改 */ router.post('/content/edit', function(req, res) { var id = req.query.id || '' if (req.body.title == '') { res.render('admin/error', { userInfo: req.userInfo, message: '标题不能为空' }) return } if (req.body.description == '' || req.body.content == '') { res.render('admin/error', { userInfo: req.userInfo, message: '简介和内容不能为空' }) return } Content.findByIdAndUpdate(id, { category: req.body.category, title: req.body.title, description: req.body.description, content: req.body.content }).then(() => { res.render('admin/success', { userInfo: req.userInfo, message: '内容保存成功', url: '/admin/content' }) }) }) })
/* 内容删除 */ router.get('/content/delete', (req, res) => { // 获取id var id = req.query.id || '' Content.remove({ _id: id }).then(() => { res.render('admin/success', { userInfo: req.userInfo, message: '删除成功', url: '/admin/content' }) }) })
做者 -- 关联 user表
建立时间 -- new Date()
前台渲染
<td>{{content.addTime|date('Y-m-d H:i:s', -8*60)}}</td>
点击量 --》 先默认为 0
有了后台的数据,咱们接下来看前台的
修改 main.js
/* 首页渲染 */ router.get('/', function (req, res, next) { req.userInfo.username = unescape(req.userInfo.username) var data = { userInfo: req.userInfo, categories: [], contents: [], count: 0, page : Number(req.query.page || 1), pages : 0, limit : 10 } Category.find() .then((categories) => { data.categories = categories return Content.count() }) .then((count) => { data.count = count // 计算总页数 data.pages = Math.ceil(data.count / data.limit) // 取值不能超过 pages data.page = Math.min(data.page, data.pages) // 取值不能小于1 data.page = Math.max(data.page, 1) var skip = (data.page - 1) * data.limit return Content .find() .sort({ addTime: -1 }) .limit(data.limit) .skip(skip) .populate(['category', 'user']) }) .then((contents) => { data.contents = contents console.log(data) res.render('main/index', data) }) })
使用swig的渲染模板 完善页面信息,不在赘述
{% if pages > 1 %} <nav aria-label="..." id="pager_dh"> <ul class="pager"> {% if page <=1 %} <li class="previous"><span href="#"><span aria-hidden="true">←</span>没有上一页了</span></li> {%else%} <li class="previous"><a href="/?category={{category}}&page={{page-1}}"><span aria-hidden="true">←</span>上一页</a></li> {%endif%} <span class="page_text">{{page}} / {{pages}}</span> {% if page >=pages %} <li class="next"><span href="#">没有下一页了<span aria-hidden="true">→</span></li> {%else%} <li class="next"><a href="/?category={{category}}&page={{page+1}}">下一页<span aria-hidden="true">→</span></a></li> {%endif%} </ul> </nav> {%endif%}
咱们建立addTime的时候,会发现mongod建立的数据的时间戳彻底同样
咱们不能使用new date()
来建立默认时间 使用 Date.now
var where = {} if (data.category) { where.category = data.category }
mongoose查询的时候使用 where
查询
<nav class="head_nav"> {% if category == ''%} <a href="/" id="inactive">首页</a> {%else%} <a href="/">首页</a> {%endif%} {% for cate in categories%} {% if category == cate.id%} <a href="/?category={{cate.id}}" id="inactive">{{cate.name}}</a> {%else%} <a href="/?category={{cate.id}}">{{cate.name}}</a> {%endif%} {% endfor %} </nav>
评论使用ajax来操做
使用ajax操做不刷新页面来操做api
后台api代码
/* 进入详情获取评论 */ router.get('/comment/post', (req, res) => { var contentid = req.query.contentid Content.findById(contentid) .then((content) => { responseData.data = content.comments res.json(responseData) }) }) /* 评论提交 */ router.post('/comment/post', (req, res) => { var contentid = req.body.contentid var postData = { username: req.userInfo.username, postTime: Date.now(), content: req.body.content } // 查询文章内容信息 Content.findById(contentid) .then((content) => { content.comments.push(postData) return content.save() }) .then((newContent) => { responseData.message = '评论成功!' responseData.data = newContent res.json(responseData) }) })
评论代码
ajax的操做都封装在了 routers/api.js 中
评论相关操做咱们都放在了js/comments.js 中
var limit = 4 var page = 1 var pages = 0 var comments = [] // 加载全部评论 $.ajax({ type: 'get', url: 'api/comment/post', data: { contentid: $('#contentId').val(), }, success: ((responseData) => { comments = responseData.data renderComment() }) }) $('.pager').delegate('a', 'click', function() { if ($(this).parent().hasClass('previous')) { page-- } else { page++ } renderComment() }) // 提交评论 $('#commentBtn').on('click',function() { $.ajax({ type: 'post', url: 'api/comment/post', data: { contentid: $('#contentId').val(), content: $('#commentContent').val() }, success: ((responseData) => { $('#commentContent').val('') comments = responseData.data.comments renderComment(true) }) }) }) function renderComment (toLaster) { $('#discuss_count').html(comments.length) var $lis = $('.pager li') pages = Math.ceil(comments.length / limit) if (!toLaster) { var start = (page-1) * limit } else { var start = (pages - 1) * limit page = pages } var end = (start + limit) > comments.length ? comments.length : (start + limit) if (pages <= 1) { $('.pager').hide() } else { $('.pager').show() $lis.eq(1).html(page + '/' + pages ) if (page <= 1) { page = 1 $lis.eq(0).html('<span>已经是最前一页</span>') } else { $lis.eq(0).html('<a href="javacript:void(0);">上一页</a>') } if (page >= pages) { page = pages $lis.eq(2).html('<span>已经是最后一页</span>') } else { $lis.eq(2).html('<a href="javacript:void(0);">下一页</a>') } } var html = '' if (comments.length) { for (var i = start; i < end; i++) { html += ` <li> <p class="discuss_user"><span>${comments[i].username}</span><i>发表于 ${formatDate(comments[i].postTime)}</i></p> <div class="discuss_userMain"> ${comments[i].content} </div> </li> ` } } $('.discuss_list').html(html) } function formatDate(d) { var date1 = new Date(d) return date1.getFullYear() + '年' + (date1.getMonth()+1) + '月' + date1.getDate() + '日' + date1.getHours() + ':' + date1.getMinutes() + ':' + date1.getSeconds() }
项目这个阶段知识简单能跑痛而已,包括细节的优化,和程序的安全性都没有考虑,安全防范措施为零,这也是之后要学习的地方。
第一次使用node写后台,完成了一次先后端的完整交互,最终要的仍是作后台的一种思想,一种处理先后台关系的逻辑。
收获了不少,愈来愈感受本身要学的东西太多了,本身好菜。。
写总结文档有点累唉 _(°:з」∠)_秃头。