Учебник по созданию структуры статьи, реагирующей на вашу прокрутку, с помощью react-scrollspy

Посещали ли вы некоторые сайты с документацией и учебными пособиями, которые позволяют вам видеть, какой раздел вы читаете сбоку? Если вы хотите улучшить читабельность своего веб-сайта Gatsby. В этой статье я поделюсь своим процессом создания интерактивного компонента таблицы содержимого, который может реагировать на вашу прокрутку.

Давайте посмотрим на требование: 1. Читатель сможет легко перемещаться по разделам контента 2. Читатель сможет узнать свой прогресс чтения

Мы будем использовать пакет с именем react-scrollspy, чтобы определить, находятся ли заголовки в области просмотра, что в ответ вызовет активное имя класса.

Включив компонент «Таблица содержания», пользователи смогут легко перемещаться по вашей статье, находя интересующий их контент. Давайте начнем и перейдем к шагу 2, если у вас уже есть сайт Gatsby.

1. Создайте сайт Гэтсби

Сначала мы установим простой стартер MDX.

gatsby new gatsby-tutorial-table-of-content https://github.com/hagnerd/gatsby-starter-blog-mdx

Используйте yarn или npm install для инициализации репозитория.

2. Установите react-scrollspy и gatsby-remark-autolink-headers.

Взглянув на react-scrollspy, нам нужно будет предоставить заголовки для каждой страницы компоненту, который, к счастью, генерируется автоматически по умолчанию в каждом почтовом узле. Нам также нужно будет указать имя класса для активации, когда он находится в поле зрения.

yarn add react-scrollspy gatsby-remark-autolink-headers

В gatsby-config.js вам нужно будет добавить gatsby-remark-autolink-headers в gatsbyRemarkPlugins.

3. Обновить пост-запрос GraphQL

Включите tableOfContents в запрос GraphQL шаблона сообщения в блоге, в моем случае это blog-post.js в папке шаблонов. После этого, если вы используете GraphiQL, вы сможете увидеть оглавление в виде объекта. Мы вызовем все значения url в объекте и вернемся в виде массива.

4. Передача Post Props в Toc компонент

Создайте новый файл с именем Toc.js в папке Components. Мы будем добавлять функции шаг за шагом, чтобы изолировать проблемы, которые могут возникнуть. Добавляя очень простой компонент, мы должны убедиться, что все реквизиты будут переданы в первую очередь.
import React from ‘react’

export default function Toc(props) {
 const { post } = props
 console.log(post)
return <h3>Table of Content</h3>
}

Сохраните файл и вернитесь к blog-post.js и импортируйте компонент Toc.

import Toc from '../components/toc'

Затем я добавлю Toc непосредственно перед MDXRenderer.

<Toc post={post.tableOfContents} />
<MDXRenderer>{post.body}</MDXRenderer>

На данный момент будет отображаться только заголовок Table of Contents h3. Но в консоли, когда мы зарегистрировали post props. Мы также можем проверить, возвращаются ли объекты tableOfContents.

5. Сопоставление таблицы реквизитов контента

Для более простой демонстрации мы будем перечислять только все заголовки первого уровня в таблице содержания. Давайте обновим toc.js, сопоставив значение реквизита. Таким образом, мы сможем получить доступ ко всей информации о заголовках и ссылкам из tableofContents из GraphQL.

return (
 <nav>
  {post.items.map(p => (
   <li key={p.url}>
    <a href={p.url}>{p.title}</a>
   </li>
  ))}
</nav>
  )

Поскольку мы установили gatsby-remark-autolink-headers для автоматического добавления якоря для каждого заголовка. Щелчок по оглавлению немедленно перенаправит к заголовку.

6. Стилизация компонента «Таблица содержимого» сбоку

Теперь, когда основная функциональность завершена, давайте позаботимся о стиле, сначала покажем, что мы можем проще протестировать прокрутку. Здесь я буду использовать простейшую реализацию с использованием CSS. Но любая реализация стиля должна работать нормально.

Давайте создадим Toc.css в той же папке и импортируем его в компонент.

import './Toc.css'

Мы зафиксируем оглавление в правой части окна, чтобы пользователи могли легко перемещаться независимо от того, в какой части страницы они находятся. Кроме того, поскольку мы не хотим изменять обычный стиль списка. Мы укажем имя класса .toc-list, которое будет добавлено на следующем шаге.

Мы также добавим класс is-current, чтобы Scrollspy мог добавить имя класса, когда заголовок находится в поле зрения.

nav {
  position: fixed;
  top: 50vh;
  right: 5vw;
  margin-left: 36px;
  max-width: 250px;
}
ul.toc-list {
  border-left: 1px solid #363636;
}
ul.toc-list > li {
  list-style-type: none;
  margin-left: 24px;
  font-size: 13px;
}
ul.toc-list > li > a {
  color: #c2c2c2;
  text-decoration: none;
  border-bottom: 0;
  transition: 1s all ease-in-out;
}
ul.toc-list > li.is-current > a {
  color: black;
}

7. Внедрите React Scrollspy

И последнее, но не менее важное: нам нужно будет определить, находится ли заголовок в поле зрения. react-scrollspy поможет нам определить, находится ли якорь в поле зрения после того, как мы пройдем через 2 объекта.

  1. Список якорных URL-ссылок в виде массива
  2. Имя класса, когда виден заголовок

На расследование ушло некоторое время, но поскольку Гэтсби уже tableofContentsудобно добавил якорь, нам действительно нужно удалить # из предоставленного объекта. Вот простая функция для вызова значения url в объекте и удаления первого символа.

let url = post.items.map(function(post) {
return post['url'].substring(1)
})

После этого давайте импортируем Scrollspy сразу после nav и передаем url и добавляем текущее имя класса:

<Scrollspy items={url} currentClassName="is-current" className="toc-list">
{post.items.map(p => (
<li key={p.url}>
<a href={p.url}>{p.title}</a>
</li>
))}
</Scrollspy>

Окончательный файл для Toc.js должен выглядеть так

import React from 'react'
import Scrollspy from 'react-scrollspy'
import './Toc.css'
export default function Toc(props) {
const { post } = props
let url = post.items.map(function(post) {
return post['url'].substring(1)
})
return (
<nav>
<Scrollspy items={url} currentClassName="is-current" className="toc-list">
{post.items.map(p => (
<li key={p.url}>
<a href={p.url}>{p.title}</a>
</li>
))}
</Scrollspy>
</nav>
)
}

Вот и все. Я создал минимальное репо, используя Gatsby Starter Blog MDX. Не стесняйтесь ссылаться на него и поднимать любые вопросы на Github. Вы также можете просмотреть демо здесь.

Вот некоторые из ошибок и вопросов, с которыми я столкнулся при разработке компонента Table of Contents с помощью Gatsby.

Как сделать условный рендеринг, когда вообще нет заголовков?

В настоящее время, если у вас есть сообщение в блоге без заголовка. Вы столкнетесь с ошибкой. Нам нужно будет добавить условный рендеринг в оглавление только тогда, когда он будет доступен в шаблоне поста.

/*blog-post.js*/
{!!post.tableOfContents.items && <Toc post={post.tableOfContents} />}

Как отладить все ошибки с помощью Gatsby Build?

Если у вас много постов в блоге, вы не сможете протестировать всех самостоятельно. Если вы использовали gatsby develop для тестирования компонента Table of Contents. Я настоятельно рекомендую вам использовать gatsby build для проверки всех сообщений в блоге перед фиксацией. Убедитесь, что в сообщении блога нет ошибок. Мне удалось найти запись в блоге без каких-либо заголовков и одну запись в блоге с неправильной иерархией заголовков (h3 перед h2), что привело к ошибке сборки.

Плагин в gatsby-remark-autolink-headersдобавляет значок перед каждым заголовком, который он обрабатывает. Согласно документации, make icon: false в параметрах плагина удалит значки перед якорными заголовками.

/*gatsby-config.js*/
{
resolve: `gatsby-remark-autolink-headers`,
options: {
icon: false,
},
},

Как сделать прокрутку плавной?

Установите smooth-scroll, добавьте следующий код в Layout.js или в любое другое место, которое будет загружаться на каждой странице.

if (typeof window !== 'undefined') {
// eslint-disable-next-line global-require
require('smooth-scroll')('a[href*="#"]')
}

Что дальше?

Есть еще некоторые проблемы с существующими решениями. Например, react-scrollspy распознает только заголовок, а не заголовок + следующие абзацы. Столь длинная статья может столкнуться с такой проблемой (Заголовок 1 в поле зрения -> Вне поля зрения -> Заголовок 2 в поле зрения).

Кроме того, в настоящее время отображается только заголовок первого уровня. Добавление цикла также станет следующим шагом в улучшении оглавления.

И последнее, но не менее важное: стоит поработать над отображением на мобильных устройствах, в настоящее время оглавление не будет отображаться на мобильных устройствах, поскольку большинство моих читателей приходят с настольных компьютеров. Но реализация плавающей кнопки с всплывающим меню также была бы возможным решением.

Первоначально опубликовано на https://desktopofsamuel.com.