Реагуйте на розриви рядків дисплея із збереженого тексту


83

Використання Facebook React. На сторінці налаштувань у мене є багаторядковий рядок, textareaкуди користувач може вводити багаторядковий текст (у моєму випадку - адресу).

<textarea value={address} />

Коли я намагаюся відобразити адресу, так щось на кшталт {address}, вона не відображає розривів рядків і знаходиться в одному рядку.

<p>{address}</p>

Будь-які ідеї, як це вирішити?

Відповіді:


241

Немає причин використовувати JS. Ви можете легко сказати браузеру, як обробляти новий рядок, використовуючи white-spaceвластивість CSS:

white-space: pre-line;

попередній рядок

Послідовності пробілів згортаються. Рядки розбиваються на символи нового рядка, на <br>і, якщо потрібно, заповнюють поля рядків.

Ознайомтеся з цією демонстрацією:

<style>
  #p_wrap {
    white-space: pre-line;
  }
</style>

<textarea id="textarea"></textarea>
<p id="p_standard"></p>
<hr>
<p id="p_wrap"></p>
<script>
  textarea.addEventListener('keypress', function(e) {
    p_standard.textContent = e.target.value
    p_wrap.textContent = e.target.value
  })
</script>

підтримка браузера для попередньої лінії


Це працює кількома шляхами: якщо ви спробуєте зробити розрив рядка (<br />) у JSX через змінну, він "безпечно" зробить розмітку замість додавання розриву рядка. Використання символів евакуації з цим CSS працює навколо цього механізму безпеки, а також вирішує заявлену проблему.
bvoyelr

дуже приємне і просте рішення. Зараз усі нові символи рядка працюють, як очікувалося, для texarea.
Наміш

31

Це слід очікувати, вам потрібно буде перетворити символи нового рядка (\ n) на розриви рядків HTML

Стаття про використання його в реакції: React Newline to break (nl2br)

Процитувати статтю:

Оскільки ви знаєте, що все в React - це функції, ви насправді цього не можете зробити

this.state.text.replace(/(?:\r\n|\r|\n)/g, '<br />')

Оскільки це поверне рядок із DOM-вузлами всередині, це також заборонено, оскільки має бути лише рядком.

Потім можна спробувати зробити щось подібне:

{this.props.section.text.split(“\n”).map(function(item) {
  return (
    {item}
    <br/>
  )
})}    

Це також не дозволено, оскільки знову React - це чисті функції, і дві функції можуть бути поруч.

tldr. Рішення

{this.props.section.text.split(“\n”).map(function(item) {
  return (
    <span>
      {item}
      <br/>
    </span>
  )
})}

Тепер ми обертаємо кожний розрив рядка в інтервал, і це працює чудово, оскільки в інтервалі span є вбудований дисплей. Тепер ми отримали робоче рішення розриву лінії nl2br


Дякую Марк, працює як шарм. Будь-який шанс ви могли б поставити відповідь тут? Stackoverflow не любить зовнішні посилання (може зникнути, важче переглянути список відповідей, ...), і я позначу вашу відповідь як правильну.
denislexic

4
Примітка для інших: Вам також потрібно додати ключовий атрибут до діапазону, оскільки він знаходиться в циклі. так би і було....map(function (item, i) { return <span key={i}>{item}<br/></span> })
denislexic

1
Чудова відповідь! Це мені було корисно. Крім того , якщо у вас є кілька розривів рядків, ви можете запобігти перевищення <br />від рендеринга для останнього елемента: ....map(function (item, i, arr) { return <span key={i}>{item}{ arr.length-1 === i ? null : <br/>}</span> }). Зверніть увагу, що я включив 3-й аргумент для.map()
Лаша

1
Я не розумію, як ти змусив це працювати. Я відображаю в <textarea> це[object Object]
Ed.

@Ed. Він відображає текст HTML не в текстовій області. Це допомагає?
denislexic

9

Рішення полягає у встановленні властивості white-spaceелемента, що відображає вміст вашого textarea:

white-space: pre-line;

4

Попередня пропозиція Піта з автономним компонентом є чудовим рішенням, хоча вона пропускає одну важливу річ. Списки потребують ключів . Я трохи підкоригував, і моя версія (без попереджень консолі) виглядає так:

const NewLineToBr = ({ children = '' }) => children.split('\n')
  .reduce((arr, line, index) => arr.concat(
    <Fragment key={index}>
      {line}
      <br />
    </Fragment>,
  ), [])

У ньому використані фрагменти React 16's


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

2

Починаючи з React 16, компонент може повертати масив елементів, а це означає, що ви можете створити такий компонент:

export default function NewLineToBr({children = ""}){
  return children.split('\n').reduce(function (arr,line) {
    return arr.concat(
      line,
      <br />
    );
  },[]);
}

який ви використовували б ось так:

<p>
  <NewLineToBr>{address}</NewLineToBr>
</p>

Мені довелося змінити "\ n" на "\\ n".
dustydojo

1

Люблю веб-версію. Я не знав про компонент Fragment, він такий корисний. Не потрібно використовувати метод зменшення. Карти досить. Крім того, у списку потрібні ключі для реагування, але це погана звичка використовувати для нього індекс із методу ітерації. eslint продовжував розбивати це у своєму попередженні, поки у мене не виникла помилка. Тож це могло б виглядати так:

const NewLine = ({ children }) =>
   children.split("\n").map(line => (
    <Fragment key={uuidv4()}>
      {line}
      <br />
    </Fragment>
  ));

1
Погана ідея використовувати uuids як ключ у React, оскільки КОЖНИЙ новий візуалізатор вважатиме цей елемент новим і, таким чином, адаптувати DOM.
enapupe
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.