Создайте мобильное веб-приложение Douban Rental, которое работает через переднюю и заднюю часть

MongoDB React.js koa

Введение

недавно узналreact, Я давно хотел сделать проект, но у меня нет хорошей идеи. Поскольку я хочу снять дом, я подумал об этом.租房AppЭта идея, относящаяся к приложению для аренды Douban, положила начало такому простому проекту фронтенда и бэкенда😄.
👉Онлайн-демонстрация нажмите здесь
👉Исходный код проекта нажмите здесь, вы можете скачать и запустить его локально, если вам это поможет, вы можете нажатьstarха 😁

// 你可以使用npm或yarn
yarn install
运行你的数据库 // 必须!!!
yarn server // 运行服务器, 连接的数据库在server目录下的config.js里配置
yarn start // 运行项目

Во-вторых, передняя часть

  1. Стек технологий проектаreact+react-router+react-redux,использоватьcreate-react-appПоколение строительных лесов. Принятие пользовательского интерфейсаAnt Design Mobile👉официальный адрес.
  2. cssСхема css-in-js, с использованиемstyle-jsx👉гитхаб-адрес, вы можете обратиться к статье о Наггетс 👉кликните сюда.
  3. Так как это мобильный терминал, это неизбежно适配проблема, используяvm/vhАдаптация, вы также можете обратиться к нагрочкам для деталей.эта статья.
  4. в сочетании2, 3В два часа, так как я хочу добавить элемент конфигурации, но не хочу добавлять его в проектrun ejectвыскочил, так привыкreact-app-rewiredПереопределите конфиг, чтобы команда не всплывала. 👉гитхаб-адрес
  5. Маршрутизация разрешений. Идея состоит в том, чтобы просмотреть таблицу конфигурации маршрутизации и выбрать авторитетный маршрут, если вам нужно разрешение, и выбрать исходный маршрут, если он вам не нужен. Подробности смотрите в проектеrouterчасть.
  6. Значок принимаетiconfont SVGиметь дело с
    iconfont
    Просмотр конкретного использованияофициальный адрес.

Возникшие проблемы:

  • (Не решено) Изменение CSS в scss в среде разработки dev не будет компилироваться и обновляться в режиме реального времени.
  • (Нерешено) Пройдено под IOSfocusСобытие не может вызвать клавиатуру, оно может быть под Android. Чтобы улучшить пользовательский опыт, я登录,搜索Когда страница откроется, пусть поле ввода автоматическиfocusразбудить клавиатуру,IOSНастоящая машинная практика может вызвать толькоfocusсобытие, но не поднимает клавиатуру,安卓обычный. После проверки информацииIOSделать ограничения(IOSТакже есть ограничения, что аудио и видео не могут воспроизводиться автоматически). Клавиатура может быть вызвана только после того, как пользователь активно щелкнет поле ввода. При следующем включении клавиатура автоматически проснется, что немного жалко😒!Пока нет решения🙄
  • (решить)Когда вы нажмете детали из списка домашней страницы, вернетесь на домашнюю страницу, вы будетеповторно запросить загрузку,а такжепозиция прокрутки потеряна, пользовательский опыт очень плохой. здесь для обученияreduxя используюredux(так же доступноreactновыйcontext api) решается, поэтому он также используется в маршрутизацииreact-redux-router, но больше не поддерживается, изменен наconnect-react-routerгитхаб нажмите здесь. Идея состоит в том, чтобы получить список в первый раз, а затем сохранить его в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.
    search_placeholder
    search_placeholder
    На картинке выше мы видим, что это проблема ширины, которая обычно должна быть110px, и только тогда, когда это неправильно80px.Временное решение: убрать ленивую загрузку маршрута и загрузить его напрямую 😏

Оптимизация проекта:

  1. Маршрут ленивой загрузки, схема:react-loadable,Добавить кloadingнамекать
  2. Ленивая загрузка изображения, схема:lazyload
    • Упаковано в компонент 👉специальный код
    • Здесь необходимо пояснить, что все изображения, загруженные на Douban на вашем веб-сайте,403, поэтому нам нужно использовать следующий веб-сайт для загрузки изображенийкликните сюда,Инструкцииhttps://images.weserv.nl/?url=+图片原来的地址, обратитесь к ссылке в предыдущем коде для получения подробной информации
  3. ajaxПо делу можно добавитьloadingподскажите, добавьтеCSS3Анимации, чтобы сделать взаимодействие более дружелюбным.

3. Бэкенд

  • использоватьkoa2+koa-router+mongodb+jsonWebToken. Главное - обратить вниманиеАсинхронная обработка и обработка исключенийЭта проблема.
  • используемая база данныхMongooseработать.Mongooseнаходится в асинхронной среде node.jsmongodbИнструменты объектной модели для удобного манипулирования. Более подробные инструкции можно найти в официальной документации: 👉кликните сюда

3.1 Сканирование данных группы Douban

  • использовалhttpбиблиотекаaxios.
  • библиотека запланированных задач,node-schedule. гитхаб: 👉кликните сюда
  • Библиотека рептилийcheerio, его использование очень просто.
const cheerio = require('cheerio')
const $ = cheerio.load('<h2 class="title">Hello world</h2>')

Здесь мы можем пройти$(selector),картинаjqueryТаким же образом можно получить элементы страницы. Официальная документация: 👉кликните сюда

Весь процесс сканирования:

  • При инициализации определите, превышает ли она максимальную длину хранимых данных (в этом проекте база данных настроена на хранение до5000данные), еслиПревосходить, удалите его, иначе пропустите.
  • Запускать запланированное задание каждый день0.00amначать ползать=>Страница со списком сканирования=>сохранить в базу данных=>еслипотерпеть неудачу, не будет ползать по течению
  • страница сведений о ,НапротивПродолжайте сканировать страницу сведений.
  • Сканер использует некоторые регулярные выражения для извлечения информации, извлечения арендной платы, контактной информации, типа комнаты, местоположения и т. д. Конкретный код: 👉кликните сюда. Что относится к 👉эта статьянекоторые регулярные выражения в .

Примечание. Douban ограничивает количество посещений 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список 👉Посмотреть код, каждый запрос приносит случайный.

3.2 Хранить в базе данных

Здесь я вставляю несколько фрагментов данных одновременно, используяapiследующим образом

db.Houses.insertMany([your array data])

3.3 Интерфейс записи (маршрутизация)

Следует отметить, что некоторые маршруты (интерфейсы, доступ к которым возможен только после входа пользователя в систему)headerнужно пройти вtokenдоступ, поэтому добавьтеПроверка промежуточного программного обеспечения маршрутизации,通过校验После этого доступ разрешается.Ознакомьтесь с подробным кодом здесь. Код ключа следующий👇

const jwt = require('jsonwebtoken');
const token = ctx.header['x-token'];
if(token){
	解析token得到用户信息
	进入下一个中间件
}else {
	返回错误需要传递token
}

В-четвертых, база данных mogodb, связанная с

4.1 Изменить структуру, связанную с базой данных

Приступая к оформлению базы данных, задайте поле ценыpricesЭто массив, и тогда я чувствую, что можно использовать строку. Итак, на основе исходной базы измененыФормат данныха такжеимя поляprices=>price

  1. Пакетное обновление поля
db.getCollection('houses').find().forEach(function(item){
    db.getCollection('houses').update({_id:item._id},{$set:{prices: ''+item.prices}})
 })
  1. изменить имя поля
// 如将字段"prices"改为"price"
db.getCollection('houses').update({},{$rename:{'prices':'price'}}, false, true)

4.2 Прикрепите немного API.

  1. Репликация базы данных. например, копированиеdouban-houseбазу данных вdouban-test
// db.copyDatabase(<from_dbname>, <to_dbname>, <from_hostname>)
 db.copyDatabase('douban-house', 'douban-test')
  1. Найти в базеДлина массива больше/меньше nДанные
// 大于 exists=1 小于exists=0
db.getCollection('houses').find({'imgs.n':{'$exists':1}})
  1. Найти в базеполе не пустоеДанные
// $ne=> not equal
db.getCollection('houses').find({'contact':{$ne:null}})
  1. Найти в базенесколько полейДанные
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.

官方文档链接:👉[点击这里](http://docs.mongodb.com/manual/reference/method/db.collection.insertMany)

Пять, связанные с развертыванием (междоменная обработка)

  • стадия развитияесть в проектеpackage.jsonдобавлено вproxyполе, здесь предполагаетсяhttp://localhost:3003наш внутренний сервер,http://localhost:3000Это сервер, на котором разрабатывается реакция Такие как: доступ в проектhttp://localhost:3000/api/house/125048127будет представленhttp://localhost:3003/api/house/125048127, междоменной проблемы нет
  "proxy": {
    "/api": {
      "target": "http://localhost:3003"
    }
  }
location  /api/ {
   proxy_pass   http://localhost:3003;
}

Шесть, связанные с git

Иногда, если вы отправляете неправильный код и хотите откатить версию, вам нужно откатить удаленныйgitКод репозитория, а затем повторите отправку. 👉Подробнее об использовании см. здесь

git_reflog

git reflog // 查看提交列表, 如我需要撤回到第二条提交记录,也就是红线下的那条
git reset --soft 3a2a12d // 这里的参数--soft表示保留本地修改记录, --hard 代表保存本地的记录,如果是--hard 则会清空本地修改记录,也就是你修改的都没有了!!切记!!!
git push -f //强制推送到远程分支