Как создать отзывчивые компоненты React с помощью React Textfit?

React Изучение

Разработка в React включает определение повторно используемых компонентов и их сборку в различные части вашего приложения для достижения желаемого пользовательского интерфейса (UI). В этой статье мы рассмотрим react-textfitбиблиотеку, которая упрощает создание отзывчивых компонентов React, которые предсказуемо отображаются в любом месте макета.

Проблема подгонки текста

Поскольку компоненты React представляют собой фрагменты кода JavaScript, описывающие определенный раздел вашего пользовательского интерфейса, они практически не зависят друг от друга. И их визуальные стили часто встроены в них, как часть их определения. Это может быть весьма полезно, учитывая, что они, вероятно, будут использоваться в разных местах и ​​в разных местах.

Но есть и недостатки встраивания стилей в повторно используемый компонент. Один пример можно увидеть в случае отзывчивости. Допустим, вы хотите, чтобы строка текста — например, заголовок — полностью заполняла зарезервированное для нее пространство по высоте и ширине, но не оборачивалась — и все это без необходимости писать собственные правила CSS для каждой возможной ситуации. (Примеры того, где вы можете захотеть, это бизнес-слоганы, рекламные сообщения или текст, встроенный в компоненты навигационной панели.)

Но есть и недостатки встраивания стилей в повторно используемый компонент

CSS и переносимость

При определении стиля вашего адаптивного компонента React вы должны учитывать размер, макет или стиль каждого возможного родительского компонента, который может обернуть его, чтобы соответствующим образом адаптировать размер шрифта. Как вы понимаете, учет всех возможных размеров контейнера на самом деле нецелесообразен — даже если бы вы могли сделать это с помощью CSS. Вы будете преследовать слишком много сценариев области просмотра, чтобы было практично писать медиа-запросы. Но кроме медиа-запросов, в CSS нет способа гарантировать, что блок текста всегда умещается в одной строке.

Создавайте повторно используемые компоненты React

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

Читайте также:  Переменные среды Node.js: как их правильно установить?

Во-первых, мы рассмотрим, почему решение такой проблемы так важно и почему общих решений может быть недостаточно, особенно при использовании React. Затем react-textfitбудет представлена ​​библиотека React, которая будет использоваться для реализации решения как для однострочного, так и для многострочного текста.

Проблема подгонки текста в повторно используемых компонентах

Давайте посмотрим на следующую демонстрацию, объясняющую проблему подбора текста на примере.

import React, {
  useState,
  useEffect
} from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";

function ReactIFrame(props) {
  const { children, ...remainingProps } = props;

  const [contentRef, setContentRef] = useState(null);
  const mountNode = contentRef?.contentWindow?.document?.body;

  return (
    <iframe {...remainingProps} ref={setContentRef}>
      {mountNode && ReactDOM.createPortal(children, mountNode)}
    </iframe>
  );
}

function Headline(props) {
  const { headline } = props;

  return <h1 style={{ fontSize: "5.5vw" }}>{headline}</h1>;
}

function SingleLineDemo() {
  const [headline, setHeadline] = useState(
    "A Sample Headline Occupying Its Space"
  );

  const [iframeBody, setIframeBody] = useState(undefined);

  useEffect(() => {
    setIframeBody(
      <div
        style={{
          width: "100%",
          maxWidth: "100%",
          background: "#C0C0C0",
          resize: "both",
          overflow: "auto"
        }}
      >
        <Headline headline={headline} />
      </div>
    );
  }, [headline]);

  return (
    <>
      <h5>User's Screen</h5>
      <ReactIFrame
        style={{
          border: "1px solid red",
          width: "50%",
          resize: "both",
          overflow: "auto"
        }}
      >
        {iframeBody}
      </ReactIFrame>
      <div>
        <h5>Edit Headline Here</h5>
        <textarea
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "50%",
            minHeight: "50px",
            height: "50px"
          }}
          placeholder={headline}
          rows="5"
          value={headline}
          onChange={(e) => setHeadline(e.target.value)}
        />
      </div>
    </>
  );
}

ReactDOM.render(<SingleLineDemo />, document.getElementById("container"));

Цель состоит в том, чтобы заголовок соответствовал отведенному для него пространству, независимо от размера экрана пользователя. В этом примере единицы области просмотра используются для определения font-sizeзаголовка. Следовательно, при изменении размера iframeэкрана пользователя с красной рамкой заголовок всегда будет соответствовать своему родительскому

. Таким образом, этот метод, безусловно, позволяет адаптировать текст заголовка к любой ширине экрана. Однако Headlineстилизованный компонент нельзя использовать повторно. Это потому, что он разработан с учетом только этого конкретного текста. При добавлении текста заголовка или изменении размера родительского

текста текст больше не умещается в одной строке. (Вы можете поэкспериментировать с изменением текста в демонстрации.) Мы действительно хотим, чтобы многократно используемый компонент был более адаптируемым, чем этот.

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

react-textfit как решение для отзывчивого реактивного текста

Итак, давайте посмотрим, как react-textfitбиблиотека React позволяет автоматически помещать текст в доступное пространство, действительно делая компонент многоразовым.

import React, {
  useState,
  useEffect
} from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
import { Textfit } from "https://cdn.skypack.dev/react-textfit@1.1.1";

function ReactIFrame(props) {
  const { children, ...remainingProps } = props;

  const [contentRef, setContentRef] = useState(null);
  const mountNode = contentRef?.contentWindow?.document?.body;

  return (
    <iframe {...remainingProps} ref={setContentRef}>
      {mountNode && ReactDOM.createPortal(children, mountNode)}
    </iframe>
  );
}

function Headline(props) {
  const { headline } = props;
  const [resized, setResized] = useState(false);
    
  return (
    <Textfit
      mode={"single"}
      forceSingleModeWidth={true}
      // simulating a resizing event to make the page update
      onHover={() => setResized((state) => !state)}
      onMouseEnter={() => setResized((state) => !state)}
    >
      {headline}
    </Textfit>
  );
  
}

function SingleLineDemo() {
  const [headline, setHeadline] = useState(
    "A Sample Headline Occupying Its Space"
  );

  const [iframeBody, setIframeBody] = useState(undefined);

  useEffect(() => {
    setIframeBody(
      <div
        style={{
          width: "100%",
          maxWidth: "100%",
          background: "#C0C0C0",
          resize: "both",
          overflow: "auto"
        }}
      >
        <Headline headline={headline} />
      </div>
    );
  }, [headline]);

  return (
    <>
      <h5>User's Screen</h5>
      <p>Hover the headline to make it fit the space</p>
      <ReactIFrame
        style={{
          border: "1px solid red",
          width: "50%",
          resize: "both",
          overflow: "auto"
        }}
      >
        {iframeBody}
      </ReactIFrame>
      <div>
        <h5>Edit Headline Here</h5>
        <textarea
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "50%",
            minHeight: "50px",
            height: "50px"
          }}
          placeholder={headline}
          rows="5"
          value={headline}
          onChange={(e) => setHeadline(e.target.value)}
        />
      </div>
    </>
  );
}

ReactDOM.render(<SingleLineDemo />, document.getElementById("container"));

Как видите, вышеупомянутые проблемы есть. Благодаря react-textfit, теперь вы можете изменить заголовок или размер родительского элемента <div>, при этом заголовок плотно прилегает к доступному пространству.

Как Textfit работает

Теперь давайте посмотрим подробно, как react-textfitработает.

Как указано на официальной странице проекта GitHub, react-textfitэто библиотека для размещения заголовков и абзацев в любых повторно используемых компонентах. Он эффективно находит правильную посадку и работает с любой конфигурацией стилей CSS, такие как padding, line-heightи так далее.

Вы можете добавить его в свои зависимости, запустив следующую команду:

npm install react-textfit --save

После этого вы сможете получить доступ к Textfitкомпоненту, умещающему любой текст, следующим образом:

import { Textfit } from 'react-textfit';

Textfitбудет переведен в <div> элемент HTML и позволит вам разместить как однострочный, так и многострочный текст в любых повторно используемых компонентах или элементах HTML.

Чтобы использовать его, вы только заставляете его переносить текст, как показано ниже:

<Textfit>
  Sample text
</Textfit>

Или любой HTML-элемент, содержащий следующее:

<Textfit>
  <span>Sample text</span>
</Textfit>

Поскольку Textfitэто a <div>, вы можете передать ему правила CSS через styleопору React следующим образом:

<Textfit
  style={{"width": "200px"}}
>
  Sample text
</Textfit>

Или назначив его классу CSS classNameследующим образом:

<Textfit
  className={"divWidth200"}
>
  Sample text
</Textfit>

Реквизит Textfit

Textfitтакже поставляется с несколькими реквизитами, которые можно использовать по желанию для вашего текста. Посмотрим их все:

  • mode- строка, которая может принимать два значения: singleили multi. Он определяет метод, используемый компонентом для соответствия тексту. singleРежим должен использоваться для заголовков, а также multiрежим для пунктов. Значение по умолчанию — multi.
  • min- число, представляющее минимальный размер шрифта в пикселях, который может достигать текст. Значение по умолчанию — 1.
  • max- число, представляющее максимальный размер шрифта в пикселях, который может достигать текст. Значение по умолчанию — 100.
  • forceSingleModeWidth- это логическое значение, которое используется только в singleрежиме, чтобы Textfitкомпонент полностью игнорировал высоту элемента. Значение по умолчанию — true.
  • throttle- число, представляющее дроссель изменения размера окна в миллисекундах. Значение по умолчанию — 50.
  • onReady это функция, которая вызывается всякий раз, когда текст умещается.

Двумя наиболее важными являются minи max, которые позволяют вам установить нижнюю и верхнюю границы с точки зрения размера шрифта соответственно. Затем есть modeсвойство, которое определяет, как Textfitкомпонент должен себя вести. Это требует более подробного объяснения. Итак, давайте посмотрим на оба режима в действии.

Как уместить однострочный текст в повторно используемые компоненты

Однострочный текст представлен заголовками, заголовками и ярлыками. Это , как правило , содержится в <h1><h2><h3>или , в более общем <p>и <span>HTML — элементов. При работе с однострочным текстом проблема подгонки почти неизбежна. Это связано с тем, что его размер шрифта обычно намного больше, чем тот, который используется в абзацах. Когда singleрежим активируется вышеупомянутой modeопорой Textfit, применяется следующий алгоритм, включающий обязательный и необязательный этапы:

1. binary search to fit the element’s width

2. if forceSingleModeWidth=false and text overflows height

2a. binary search to also fit the element’s height

Как объясняется здесь, алгоритм двоичного поиска используется для получения правильного размера шрифта, чтобы текст, содержащийся в Textfitкомпоненте, соответствовал его ширине. Затем, если forceSingleModeWidthустановлено значение false, используется тот же подход, но также с учетом высоты элемента.

Создание многоразового использования компонента React: однострочная демонстрация

Теперь давайте посмотрим, как работает singleрежим Textfit в живой демонстрации:

import { Textfit } from "https://cdn.skypack.dev/react-textfit@1.1.1";
import React, { useState } from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";

function SingleLineDemo() {
  const [text, setText] = useState("Sample Headline!");
  const [resized, setResized] = useState(false);

  return (
    <>
      <div>
        <h2>Single Line Text</h2>
        <Textfit
          mode={"single"}
          forceSingleModeWidth={false}
          // simulating a resizing event to make the page update
          onMouseLeave={() => setResized((state) => !state)}
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "100%",
            maxWidth: "100%",
            minHeight: "50px",
            height: "50px",
            resize: "both",
            overflow: "auto"
          }}
        >
          {text}
        </Textfit>
      </div>
      <div>
        <h2>Edit Text Here</h2>
        <textarea
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "100%",
            minHeight: "50px",
            height: "50px"
          }}
          placeholder={text}
          rows="5"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
      </div>
    </>
  );
}

ReactDOM.render(<SingleLineDemo />, document.getElementById("container"));

Как видите, при увеличении текста размер шрифта будет соответственно обновлен, Textfitчтобы он соответствовал его размеру. Та же самая логика применяется при изменении размера текстового поля с сохранением текстовой константы. Вот что произошло бы с экранами меньшего размера. Таким образом, Textfitпредставляет собой идеальное решение для создания адаптивных заголовков и заголовков в любом компоненте React или элементе HTML.

Как разместить многострочный текст в компонентах Responsive React

Многострочный текст представлен абзацами, субтитрами и описаниями. Это, как правило , содержится в <p><em>или <div>HTML — элементов. Проблема с подгонкой многострочного текста часто возникает из-за высоты. Фактически, при работе с экранами меньшего размера ваш текст станет выше из-за меньшей доступной ширины. В результате ваш текст может превышать размер карточек или разделов с фиксированной высотой.

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

1. binary search to fit the element's height
2. if text overflows width
    2a. binary search to also fit the element's width

Алгоритм двоичного поиска используются для получения нужного размера шрифта, чтобы сделать текст, содержащийся в Textfitкомпоненте приступа его высоту. Затем используется тот же подход, но также с учетом ширины элемента. Как видите, в отличие от singleрежима, высота имеет приоритет над шириной. Это объясняется приведенной выше причиной.

Создание многоразового использования компонента React: многострочная демонстрация

Теперь давайте посмотрим, как работает multiрежим Textfit в живой демонстрации:

import { Textfit } from "https://cdn.skypack.dev/react-textfit@1.1.1";
import React, { useState } from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";

function MultiLineDemo() {
  const [text, setText] = useState("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
  const [resized, setResized] = useState(false);

  return (
    <>
      <div>
        <h2>Multi Line Text</h2>
        <Textfit
          mode={"multi"}
          // simulating a resizing event to make the page update
          onMouseLeave={() => setResized((state) => !state)}
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "100%",
            maxWidth: "100%",
            maxHeight: "400px",
            height: "50px",
            resize: "both",
            overflow: "auto"
          }}
        >
          {text}
        </Textfit>
      </div>
      <div>
        <h2>Edit Text Here</h2>
        <textarea
          style={{
            border: "1px solid",
            paddingTop: "20px",
            paddingBottom: "20px",
            width: "100%",
            minHeight: "50px",
            height: "50px"
          }}
          placeholder={text}
          rows="5"
          value={text}
          onChange={(e) => setText(e.target.value)}
        />
      </div>
    </>
  );
}

ReactDOM.render(<MultiLineDemo />, document.getElementById("container"));

При взаимодействии с интерактивной демонстрацией и увеличении длины многострочного текста размер шрифта будет обновлен, чтобы текст соответствовал размеру элемента HTML. То же самое происходит при изменении размера Textfitкомпонента при сохранении постоянной текста. Вот что произойдет с экранами меньшего размера. Итак, Textfit это хорошее решение. Чтобы сделать абзацы и длинные описания адаптивными в любом элементе HTML или компоненте React.

Заключение

Поскольку смартфоны и планшеты стали наиболее широко используемыми устройствами для доступа в Интернет, скорость отклика стала проблемой, которую больше нельзя игнорировать. В этой статье мы рассмотрели конкретную проблему в этой области. В частности, мы исследовали конкретную проблему подгонки текста, почему ее так важно решать и как это делать в React.

react-textfit Библиотека является полезным, открытым исходным кодом, эффективная Реагировать библиотека, которая позволяет легко сделать текст — как однострочный и многострочный — подходит любой Реагировать компонент без особых усилий. Надеюсь, вы нашли объяснение и демонстрации полезными. Спасибо за прочтение! Не стесняйтесь обращаться ко мне с любыми вопросами, комментариями или предложениями.

Оцените статью
bestprogrammer.ru
Добавить комментарий