当前位置: 首页 > 面试题库 >

如何在React中响应自动调整大小的DOM元素的宽度?

夏兴生
2023-03-14
问题内容

我有一个使用React组件的复杂网页,并且正在尝试将该页面从静态布局转换为响应更快,可调整大小的布局。但是,我一直遇到React的限制,并且想知道是否存在用于处理这些问题的标准模式。在我的特定情况下,我有一个使用display:table-
cell和width:auto呈现为div的组件。

不幸的是,我无法查询组件的宽度,因为您无法计算元素的大小,除非将其实际放置在DOM中(该元素具有推论实际渲染宽度的完整上下文)。除了用于相对鼠标定位之类的功能外,我还需要此功能来在组件内的SVG元素上正确设置宽度属性。

另外,当窗口调整大小时,如何在安装过程中将尺寸变化从一个组件传递到另一个组件?我们正在shouldComponentUpdate中完成所有第三方SVG渲染,但是您无法在该方法中设置自己或其他子组件的状态或属性。

是否有使用React处理此问题的标准方法?


问题答案:

最实用的解决方案是使用库来进行类似react-measure的操作。

更新 :现在有一个用于调整大小检测的自定义钩子(我没有亲自尝试过):react-resize-
aware
。作为自定义挂钩,它看起来比起来更方便react-measure

import * as React from 'react'
import Measure from 'react-measure'

const MeasuredComp = () => (
  <Measure bounds>
    {({ measureRef, contentRect: { bounds: { width }} }) => (
      <div ref={measureRef}>My width is {width}</div>
    )}
  </Measure>
)

为了传达组件之间的大小变化,您可以传递一个onResize回调并将接收到的值存储在某个地方(如今,共享状态的标准方法是使用Redux):

import * as React from 'react'
import Measure from 'react-measure'
import { useSelector, useDispatch } from 'react-redux'
import { setMyCompWidth } from './actions' // some action that stores width in somewhere in redux state

export default function MyComp(props) {
  const width = useSelector(state => state.myCompWidth) 
  const dispatch = useDispatch()
  const handleResize = React.useCallback(
    (({ contentRect })) => dispatch(setMyCompWidth(contentRect.bounds.width)),
    [dispatch]
  )

  return (
    <Measure bounds onResize={handleResize}>
      {({ measureRef }) => (
        <div ref={measureRef}>MyComp width is {width}</div>
      )}
    </Measure>
  )
}

如果您确实喜欢以下内容,该如何滚动自己:

创建一个包装器组件,该组件处理从DOM获取值并监听窗口调整大小事件(或所使用的组件调整大小检测react- measure)。您告诉它要从DOM获取哪些道具,并提供将这些道具作为子对象的渲染函数

必须先安装渲染的内容,然后才能读取DOM属性;当这些道具在初始渲染期间不可用时,您可能需要使用它,style={{visibility: 'hidden'}}以便用户在获得JS计算的布局之前看不到它。

// @flow

import React, {Component} from 'react';
import shallowEqual from 'shallowequal';
import throttle from 'lodash.throttle';

type DefaultProps = {
  component: ReactClass<any>,
};

type Props = {
  domProps?: Array<string>,
  computedStyleProps?: Array<string>,
  children: (state: State) => ?React.Element<any>,
  component: ReactClass<any>,
};

type State = {
  remeasure: () => void,
  computedStyle?: Object,
  [domProp: string]: any,
};

export default class Responsive extends Component<DefaultProps,Props,State> {
  static defaultProps = {
    component: 'div',
  };

  remeasure: () => void = throttle(() => {
    const {root} = this;
    if (!root) return;
    const {domProps, computedStyleProps} = this.props;
    const nextState: $Shape<State> = {};
    if (domProps) domProps.forEach(prop => nextState[prop] = root[prop]);
    if (computedStyleProps) {
      nextState.computedStyle = {};
      const computedStyle = getComputedStyle(root);
      computedStyleProps.forEach(prop => 
        nextState.computedStyle[prop] = computedStyle[prop]
      );
    }
    this.setState(nextState);
  }, 500);
  // put remeasure in state just so that it gets passed to child 
  // function along with computedStyle and domProps
  state: State = {remeasure: this.remeasure};
  root: ?Object;

  componentDidMount() {
    this.remeasure();
    this.remeasure.flush();
    window.addEventListener('resize', this.remeasure);
  }
  componentWillReceiveProps(nextProps: Props) {
    if (!shallowEqual(this.props.domProps, nextProps.domProps) || 
        !shallowEqual(this.props.computedStyleProps, nextProps.computedStyleProps)) {
      this.remeasure();
    }
  }
  componentWillUnmount() {
    this.remeasure.cancel();
    window.removeEventListener('resize', this.remeasure);
  }
  render(): ?React.Element<any> {
    const {props: {children, component: Comp}, state} = this;
    return <Comp ref={c => this.root = c} children={children(state)}/>;
  }
}

这样,响应宽度变化非常简单:

function renderColumns(numColumns: number): React.Element<any> {
  ...
}
const responsiveView = (
  <Responsive domProps={['offsetWidth']}>
    {({offsetWidth}: {offsetWidth: number}): ?React.Element<any> => {
      if (!offsetWidth) return null;
      const numColumns = Math.max(1, Math.floor(offsetWidth / 200));
      return renderColumns(numColumns);
    }}
  </Responsive>
);


 类似资料:
  • 问题内容: 不知道我需要什么。我有一个包含一些内部元素的容器(JPanel)。我想知道是否有可能迫使内部元素适应容器的大小。我需要使它们完全可见,即调整其大小以适合面板的尺寸,并且不剪切内部元素的某些部分。 滚动不是一种选择。 使用Layout或其他方法可以做到吗? 编辑:重要说明:问题是我无法访问内部元素,也无法访问其属性,因此我想说需要一个能够调整子元素大小以适合其大小的Layoutmanag

  • 问题内容: 我正在将AutoSizing单元格与Autolayout和UICollectionView一起使用。 我可以在单元初始化的代码中指定约束: 但是,由于该单元尚未添加到中,该应用程序崩溃了。 问题 在该阶段的生命周期,可以添加一个约束的? 有没有作出任何默认方式的equal to the of thewithout accessing an instance of or? 编辑 这个问题

  • 我想将组件的宽度设置为容器宽度的100%,并根据结果宽度值和图像的纵横比设置高度。 我的容器有一些填充,这意味着 对我来说没有用,因为它没有给我图像宽度设置为 100% 所产生的值。其他方案也无法将维度 API 作为可接受的解决方案。 下面是一个代码示例: 结果: 红色背景只是为了显示< code>Image组件。 使用prop,我可以获得结果宽度的运行时值,并且借助Image API,我可以计算

  • 为了增强用户体验,CSS3 中新增了一个非常实用的 resize 属性,该属性允许用户通过拖动的方式来自由缩放元素的尺寸,在此之前要实现类似的效果还需要借助大量的 JavaScript 代码。resize 属性的语法格式如下: resize: none|both|horizontal|vertical; 语法说明如下: none:用户无法调整元素的尺寸; both:用户可调整元素的高度和宽度; h

  • 问题内容: 我有一个子类,可以在其上添加按钮,标签,表格等。要在屏幕上显示,请使用: 但是,当我调整窗口大小时,面板的大小不会改变。即使调整了尺寸,如何使面板的尺寸与窗口的尺寸相同? 问题答案: 您可以设置一个类似于BorderLayout的布局管理器,然后更具体地定义面板应该放置的位置: 这会将面板置于框架的中央区域,并在调整框架大小时自动增长。

  • Android最近增加了根据视图大小以及最小和最大文本大小调整TextViews文本大小的支持。 https://developer.Android.com/guide/topics/ui/look-and-feel/autosizing-textView.html 不幸的是,他们不支持EditTexts,那么EditText还有其他的替代方案吗?