В процессе изучения React я реализовал личный блог, без сложной реализации и эксплуатации, пригодный для входа ~
Оригинальный адрес:GitHub.com/Axue Temple/Hot Ah…
На самом деле функция этого проекта очень проста, то есть общая домашняя страница, блог, демо, обо мне и другие функции.
Все стили страницы написаны мной, в черно-белом стиле, что может быть немного некрасиво. Но все же CSS самого низкого уровня, готовый к рефакторингу ~
Если есть лучший способ или если мои идеи предвзяты, пожалуйста, сообщите и поправьте меня.
Добро пожаловать в гости:axuebin.com/react-blog
Гитхаб:GitHub.com/Axue Temple/Hot Ah…
предварительный просмотр
титульная страница
страница блога
Страница содержания статьи
Демонстрационная страница
ключевая технология
- ES6: В проекте используется синтаксис ES6, попробуйте использовать его в процессе написания, могут быть места, которых я не ожидал
- React
- React-Router: внешняя маршрутизация
- React-Redux: управление состоянием
- вебпак: упаковка
- Отмечено: рендеринг отметки
- highlight.js: выделение кода
- выборка: асинхронный запрос данных
- eslint: проверка кода
- antd: Некоторым компонентам лень писать свои собственные. .
Готов к работе
Поскольку это не проект, сгенерированный с использованием скаффолдинга React, все настраивается вручную само по себе. . .
сборщик модулей
упаковано сwebpack 2.6.1
, готовы войти в ямуwebpack 3
.
Официальная документация:webpack.js.org/
Китайский документ:doc.webpack-china.org/
дляwebpack
Конфигурация не слишком знакома, просто простая конфигурация для запуска проекта:
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: __dirname + '/src',
entry: "./js/index.js",
module: {
loaders: [
{
test: /\.js?$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}, {
test: /\.css$/,
loader: 'style-loader!css-loader'
}, {
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'eslint-loader'
}, {
test: /\.json$/,
loader: 'json-loader'
}
]
},
output: {
path: __dirname + "/src/",
filename: "bundle.js"
}
}
webpack
Есть несколько важных свойств:entry
,module
,output
,plugins
, плагином еще не пользовался, так что настройки нетplugins
.
module
серединаloaders
:
- babel-loader: преобразовать код в код es5
- css-loader: обрабатывать такие проблемы, как ссылки на пути в css
- style-loader: динамически записывать стили в css
- eslin-loader: используйте eslint
управление пакетами
Управление пакетами все еще используетсяNPM
.
Официальная документация:docs.npmjs.com/
- npm init
- npm install
- npm uninstall
оnpm
, возможно, также необходимо знатьdependencies
а такжеdevDependencies
Разница, я просто понимаю это так:
- зависимости: модули, которые необходимо использовать после запуска проекта.
- devDependencies: модули, необходимые для разработки, но не нужные после запуска проекта.
проверка кода
В проекте используется более популярныйESLint
в качестве инструмента проверки кода и использоватьAirbnb
правила осмотра.
ESLint:GitHub.com/ESL int/Злые силы…
eslint-config-airbnb:Ууууу, эта лошадь плюс .com/package/evil force…
существуетpackage.json
Его можно увидеть вESLint
Пакет помещается вdevDependencies
Нижний, потому что он используется только во время разработки.
использовать
- существует
webpack
загрузить в конфигурацииeslint-loader
:
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'eslint-loader'
}
]
}
- Создайте
.elintrc
документ:
{
"extends": "airbnb",
"env":{
"browser": true
},
"rules":{}
}
затем работаетwebpack
, он выполнит проверку кода, просматривая кучуwarning
,error
Разве это не круто~
Вот общие правила ESLint:eslint.cn/docs/rules/
источник данных
Потому что это для практикиReact
, на данный момент рассмотрите возможность создания только статической страницы, и теперь все больше и больше крупных коров любят использоватьGithub Issues
Чтобы вести блог, он также может предоставить лучшую функцию комментариев, поэтому я тоже хочу попробовать.Github Issues
в качестве источника данных для блога.
API здесь:developer.github.com/v3/issues/
Я не читал все API, я просто посмотрел, как получитьIssues
список. .
https://api.github.com/repos/axuebin/react-blog/issues?creator=axuebin&labels=blog
Через параметры управленияcreator
а такжеlabels
, который можно отфильтровать как отображениеIssues
. он вернетissue
Массив объектов формата. Каждыйissue
Есть много свойств, нам может не понадобиться так много, сначала поймите следующее:
// 为了方便,我把注释写在json中了。。
[{
"url": , // issue 的 url
"id": , // issue id , 是一个随机生成的不重复的数字串
"number": , // issue number , 根据创建 issue 的顺序从1开始累加
"title": , // issue 的标题
"labels": [], // issue 的所有 label,它是一个数组
"created_at": , // 创建 issue 的时间
"updated_at": , // 最后修改 issue 的时间
"body": , // issue 的内容
}]
Запрашивать данные асинхронно
Когда метод асинхронного запроса данных, используемый в проектеfetch
.
оfetch
:сегмент fault.com/ah/119000000…
Это просто в использовании:
fetch(url).then(response => response.json())
.then(json => console.log(json))
.catch(e => console.log(e));
рендеринг уценки
существуетGithub
Узнайте, какReact
выполнитьmarkdown
, нашел эти две библиотеки:
- реакция-уценка:GitHub.com/Hot-Blood Ares/Горячие…
- отмечено:github.com/chjj/marked
Он очень прост в использовании.
еслиreact-markdown
, просто сделайте это:
import ReactMarkdown from 'react-markdown';
const input = '# This is a header\n\nAnd this is a paragraph';
ReactDOM.render(
<ReactMarkdown source={input} />,
document.getElementById('container')
);
еслиmarked
,Сюда:
import marked from 'marked';
const input = '# This is a header\n\nAnd this is a paragraph';
const output = marked(input);
Здесь немного по-другому, мы получаем строкуoutput
, обратите внимание, это строка, поэтому мы должны вставить ее вdom
в, вReact
Мы можем это сделать:
<div dangerouslySetInnerHTML={{ __html: output }} />
Так как наш проект основан наReact
, поэтому я подумал об использованииreact-markdown
было бы лучше, и из соображений безопасностиReact
не выступает за прямоеdom
Вставьте в него строку, но в процессе использования обнаруживается, чтоreact-markdown
Поддержка таблиц не является дружественной, поэтому я должен отказаться от нее и использовать вместо нееmarked
.
подсветка кода
Подсветка кода используетhighlight.js
:GitHub.com/ISA gala EV/ также…
это иmarked
Может быть легко подключен ~
Просто сделайте это:
import hljs from 'highlight.js';
marked.setOptions({
highlight: code => hljs.highlightAuto(code).value,
});
highlight.js
Он поддерживает различные стили сопоставления цветов кода, которые можно найти вcss
переключиться в файле:
@import '~highlight.js/styles/atom-one-dark.css';
Здесь вы можете увидеть стили выделения и подбора цветов для каждого языка:highlightjs.org/
React
что такое состояние и реквизит
Смотрите предыдущую статью:GitHub.com/Axue Temple/Hot Ah…
Жизненный цикл React Components
Смотрите предыдущую статью:GitHub.com/Axue Temple/Hot Ah…
Внешняя маршрутизация
Интерфейсная маршрутизация в проектеReact-Router V4
.
Официальная документация:реагировать-обучение.com/реагировать-маршрут…
Китайский документ:reacttraining.cn/
основное использование
<Link to="/blog">Blog</Link>
<Router>
<Route exact path="/" component={Home} />
<Route path="/blog" component={Blog} />
<Route path="/demo" component={Demo} />
</Router>
Примечание: должен находиться в корневом каталогеRoute
заявление вexact
, иначе вы не сможете перейти по любой ссылке.
Переход в каталог уровня 2
Например, если я хочу сейчас щелкнуть по странице блога,url
даlocalhost:8080/blog
, должен статьlocalhost:8080/blog/article
, что можно сделать так:
<Route path={`${this.props.match.url}/article/:number`} component={Article} />
Это перейдет кlocalhost:8080/blog/article
, а также прошелnumber
параметр, вarticle
сквозьthis.props.params.number
Получать.
HashRouter
Когда я размещаю проект наGithub Page
Потом возникла такая проблема.
Обновите страницу, чтобы появилось
Cannot GET /
Подскажите, роутинг не действует.
Понимая, я знаю, что причина в этом, и ее можно решить:
- Поскольку после обновления запрос будет отправлен на сервер на основе URL-адреса вместо обработки маршрута, что приведет к
Cannot GET /
ошибка. - путем изменения
<Router>
→<HashRouter>
. -
<HashRouter>
Маршрутизация достигается с помощью хэша в URL-адресе. Цель переключения страниц может быть достигнута без полноэкранного обновления.
После перехода по маршруту он не будет автоматически возвращаться наверх
После того, как текущая страница будет прокручена до определенной области, после нажатия кнопки «Перейти» страница хоть и перепрыгнет, но останется в области прокрутки и не вернется автоматически к началу страницы.
Это можно решить, выполнив следующие действия:
componentDidMount() {
this.node.scrollIntoView();
}
render() {
return (
<div ref={node => this.node = node} ></div>
);
}
государственное управление
В проекте необходимо использоватьGithub Issues
Запрошенные данные, поскольку они были известны ранееRedux
Хотя наличие этой штуки немного избыточно, чтобы изучить или использовать ее для управления статусом проекта, достаточно один раз запросить данные.
Официальная документация:redux.js.org/
Китайский документ:cn.redux.js.org/
Проще говоря, каждый раз, когда состояние изменяется, его нужно запускать.action
, Однако на самом деле измененные данные 2333 я еще не использовал в проекте. . .
Что касается управления состоянием, так как я мало в этом разбираюсь, я не пойму детей неправильно~
основные компоненты
React строится на основе компонентов, поэтому в начале построения страницы мы должны сначала подумать, какие компоненты нам нужны, какова взаимосвязь между этими компонентами, какие компоненты можно использовать повторно и так далее.
титульная страница
Как видите, я в основном разделил домашнюю страницу на четыре части:
- заголовок: заголовок сайта, подзаголовок, панель навигации
- баннер: обо мне ~, собираюсь поменять фон на свое фото, но подходящего фото пока нет
- область карт: пока три карты
- карточка блога: последние сообщения в блоге
- демо-карта: несколько небольших демо-категорий
- мне карта: это место, где я позволяю себе идти
- нижний колонтитул: информация об авторских правах, информация о регистрации, просмотры страниц
страница блога
Страница блога — очень стандартная страница, это часть с наибольшим объемом кода во всем проекте, включая следующие части:
- Компонент списка статей
- Компонент перелистывания страниц
- Компонент кнопки архивации
- Компонент категории
- Компонент этикетки
Список статей
Список статей на самом делеlist
, есть по одномуitem
:
<div class="archive-list">
<div class="blog-article-item">文章1</div>
<div class="blog-article-item">文章2</div>
<div>
для каждогоitem
, что на самом деле так:
Компонент элемента статьи может включать:
- название статьи
- Время, категория, тег и т. д., когда статья была опубликована.
- Резюме статьи
- ...
Если вы используетеDOM
Чтобы описать это, это должно выглядеть так:
<div class="blog-article-item">
<div class="blog-article-item-title">文章标题</div>
<div class="blog-article-item-time">时间</div>
<div class="blog-article-item-label">类别</div>
<div class="blog-article-item-label">标签</div>
<div class="blog-article-item-desc">摘要</div>
</div>
Итак, у нас может быть много компонентов:
- Компонент списка статей
<ArticleList />
- Компонент элемента статьи
<ArticleItem />
- Компонент метки категории
<ArticleLabel />
Это могут быть такие отношения:
<ArticleList>
<ArticleItem>
<ArticleTitle />
<ArticleTime />
<ArticleLabel />
<ArticleDesc />
</ArticleItem>
<ArticleItem></ArticleItem>
<ArticleItem></ArticleItem>
</ArticleList>
нумерация страниц
Для функции пейджинга традиционный метод реализации состоит в том, чтобы завершить пейджинг на бэкенде, а затем вернуть его во внешний интерфейс в пакетах.Например, может быть возвращена часть данных, подобная этой:
{
total:500,
page:1,
data:[]
}
То есть бэкэнд вернет данные разделенных страниц, включая общий объем данных.total
, текущее количество страницpage
, а данные, принадлежащие страницеdata
.
Однако моя страница — это просто статическая страница, и данные извлекаются через API на Github Issues. (Похоже, что разбиение по страницам Github Issues не может настроить число...), поэтому нет способа напрямую вернуть разделенные данные, поэтому вы можете принудительно разбивать страницы только на внешнем интерфейсе ~
Мне лень пользоваться функцией пейджинга... Используюantd
компонент перелистывания страниц<Pagination />
.
Официальная документация:Anta.design/components/…
Документация понятна и очень проста в использовании.
Логика внешнего рендеринга (немного глуповатая): хранить данные в массиве, вычислять значение индекса отображения в соответствии с текущим количеством страниц и количеством баров, отображаемых на каждой странице, и извлекать соответствующие данные.
В компоненте перелистывания страниц:
constructor() {
super();
this.onChangePage = this.onChangePage.bind(this);
}
onChangePage(pageNumber) {
this.props.handlePageChange(pageNumber);
}
render() {
return (
<div className="blog-article-paging">
<Pagination onChange={this.onChangePage} defaultPageSize={this.props.defaultPageSize} total={this.props.total} />
</div>
);
}
Когда количество страниц изменится, это вызовет передачу из родительского компонента.<ArticlePaging />
МетодыhandlePageChange
, тем самым передавая количество страниц в родительский компонент, который затем передается в<ArticleList />
середина.
В родительском компоненте:
handlePageChange(pageNumber) {
this.setState({ currentPage: pageNumber });
}
render() {
return (
<div className="archive-list-area">
<ArticleList issues={this.props.issues} defaultPageSize={this.state.defaultPageSize} pageNumber={this.state.currentPage} />
<ArticlePaging handlePageChange={this.handlePageChange} total={this.props.issues.length} defaultPageSize={this.state.defaultPageSize} />
</div>
);
}
Список:
render() {
const articlelist = [];
const issues = this.props.issues;
const currentPage = this.props.pageNumber;
const defaultPageSize = this.props.defaultPageSize;
const start = currentPage === 1 ? 0 : (currentPage - 1) * defaultPageSize;
const end = start + defaultPageSize < issues.length ? start + defaultPageSize : issues.length;
for (let i = start; i < end; i += 1) {
const item = issues[i];
articlelist.push(<ArticleItem />);
}
}
label
существуетGithub Issues
, может бытьissue
добавить многоlabel
, я использую их как полезные для контента блогаlabel
Он разделен на три категории, которые представлены разными цветами.
Объясните здесь,label
После создания случайныйid
,хотяid
Не повторяется, но рубрики и теги статьи будут увеличиваться при добавлении новойlabel
, программа может также нуждаться в соответствующей модификации, в качестве различияlabel
Стандарт может быть неподходящим, поэтому я использую цвет, чтобы различать их.
- Блог с указанием, что это статья: только если есть
blog
изissue
для отображения на странице, фильтрbug
,help
Ждать - Указывает категорию статьи: используется для обозначения категории статьи, например, «внешний интерфейс», «фотография» и т. д.
- Для тегов статей: теги, используемые для обозначения статей, такие как «JavaScript», «React» и т. д.
даже с новымlabel
, если он классифицируется в соответствии с цветом, к какой категории он принадлежит.
категория
Основная идея здесь такова: пройти всеissues
, затем перебирает каждыйissue
изlabels
, Найтиlabel
, то посчитай.
const categoryList = [];
const categoryHash = {};
for (let i = 0; i < issues.length; i += 1) {
const labels = issues[i].labels;
for (let j = 0; j < labels.length; j += 1) {
if (labels[j].color === COLOR_LABEL_CATEGORY) {
const category = labels[j].name;
if (categoryHash[category] === undefined) {
categoryHash[category] = true;
const categoryTemp = { category, sum: 1 };
categoryList.push(categoryTemp);
} else {
for (let k = 0; k < categoryList.length; k += 1) {
if (categoryList[k].category === category) {
categoryList[k].sum += 1;
}
}
}
}
}
}
Для этого требуется три цикла. Сложность немного высока, и это кажется немного глупым. Его нужно улучшить. Если есть лучший метод, пожалуйста, дайте мне больше советов ~
Этикетка
Идея здесь в основном такая же, как и идея категории, но отображается по-другому.
Изначально я хотел использовать размер шрифта, чтобы отразить вес каждого тега. Позже я подумал, что, может быть, для меня только эти теги будут очень частыми на данный момент, а других тегов может быть очень мало. различать по размеру шрифта или изменить способ сортировки.
Страница статьи
Страница статьи в основном разделена на две части:
- Область содержания статьи: отображение содержимого статьи, отображаемое в основной области страницы
- Содержание главы: оглавление главы статьи, отображаемое в правой части статьи.
Содержание статьи
Есть два способа получить конкретное содержание статьи:
- Перебрать массив, чтобы найти желаемое содержимое статьи из массива, который был запрошен ранее.
- пройти через
issue number
Повторно отправьте запрос, чтобы получить контент напрямую
Наконец я выбрал последний.
артикль используетсяmarkdown
Он написан грамматически, поэтому его нужно преобразовать вhtml
Затем вставьте его на страницу, здесь мы используемReact
Устаревшие атрибуты:dangerouslySetInnerHTML
.
За исключением рендерингаmarkdown
Пришлось код статьи подсвечивать, есть пользовательские стили статей разными метками.
Содержание главы
Во-первых, вотissue
, я надеюсь, что вы можете дать некоторые предложения ~
Содержание статьи черезmarkdown
Вставить после рендерингаdom
в, потому чтоReact
Не рекомендуетсяdocument.getElementById
Приобретениеdom
элемент, поэтому мы можем найти способ получить заголовок каждой главы статьи только путем сопоставления строк.
Поскольку я не очень хорошо знаком с регулярными выражениями, я однажды проконсультировался на sf и принял один из ответов:
const issues = content;
const menu = [];
const patt = /(#+)\s+?(.+)/g;
let result = null;
while ((result = patt.exec(issues))) {
menu.push({ level: result[1].length, title: result[2] });
}
Это получит все#
строка, то естьmarkdown
название в ,result[1].length
означает, сколько#
, на самом деле это означает несколько уровней заголовков,title
Это просто название.
Здесь есть еще одна проблема, которая изначально была пропущена через<a target="" />
Способ добиться перехода по щелчку, но теперь визуализируетсяhtml
Для каждого заголовка нет уникального идентификатора. . .
Архивная страница
Архив по годам:
Архив по категориям:
Архив по тегу:
вопрос
Основные функции в основном реализованы, и остаются следующие проблемы, которые можно рассматривать как однуTodoList
Бар
- Функция комментариев. предназначен для использования
Github Issues API
Реализовать комментарии, должны реализоватьGithub
Авторизованный вход - вернуться наверх. предназначен для использования
antd
компоненты, ноstate
серединаvisibility
всегдаfalse
- Рендеринг главной страницы. Теперь упакованный файл js все еще слишком велик, что делает рендеринг домашней страницы слишком медленным.Это основная цель следующей работы, и я узнал об оптимизации в этом отношении:
-
webpack
Нагрузка по требованию. Это, вероятно, самый удобный способ на данный момент - Рендеринг на стороне сервера. Это хлопотно, но есть много преимуществ, не только для решения проблемы рендеринга, но и для SEO, так что это также
todo
один
-
- Код запутан, а логика неверна. Это моя собственная проблема, и мне нужно снова попрактиковаться.
Оригинальный адрес:GitHub.com/Axue Temple/Hot Ah…