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


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.