内容简介:最近学了: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-routergithub点这里 。思路是首次获取房源列表,然后存入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的唯一索引值,在设置的时候也遇到不少的坑,查了很多资料,总结相关的apiconst 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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learning Vue.js 2
Olga Filipova / Packt Publishing / 2017-1-5 / USD 41.99
About This Book Learn how to propagate DOM changes across the website without writing extensive jQuery callbacks code.Learn how to achieve reactivity and easily compose views with Vue.js and unders......一起来看看 《Learning Vue.js 2》 这本书的介绍吧!