2016-04-06 3 views
0

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

enter image description here

Итак, что я нацеливание (а также работает некоторое время) для оказанной заголовка к проходным и установите высоту самой высокой из трех заголовков. На изображении выше функция должна иметь аналогичный вид, но где каждый из заголовков сохраняет свой запас. Вместо этого он рассчитал их все на один размер, чтобы разрезать край. К сожалению, кажется, что (обычно) на заголовках, которые имеют только одну сироту, высота вычисляется правильно. У кого-нибудь есть лучшие идеи? Мой код ниже.

Columns.js (updateHeight является важной функцией здесь) -

import React from 'react' 
 
import { branch } from 'baobab-react/higher-order' 
 
import classNames from 'classnames' 
 
import _parseInt from 'lodash.parseint' 
 
import _filter from 'lodash.filter' 
 
import InlineSVG from 'react-inlinesvg' 
 

 
// Column Components 
 
import ImageContainer from './columns/ImageContainer' 
 
import IconContainer from './columns/IconContainer' 
 
import ColumnHeader from './columns/ColumnHeader' 
 
import Content from './columns/Content' 
 

 
class Columns extends React.Component { 
 

 
\t constructor(props, context) { 
 
\t \t super(props, context) 
 
\t \t this.state = { 
 
\t \t \t content: 0, 
 
\t \t \t header: 0, 
 
\t \t } 
 
\t } 
 

 
\t updateHeight(height, component) { 
 
\t \t if (window.innerWidth > 768 && window.innerHeight > 768) { 
 
\t \t \t if (height > this.state[component]) { 
 
\t \t \t \t this.setState({ [component]: height }) 
 
\t \t \t } else { 
 
\t \t \t \t return false 
 
\t \t \t } 
 
\t \t } else { 
 
\t \t \t return false 
 
\t \t } 
 
\t } 
 

 
\t getItems(column, index) { 
 

 
\t \t let data = column[0] || column 
 
\t \t const icon = data.icon ? '/assets/icons/' + data.icon : null 
 
\t \t const image = data.bioImage ? '/assets/bio-photos/' + data.bioImage : null 
 
\t \t const ref = `column${ index }` 
 

 
\t \t return (
 
\t \t \t <div className="column" key={ index } ref={ ref }> 
 
\t \t \t \t { image ? <ImageContainer title={ data.title } image={ image } /> : null } 
 
\t \t \t \t { icon ? <IconContainer icon={ icon } /> : null } 
 
\t \t \t \t <ColumnHeader 
 
\t \t \t \t \t title={ data.title } 
 
\t \t \t \t \t subtitle={ data.subtitle } 
 
\t \t \t \t \t index={ index } 
 
\t \t \t \t \t updateHeight={ this.updateHeight.bind(this) } 
 
\t \t \t \t \t height={ index === undefined ? 'auto' : this.state.header } /> 
 
\t \t \t \t <Content 
 
\t \t \t \t \t content={ data.content } 
 
\t \t \t \t \t updateHeight={ this.updateHeight.bind(this) } 
 
\t \t \t \t \t height={ index === undefined ? 'auto' : this.state.content } /> 
 
\t \t \t \t { this.props.type === 'team' 
 
\t \t \t \t \t ? <div className="team__social"><InlineSVG src="/assets/icons/linkedin.svg"></InlineSVG></div> 
 
\t \t \t \t \t : null 
 
\t \t \t \t } 
 
\t \t \t </div> 
 
\t \t) 
 
\t } 
 

 
\t render() { 
 
\t \t const data = this.props.data.columns || this.props.data 
 
\t \t const type = this.props.type 
 
\t \t const count = data.length || 1 
 
\t \t let columns = count > 1 ? data.map((column, index) => this.getItems(column, index)) : this.getItems(data, 1) 
 

 
\t \t let columnClasses = classNames({ 
 
\t \t \t 'columns': true, 
 
\t \t \t [`columns--${count}`]: true, 
 
\t \t \t 'columns--icons': type === 'icons' ? true : false, 
 
\t \t \t 'columns--team': type === 'team' ? true : false, 
 
\t \t }) 
 

 
\t \t return (
 
\t \t \t <div className={ columnClasses }> 
 
\t \t \t \t { columns } 
 
\t \t \t </div> 
 
\t \t) 
 
\t } 
 
} 
 

 

 
export default branch(Columns, { 
 
\t cursors: { 
 
\t \t navOpen: ['navOpen'], 
 
\t } 
 
})

ColumnHeader.js -

import React from 'react' 
 
import { branch } from 'baobab-react/higher-order' 
 

 
class ColumnHeader extends React.Component { 
 

 
\t constructor(props, context) { 
 
\t \t super(props, context) 
 
\t } 
 

 
\t componentDidMount() { 
 
\t \t this.props.updateHeight(this.refs.header.offsetHeight, 'header') 
 
\t } 
 
\t 
 
\t render() { 
 
\t \t let { title, subtitle } = this.props 
 
\t \t let height = (this.props.height === 0) ? 'auto' : this.props.height 
 
\t \t return (
 
\t \t \t <div className="column__header" ref="header" style={{ height: height }}> 
 
\t \t \t \t <h1 className="title">{ title }</h1> 
 
\t \t \t \t { subtitle ? (<h2 className="subtitle">{ subtitle }</h2>) : null } 
 
\t \t \t </div> 
 
\t \t) 
 
\t } 
 
} 
 

 
export default ColumnHeader

Второе изображение для наглядности: enter image description here

+0

Все элементы вашего изображения (значок, заголовок, подзаголовок, текст) кажутся одинаковой высоты (по мере необходимости), с содержимым внутри выровненного вверх. Что именно вы хотите по-другому? – wintvelt

+0

Он появляется только таким образом (как я, возможно, плохо объяснил выше), поскольку на каждом элементе заголовка есть 1-кратное поле. Таким образом, высота фактически отсекает два заголовка справа, но маржа подпирает их так, что общее пространство, на котором они размещаются, составляет примерно 68 пикселей, но фактическая высота заголовка равна 42 пикселям, что хорошо ниже фактической высоты заголовка. Реально, все три должны быть 68 пикселей в высоту, например, с нижним краем 1rem для каждого (если он работал правильно). – thesublimeobject

+0

Извините, но я до сих пор этого не вижу. CSS Height = content + padding + margin. Если высота всегда равна 68px, тогда высота одинакова для всех заголовков, хотя маржа отличается. И тогда все элементы выравниваются. Не могли бы вы поделиться более четкими изображениями неправильного и правильного расположения? – wintvelt

ответ

2

Это вопрос css: offsetHeight и height имеют разные определения в css, которые важны для понимания. Если вы используете read one и используете это значение для установки другого, все пойдет не так. Не имеет значения, используете ли вы реакцию на это или на любые другие рамки.

  • offsetHeight = содержание + обивка + граница (но исключает рентабельности)
  • высота = содержание + отступы + границу + запас

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

В примере:

  • давайте предположим, что ваш высокий заголовок имеет отступ 0, края 10px сверху и снизу, и содержание с 2 линиями и высоты содержимого в 48px.
  • Таким образом, общая высота составляет 10 + 48 + 10 = 68 пикселей.
  • offsetHeight вы читаете тогда 48px. (исключая поля)
  • затем вы устанавливаете height в 48px. Итоговая общая высота, включая маржу, теперь установлена ​​на 48 пикселей.
  • Это неправильное значение. Правильное значение должно быть 68 пикселей.

Чтобы исправить, необходимо включить верхний и нижний край к offsetHeight до прохождения высоты к updateHeight() метода:

componentDidMount() { 
    // get topMargin and bottomMargin from DOM 
    let heightPlusMargins = this.refs.header.offsetHeight + topMargin + bottomMargin; 
    this.props.updateHeight(heightPlusMargins, 'header') 
} 

Вы можете использовать JQuery или ваниль Javascript, чтобы получить верхнюю и нижнюю границу , Оба объясняются в separate thread on SO here.

В более общем примечании: общий подход к получению рядов одинаковой высоты кажется очень неэффективным. Сначала вы создаете столбцы, затем читаете высоту из всех ячеек, а затем корректируете высоту и повторно визуализируете. Вероятно, существует лучшее общее решение для решения проблемы высоты в CSS.
Похоже, что ваши столбцы имеют одинаковую ширину, и поэтому все ячейки имеют одинаковую ширину.
Вы также можете отобразить по строке (вместо столбца), используя только css, чтобы каждая ячейка имела такую ​​же ширину (% или фиксированную) и чтобы каждая ячейка в той же строке была одинаковой высоты. HTML-таблицы или CSS flexbox (я предпочитаю последний) - это варианты для этого.
Затем вы можете просто сделать за один проход и потерять все показания чтения, обновления состояния и кода повторного рендеринга. Улучшение общего кода и повышение эффективности работы.

+0

Определенно хороший футляр для flexbox –

+0

Я действительно использую flexbox, но не в виде строки. Я не могу вернуться назад и сделать это в этот момент, поскольку мне придется переписать большую часть моей структуры данных, на которые у меня нет времени. Я согласен, тем не менее, это, вероятно, было бы лучшим решением. Однако я не согласен с тем, что это проблема CSS. Даже если я устанавливаю высоту и маржу отдельно после рендеринга, я получаю те же результаты. Ошибка заключается в чтении правильной высоты после рендеринга, поэтому мой вопрос по существу, я думаю, один из вопросов, как реагировать на чтение этих значений DOM, и если есть лучший способ. – thesublimeobject

+0

Спасибо за помощь @wintvelt. Это была не проблема с CSS, но я все-таки получил ее на работу, хотя и в круговом и неровном порядке. Вы правы в том, что сетка строк является лучшим вариантом, у меня просто нет времени переписывать свои структуры данных. Это был запрос от дизайнера после того, как я написал большую часть приложения. : // – thesublimeobject

Смежные вопросы