内容简介:最近学了:point_right:在线demo点击这里:point_right:
最近学了 react
,一直想做一个项目,没有什么好的主意。因为自己也要租房住,就想到了 租房App
这个idea,参考豆瓣租房小程序,着手了这样一个简陋的前后端项目:smile:。
:point_right:在线demo点击这里
:point_right: 项目源码点击这里 ,你可以下载在本地运行,如果对你有帮助可以点一下 star
哈:grin:
// 你可以使用npm或yarn yarn install 运行你的数据库 // 必须!!! yarn server // 运行服务器, 连接的数据库在server目录下的config.js里配置 yarn start // 运行项目 复制代码
二、前端
- 项目技术栈
react+react-router+react-redux
,用create-react-app
脚手架生成。UI方面采用Ant Design Mobile
:point_right:官方地址。 -
css
方案是css-in-js,采用style-jsx
,:point_right: github地址 ,可参考掘金上的一篇文章:point_right:点击这里。 - 由于是移动端,避免不了
适配
问题,采用vm/vh
适配,具体同样可以参考掘金的:point_right:这篇文章。 - 在结合 2、3 两点时,由于要添加配置项,但我不想在项目中
run eject
弹出,于是用了react-app-rewired
改写配置,这样就不用弹出命令了。:point_right: github地址 - 权限路由。思路是根据遍历路由配置表,需要权限的走权限路由,不需要的走原来的路由。具体可看项目中的 router 部分。
- 图标采用
iconfont SVG
处理
具体用法查看官方地址。
遇到的问题:
- (未解决)在dev开发环境下修改scss中的css,不会实时编译更新
- (未解决)IOS下通过
focus
事件不能唤起键盘,安卓下可以 。为了有个较好的用户体验,我在登录,搜索
页面打开时,让输入框自动focus
唤起键盘,经IOS
真机实践,只能触发focus
事件,但是不会唤起键盘,安卓
正常。查阅资料后是IOS
做的限制,(IOS
还有和音频、视频不能自动播放的限制)。需要用户主动点击输入框后,才可以唤起键盘。下一次重新打开就能自动唤起键盘了,很坑的一点:unamused:! 目前无解 - (解决) 从首页列表点击详情时候,返回到首页,会 重新请求加载 ,并且 滚动位置丢失 ,用户体验十分不好。这里为了学习
redux
我用redux
(也可用react
的新context api
)解决,因此在路由方面也用了react-redux-router
,但已不维护,改为connect-react-router
github点这里 。思路是首次获取房源列表,然后存入redux
中,下次打开的时候,从redux
中获取。 - (解决)
热加载
后不能保存redux
中的状态。解决方法:在store
中,添加以下代码, 详细看这里
if (module.hot) { // Reload reducers module.hot.accept('./reducers', () => { store.replaceReducer(connectRouter(history)(rootReducer)); }); } 复制代码
- (解决??) 用了
react-loadble
加载项目中的搜索页面,会有搜索input
的placeholder
显示不全的问题,初次打开会有问题,第二次打开没有问题,如下图。 在dev
环境下不能重现,生产环境
下会有问题。该组件为Ant Design Mobile
的searchBar
。 上图我们可以看到是宽度的问题,正常应该为110px
,而错误的时候则才80px
。 暂时解决方法:移除该路由懒加载,直接加载:smirk:
项目优化:
- 路由懒加载,方案: react-loadable ,添加
loading
提示 - 图片懒加载,方案: lazyload
- 封装成一个组件:point_right: 具体代码
- 这里需要说明在你的网站上加载豆瓣的图片都是
403
的,因此我们需要用到下面这个网站来加载图片点击这里,使用方法https://images.weserv.nl/?url=+图片原来的地址
, 详细参考上一步代码中的链接
-
ajax
视情况添加loading
提示,添加CSS3
动画,使交互更加友好。
三、后端
- 采用
koa2
+koa-router
+mongodb
+jsonWebToken
。最主要的是需要注意 异步和异常处理 的问题。 - 数据库方面用了
Mongoose
来操作。Mongoose
是在node.js异步环境下对mongodb
进行便捷操作的对象模型工具。更多详细说明请看官方文档::point_right:点击这里
3.1 爬取豆瓣小组数据
- 用到的
http
库是axios
。 - 定时任务库,
node-schedule
。github::point_right: 点击这里 - 爬虫库
cheerio
,它的用法十分简单。
const cheerio = require('cheerio') const $ = cheerio.load('<h2 class="title">Hello world</h2>') 复制代码
这里我们就可以通过 $(selector)
,像 jquery
一样的方式取到页面的元素。官方文档::point_right:点击这里
整个爬取的流程:
- 初始化的时候判断是否大于最大存储的数据长度(此项目中设置了数据库最多储存
5000
条数据),如果 超过 ,则执行删除,反之跳过。 - 开启一个定时任务,每天的
0.00am
开始爬取=>
爬取列表页面=>
存入数据库=>
如果 失败 ,不会爬取该条tid - 的详情页, 反之 继续爬取详情页。
- 爬虫提取信息用到了一些正则表达式,提取房租、联系方式、房型、所在地区等等。具体代码::point_right: 点击这里 。其中参考了:point_right:这篇文章中的一些正则表达式。
注意:豆瓣会限制一个时段内Ip的访问次数,因此需要我们做一些调整。
- 列表页面每一页、 详情页每一条数据的爬取的间隔时间保证是不同的。 (定时器+随机数时间) (貌似没什么卵用?)
// sleep function sleep(time = 0) { return new Promise(resolve => { setTimeout(resolve, time); }); } // 更新数据库函数 async updateTopic(tid, resolve, reject) { // 睡眠 await sleep(Math.ceil(Math.random() * 50 * 1000) + 5000); // 开始更新 await this.fetchDetail(tid).then(houseInfo => {...}); } 复制代码
- 改变请求头的
user-agent
。项目中是有个user-agent
列表:point_right: 查看代码 ,每次请求都带上随机中的一个。
3.2 存入数据库
这里我是一次性插入多条数据,用到的 api
如下
db.Houses.insertMany([your array data]) 复制代码
3.3 写接口(路由)
需要注意的是部分路由(需要用户登录后才可以访问的接口) header
中需要传递 token
才能访问,因此添加 路由中间件校验 , 通过校验
后才允许访问。 详细代码查看这里 。关键代码如下:point_down:
const jwt = require('jsonwebtoken'); const token = ctx.header['x-token']; if(token){ 解析token得到用户信息 进入下一个中间件 }else { 返回错误需要传递token } 复制代码
四、数据库mogodb相关
4.1 修改数据库相关结构
开始设计数据库的时候,设置价格字段 prices
是数组,后觉得字符串就可以了。于是在原数据库的基础上修改 数据格式 及 字段名 prices
=> price
- 批量更新某个字段
db.getCollection('houses').find().forEach(function(item){ db.getCollection('houses').update({_id:item._id},{$set:{prices: ''+item.prices}}) }) 复制代码
- 更改字段名
// 如将字段"prices"改为"price" db.getCollection('houses').update({},{$rename:{'prices':'price'}}, false, true) 复制代码
4.2 附上一些api.
- 数据库复制。如复制 douban-house 数据库到 douban-test
// db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>) db.copyDatabase('douban-house', 'douban-test') 复制代码
- 查找数据库中 数组长度大/小于n 的数据
// 大于 exists=1 小于exists=0 db.getCollection('houses').find({'imgs.n':{'$exists':1}}) 复制代码
- 查找数据库中 某个字段不为null 的数据
// $ne=> not equal db.getCollection('houses').find({'contact':{$ne:null}}) 复制代码
- 查找数据库中 多条某个字段 的数据
db.getCollection('houses').find({'tid':{$in:['这里是数组','例如id1','2']}}) 复制代码
另外:插入字段数字 Number Int
类型的数据会存储为 Double
类型,会带有小数点,例如存的是 10
,存进数据库之后会变成 10.0
,可以用 NumberInt
或者 NumberLong
来存储
db.houses.insert({"tid": NumberInt(666)}) 复制代码
4.3 遇到的问题
爬虫爬取贴子的时候,会爬到相同的贴子,而我们是不需要这些重复的。这里的问题是在插入重复值的时候, 出现错误之后不会继续插入剩下的数据 ,这是很坑的一点。 下面是解决方法:
- 先设置
mongodb
的唯一索引值,在设置的时候也遇到不少的坑,查了很多资料,总结相关的api
const housesSchema = new mongoose.Schema({ tid: String, //我这里设置的唯一索引是每条贴子的id号 ...省略 }) housesSchema.index({ tid: 1 }, { unique: true }); 复制代码
- 这里设置好之后,当插入重复的tid时,数据库会返回错误,不插入该条数据。特别需要说的 大坑 是插入的api无论是
insert
还是insertMany
, 他们的api
如下
db.collection.insert( <document or array of documents>, { writeConcern: <document>, ordered: <boolean> } ) 复制代码
这里需要注意的是`ordered`这个参数, 这是一个可选参数,官方解释如下 复制代码
Optional. A boolean specifying whether the mongod instance should perform an ordered or unordered insert. Defaults to true.
大意就是指定mongod实例是否应执行有序插入。默认为```true```。 **重点是:**当有序插入的时候,如果出现了错误,程序会停下当前的插入,不执行插入剩余的数据。只有当无序插入,也就是设置了```ordered: false```,当出现错误之后,才会把剩下的继续插入。官方说明如下: > Excluding Write Concern errors, ordered operations stop after an error, while unordered operations continue to process any remaining write operations in the queue. 官方文档链接::point_right:[点击这里](http://docs.mongodb.com/manual/reference/method/db.collection.insertMany) 复制代码
五、部署相关(跨域处理)
- 开发阶段 可在项目中的
package.json
中添加proxy
字段, 这里假设http://localhost:3003
就是我们的后台服务器,http://localhost:3000
是react开发时候的服务器 如:在项目中访问http://localhost:3000/api/house/125048127
就会代理到http://localhost:3003/api/house/125048127
, 就没有跨域问题了
"proxy": { "/api": { "target": "http://localhost:3003" } } 复制代码
- 线上环境 nginx 配置代理 :point_right:参考这里
location /api/ { proxy_pass http://localhost:3003; } 复制代码
六、git相关
有时候提交了错误的代码又想回退版本,就需要回退远程 git
仓库的代码,再重新提交。 :point_right:更多用法参考这里
git reflog // 查看提交列表, 如我需要撤回到第二条提交记录,也就是红线下的那条 git reset --soft 3a2a12d // 这里的参数--soft表示保留本地修改记录, --hard 代表保存本地的记录,如果是--hard 则会清空本地修改记录,也就是你修改的都没有了!!切记!!! git push -f //强制推送到远程分支 复制代码
以上所述就是小编给大家介绍的《做一个跑通前后端的`豆瓣租房`移动端webApp》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 一款租房 APP,基于 Node.js 爬虫
- 爬取两万多租房数据,告诉你广州房租现状
- 到今年6月 北京市所有公租房都将安装人脸识别系统
- 北京五环实录:合租房里互不相识,凌晨四点互联网大厂上班
- 租房有深坑?手把手教你如何用R速读评论+科学选房
- 编写豆瓣相册下载器(python爬虫)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。