React终极实战(一)-原型设计和数据模型

2018-02-11 14:09:35来源:segmentfault作者:青湛人点击

分享

React Target 我的React学习路径,接收任何建议,喜欢的点个赞,谢谢。

项目地址戳这里戳这里戳这里,你们的start就是我的动力!


关于

本篇作为我React项目实战的第一篇,也是我React Target 序中的第一篇,我还是有点紧张。但是其实这一篇并没有太多跟技术相关的内容,或者说跟React相关的内容,主要说一下我对将要开发的实战项目的原型设计和数据模型规划等的。


关于这个技术社区三端同构的意思就是客户端(client)、管理端(manage)和数据端(server)同时构建,搭建一个完整的技术社区也可以叫做技术论坛的这么一个东东,技术栈采用了没的说我爱的React + Redux + Express + MongoDB + Antd + Purely的方式,可能你没有听过Purely是什么,没关系,这个东西确实还不存在也可以说是还没有开始做,所以我的整体计划是先搭建管理端和数据端,管理端不用多说使用Antd并且很多地方参照Antd Pro,谁让我很喜欢这个UI呢。


前言

本来已经写好的文案...回退版本给我弄没了...心累!!从我刚刚入门前端到现在差不多1年出头了,收获了很多,也希望能够做点事情,我的初衷并不是做一个实际的项目,而是能帮助别人的工具,但是在开发工具的过程中才发现,没有一个实际的项目去测验工具的好坏我只能凭空想象,所以捡起一个我之前很早做的一个项目,来一次大革新,希望对你我都有所帮助!


本文跟之后的几篇文都可能随时更新,看我中途有没有改的想法了。
本意是想着整个项目做完了在慢慢写文的,但是呢,我真的是怕我忘了,所以中途可能有所更新。


其实写本文的时候,项目已经进行到能写三篇文的程度了,我真的是一心不能二用啊,写文章,项目就停下来了。


多说两句

前段时间我的直系领导兼产品经理让我在我们现有的产品上开发一个独立的功能,没有产品经理和设计的帮助,自己去设想功能和流程,给我苦的,本来是说让我先画原型图,但是对我来说真的是太难了,学很多技术的东西我都觉得时间不够,还哪有功夫去学axure做原型图设计。


后来我在做这个功能的时候,中间磕磕碰碰,拖了很长的时间走了很多弯路,才发现在一开始就对一个产品做好规划是有多么的重要,所以这一次,我决定做一个分析和原型图在正式开始这一次的产品实现。


准备工作

我们在做一个东西之前,总是要思考他能做什么,他需要实现哪些功能。可能这些设想对于我们以后来说不够完美,但是大体方向对了,我们才能节省更多的时间。


PS:此次原型设计只做客户端,管理端参照Antd Pro规划,我后面会对它进行详细的说明。

功能设想

这一次我打算做的是一个技术社区,当然我肯定不能做的跟segmentFault这么完善,但是我们还是要把想实现的功能先列出来,先来看一下我的设想。

用户注册、登录
能够发表文章
能够发表心情
可以给文章、心情点赞或者评论
编辑已经发表的文章
编辑个人信息
收藏文章

暂时我可能只能想到这些东西,我们可以后来慢慢去补充他。


原型设想

在做原型图之前,我们可以在脑海中,或者是在本子上随便的瞎画,去设想都需要哪些页面,我是比较喜好在本子上画的,毕竟我的设计水平有限....


如果是网页可能要复杂的多,所以我选择移动端的原因有很多的程度是由于移动端的原型更好设计,更为简单,元素更加的少。


初步预设就是底部菜单栏,分为五个模块分别是:主页、分类、发布、心情和用户中心。

主页:用于展示文章和心情头条内容
分类:用于展示所有分类信息
发布:用于发布文章和心情内容
心情:用于展示所有用户发布的心情
个人中心: 用于展示和修改个人信息

在这些准备工作完成后,我们就可以开始做原型图了,这里再说两句,其实吧,对于我们这种没有设计基础的程序员来说,基本可以使用模仿的方式,模仿那些已经很成熟的产品,像我做这个技术社区就打算模仿掘金APP,segmentFault手机版网页和一个APP。


原型图

在我司,产品经理都是用axure画的原型图,但是为了画个原型图我还要去学习axure的使用,成本略高,所以我选择了比较傻瓜式的在线画原型图的网站,我用的是墨刀还蛮好用的,你也可以选择别的,我也不是很熟,可以自行搜索。


画的过程我就不多说了,比较傻瓜式,来看看我最终的基本效果,略丑(别笑我....):



segmentdefault不太智能,不能控制图片大小,加上图片略多,放上来太占地方了,就放了一张主页,剩下的可以通过下面的外链的方式查看哈:

文章详情页
分类页
分类展示页
添加页
添加文章页
添加心情页
心情页
心情详情页
登录页
注册页
个人中心页数据模型

其实对于数据结构我也是外行(虽然我也算是软工出身但是学的真不好),在用MongoDB的过程中,也就知道了一些皮毛的知识,不敢随便乱说。但是我们只需要知道我们需要哪些东西,需要存储哪些东西就行。我会用到的模型大概就六种管理员、用户、文章、心情和分类,你可能要问这才五种啊,还有一种Ids用来管理每个模型的id,为什么这么做呢?因为mongodb自己生成的id是一长串字符串,不好理解,所以我单独用了一个Ids模型用来生成我其他模型的数字id。


建立MongoDB模型还算比较简单,这里我使用了一个外部依赖mongoose来帮助我更加简单的搭建MongoDB模型和连接我的Node程序,至于如何建立数据模型看我下面的代码,我把所有的模型都存储在server/models目录下方便我管理这些模型。


PS:我以后本系列的文章所说的目录皆以我的项目qz-demo为根目录,像server/models就是qz-demo/server/models目录。

管理员模型

管理员模型需要存储这些字段的信息:


id:作为它的唯一标识,其实MongoDB自带这个标识,但是复杂度太高,我想用单纯的数字来表示它。username:管理员账户名 (唯一值,字符串类型,必须值)password:管理员密码 (字符串类型,必须值)mobile:管理员手机号 (唯一值,字符串类型,必须值)roles:管理员权限值 (数字类型,必须值,默认值为1)status:管理员账户状态 (字符串类型,必须值,默认值为info)

关于最后一个字段status我多说两句,这个是我在管理员账户上多做了一重限制,不是每个人都可以直接注册成为管理员的,你只能通过申请的方式,以这个字段作为申请管理员账户的状态值,方便超级管理员审核和拒绝管理员申请。


最后我直接初始化了一个超级管理员账户qingzhan,方便我们管理。字段暂时就先这些,后面用到别的我们在来补充,下面看一下代码。


路径为server/models/admin.js:


import mongoose from 'mongoose';const Schema = mongoose.Schema;const AdminSchema = new Schema({
id: { unqie: true, type: Number, isRequire: true },
username: { unqie: true, type: String, isRequire: true },
password: { type: String, isRequire: true },
mobile: { unqie: true, type: String, isRequire: true },
roles: { type: Number, isRequire: true, default: 1},
status: { type: String, isRequire: true, default: 'info' }
});AdminSchema.index({ id: 1 });const Admin = mongoose.model('Admin', AdminSchema);Admin.findOne((err, data) => {
if (!data) {
const rootAdmin = new Admin({
id: 0,
username: 'qingzhan',
password: 'a123456',
mobile: '18788888888',
roles: 101,
status: 'success'
});
rootAdmin.save();
}
});export default Admin;
用户模型

用户模型需要存储这些字段的信息:


id:依然是它的唯一标识mobile:用户登录账户 (唯一值,数字类型,必须值)password:用户登录密码 (字符串类型,必须值)nickname:用户昵称 (唯一值,字符串类型,必须值)motto:用户简介 (字符串类型)post:用户发表的文章列表 (数组类型,存储文章ID)mood:用户发表的心情列表 (数组类型,存储心情ID)collect:用户收藏列表 (数组类型,存储文章ID)praise:用户点赞列表 (数组类型,存储文章或者心情ID)dynamic:用户动态信息 (数组类型,存储用户信息列表)follow:用户关注人的列表 (数组类型,存储用户ID)fans:户在粉丝列表 (数组类型,存储用户ID)

用户模型的每一个字段都挺好理解的,所以我也不多说了,跟我继续走,没有什么特殊的地方我就直接略过了。


路径为server/models/user.js:


import mongoose from 'mongoose';const Schema = mongoose.Schema;const UserSchema = new Schema({
id: { unqie: true, type: Number, isRequire: true },
mobile: { unqie: true, type: Number, isRequire: true },
password: { type: String, isRequire: true },
nickname: { unqie: true, type: String, isRequire: true },
motto: { type: String },
post: [Number],
mood: [Number],
collect: [Number],
praise: [Number],
dynamic: [String],
follow: [Number],
fans: [Number]
});UserSchema.index({ id: 1 });const User = mongoose.model('User', UserSchema);export default User;
文章模型

我的文章模型需要存储这些字段的信息:


id:依然用来作为它的唯一标识。genre:文章分类 (字符串类型,必须值)title:文章标题 (唯一值,字符串类型,必须值)content:文章内容 (字符串类型,必须值)praise_num:文章点赞数 (数字类型,默认值为0)comment:文章评论列表 (数组类型)author:文章作者 (数字类型,必须值)create_at:文章创建时间 (字符串类型, 必须值)update_at:文章最后一次修改时间 (字符串类型, 必须值)

路径为server/models/post.js:


import mongoose from 'mongoose';const Schema = mongoose.Schema;const PostSchema = new Schema({
id: { unqie: true, type: Number, isRequire: true },
genre: { type: String, isRequire: true },
title: { type: String, isRequire: true },
content: { type: String, isRequire: true },
praise_num: { type: Number, default: 0 },
comment: [Object],
author: { type: Number, isRequire: true },
create_at: { type: String, isRequire: true },
update_at: { type: String }
});PostSchema.index({ id: 1 });const Post = mongoose.model('Post', PostSchema);export default Post;
心情模型

我的心情模型需要存储这些字段的信息:


id:依然用来作为它的唯一标识。content:心情内容 (字符串类型,必须值)author:心情发布人 (数字类型,必须值)praise_num:心情点赞数 (数字类型,默认值为0)comment:心情评论列表 (数组类型)create_at:心情创建时间 (字符串类型,必须值)

路径为server/models/mood.js:


import mongoose from 'mongoose';const Schema = mongoose.Schema;const MoodSchema = new Schema({
id: { unqie: true, type: Number, isRequire: true },
content: { type: String, isRequire: true },
author: { type: Number, isRequire: true },
praise_num: { type: Number, default: 0 },
comment: [Object],
create_at: { type: String, isRequire: true }
});MoodSchema.index({ id: 1 });const Mood = mongoose.model('Mood', MoodSchema);export default Mood;
分类模型

我的心情模型需要存储这些字段的信息:


id:依然用来作为它的唯一标识。name:分类名称 (唯一值,字符串类型,必须值)posts:分类下文章列表 (数组类型,默认值为[])

路径为server/models/genre.js:


import mongoose from 'mongoose';const Schema = mongoose.Schema;const GenreSchema = new Schema({
id: { unqie: true, type: Number, isRequire: true },
name: { unqie: true, type: String, isRequire: true },
posts: { type: Array, default: [] }
});GenreSchema.index({ id: 1 });const Genre = mongoose.model('Genre', GenreSchema);export default Genre;
ID模型

我最后来说一下这个比较特殊的ID模型,作用就是辅助我们生成其他每个模型的数字ID,来看看它怎么生成我们想要的数字ID吧。


import mongoose from 'mongoose';const Schema = mongoose.Schema;const IdsSchema = new Schema({
admin_id: Number,
user_id: Number,
genre_id: Number,
post_id: Number,
mood_id: Number
});const Ids = mongoose.model('Ids', IdsSchema);Ids.findOne((err, data) => {
if (!data) {
const newIds = new Ids({
admin_id: 1,
user_id: 1,
genre_id: 1,
post_id: 1,
mood_id: 1
});
newIds.save();
}
});export default Ids;

注意看,其实这个模型从一开始到最后都只会有一条数据,里面保存着最新的各个模型的ID号,最开始连接数据库后与管理员初始化超管一个道理,我初始化了一条每个模型的ID都为1的数据,之后我通过一个getId的方法来获取最新的ID并且把当前IDS模型中的那个字段加1,我们来看看我的getId方法是怎么做的。


// 初始化一个id类型列表
const idList = ['admin_id', 'user_id', 'genre_id', 'post_id', 'mood_id'];
// 传入我获取id的类型
async function getId(type) {
// 如果传入的类型不在我一开始定义的类型中就抛出错我
if (!idList.includes(type)) {
console.error('Id 类型错误!');
return false;
}
try {
// 获取到我的ids里面的那条数据
const idData = await Ids.findOne();
// 使其为当前值加一,如果管理员已经存在5个了,这个时候admin_id就为5,使其加一作为第6个管理员的id
idData[type]++;
// 保存到ids模型中
await idData.save();
// 返回当前的id号,以前面的列子就是6
return idData[type];
} catch(err) {
// 这里我用了 async/await 关键字,try/catch用来捕获ids查找数据失败时的错误
console.error(`${chalk.redBright('获取id数据失败')}`);
return false;
}
}

看到这里模型我就说完了,我不敢绝对的说以后的模型就是这个了,可能后期会由于功能的增加增加字段或者是新的模型,我会回头来补这一篇,其实我写到这里的时候我管理端注册登录已经完成的差不多了,你可以看我的代码先走一步,你也可以等我下一篇的说明,最后在贴一个项目的地址qz-demo,使劲戳下面的链接。


链接使劲戳我戳我戳我!!


本篇结尾

其实本篇写的东西我作为一个前端开发者来说并不是很熟,但是我还是去尝试了,我希望我这一次做的这个产品能够对我的提高起到很多的帮助,也希望我的项目和我的博客能对在看本文的你来说有巨大的帮助。


技术的提高是在不断的学习、学习、学习中成长的,与君共勉!

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台