В v16 React появилась новая фичаPortals. Когда я впервые увидел функцию «Порталы», я не увидел в ней ничего особенного. Однако, когда я недавно имел дело с бизнес-требованием, я понял, чтоPortalsЭто действительно интересно.
воспроизведение сцены
Сначала восстановим требования к продукту.
анализ спроса
В этом функциональном модуле компонент A управляет отображением вкладок первого уровня, компонент B управляет отображением вкладок второго уровня, а компонент C отвечает за отображение текущего активного содержимого вкладок; нажмите на элемент в список заголовков в компоненте C (например, левый, как показано на рисунке), то есть разверните список деталей D правого рисунка в этом модуле. А детали D будут отображаться во всю ширину и высоту в этом модуле.
Реализовать идеи
Приблизительная структура компонента C моделируется с помощью следующего кода.
class C extends React.Component {
constructor(props) {
super(props)
this.state = { visible: false }
}
handleClick = () => {
this.setState({ visible: false })
}
render() {
return (
<div>
<Others onClick={this.handleClick} />
{this.state.visible && <D />}
</div>
)
}
}
Нажав на заголовок в Othors (код моделирования, не беспокойтесь о полной реализации), измените видимое логическое значение в состоянии в компоненте C, а затем определите отображение и скрытие компонента D.
Поскольку требование состоит в том, чтобы отображать 100% полной ширины и высоты, я очень рад написать стиль css компонента D следующим образом:
.d {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #fff;
z-index: 10;
}
cmd+s
После сохранения вернитесь в браузер, чтобы увидеть результат, и обнаружите, что требования действительно выполнены, а взаимодействие также соответствует черновому варианту дизайна.
Похоже, то, что я сказал ранее, не имеет никакого смысла. Но когда я допил бутылку со льдом Fat Boy Happy Water, я вдруг понял, что в таком коде обязательно будут баги.
сайт с ошибками
В приведенном выше коде css первая строкаposition: absolute
Вот в чем опасность.
мы все знаем приложениеposition: absolute
элементы смещаются относительно ближайшего нестатически расположенного элемента-предка. В этом примере ближайшим предком компонента D является C. Хотя в настоящее время в компонентах C мы не используем такие вещи, какposition: relative
css, как это, но когда-нибудь, если нам нужно будет использовать его в компонентах Cposition: relative
При выполнении позиционирования элемента ширина и высота компонента D могут поддерживать только компонент C. (Как показано ниже)
В качестве переднего конца можно сказать, что 100% уменьшается UI, чтобы быть достойным, как передняя часть. Мы не можем сказать товару: «Вы больше не можете добавлять элементы в компонент C в будущем, в противном случае он повлияет на исходную функцию».
Итак, давайте теперь абстрагируемся.В этом требовании мы надеемся, что при нажатии определенного заголовка в компоненте C,Перенесите компонент D в компонент A и повторно используйте его.position: absolute
Заставьте компонент D заполнить компонент A.
Похоже, нам нужен портал, и когда компонент D выходит через эту дверь, он достигает компонента A.
Портал React World -- Порталы
Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
Порталы предоставляют отличный способ отображать дочерние узлы в узлах DOM, отличных от родительского компонента.
На самом деле, до того, как я углубился в эту функцию, я не знал, каким словом перевести порталы в уме, и теперь я действительно чувствую, что перевод «портал» действительно является сутью.
Что такое порталы
Давайте кратко рассмотрим порталы:
ReactDOM.createPortal(child, container)
Первый параметр — это визуализируемый дочерний элемент React, а второй параметр — элемент DOM.
модификация кода
Итак, теперь давайте воспользуемся порталами для преобразования нашего кода.
Во-первых, нам нужно получить элемент DOM компонента A, добавив идентификатор к компоненту A, а затем в соответствии сdocument.getElementById('component-a')
Получить ссылку DOM A:
<div id="component-a">
{/* ... 组件A的代码*/}
</div>
CSS компонента A должен добавить абзацposition: relative
, чтобы следующий компонент D был абсолютно расположен относительно компонента A.
Затем создайте компонент, который применяет порталы:
import * as React from 'react'
import { createPortal } from 'react-dom'
import './index.scss'
import { ComponentExt } from '@utils/reactExt'
export interface PortalsContainerProps {}
class PortalsContainer extends ComponentExt<PortalsContainerProps> {
el: HTMLDivElement = null
constructor(props: PortalsContainerProps) {
super(props)
const containers = document.getElementById('component-a')
this.el = document.createElement('div')
containers.appendChild(this.el)
}
componentWillUnmount() {
document.getElementById('component-a').removeChild(this.el)
}
render() {
return createPortal(<div className="portals-container">{this.props.children}</div>, this.el)
}
}
export default PortalsContainer
css часть
.portals-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: #fff;
z-index: 10;
}
Наконец, компонент D может быть передан как Children of PortalsContainer:
import PortalsContainer from './PortalsContainer'
...
<PortalsContainer>
{/* ... 组件D的代码*/}
</PortalsContainer>
Теперь мы можем взглянуть на окончательную структуру кода в DOM после оптимизации через портал:
И тогда мы найдем что-то очень волшебное. Компонент D, очевидно, является дочерним элементом компонента C, но теперь его структура DOM напрямую вставляется в компонент A через порталы. Это похоже на то, что React Portals открыл для нас портал, позволяющий нашему компоненту D проходить непосредственно в структуру DOM компонента A.
Таким образом, наш компонент D позиционируется непосредственно относительно всего компонента модуля A независимо от того, будет ли компонент C добавлен с элементами позиционирования в будущем.
расходящийся
Когда я узнал о функции портала Portals, я обнаружил, что общие компоненты пользовательского интерфейса, такие как модальные всплывающие окна (Modal), глобальные подсказки (Message) и текстовые подсказки (Tootip), могут применять эту функцию. Вдвойне круто!
Например, вant-designВ компоненте пузырьковой карты Popover он применяется к порталам.
Мы можем посмотреть на составную структуру компонента Popover в React:
Стрелка показывает применение порталов в триггере. А компонент контента посередине — это то место, где контент нашей карты действительно существует.
PS: Если вы заинтересованы в таком компоненте рамы пули, настоятельно рекомендуется взглянутьrc-triggerисходный код.
Эпилог
Поддержка React для порталов очень хорошо решила проблемы, с которыми я столкнулся в бизнесе, и мне не нужно рассматривать какие-то очень хакерские методы. Поэтому напишите сообщение в блоге, чтобы описать процесс.
Оглядываясь назад на процесс, начиная с того момента, когда я впервые увидел порталы, и заканчивая углубленной практикой позже, я чувствую, что мне часто нужно больше изучать граничные условия бизнес-сценариев. Может быть, вы также можете получить некоторые знания, которые можно использовать самостоятельно. Вы не можете просто написать код со скрытыми уязвимостями только для того, чтобы соответствовать требованиям и успеть к графику.