Визуализации и реализованные функции
Схема эффекта реализации выглядит следующим образом, основными функциями являются:
- Вставка выражений
- Выберите текст после вставки темы
- Адаптивная высота текстового поля
- Отправьте сообщение, получите текстовое содержимое в поле отправки
- Реализация заполнителя
- Панель подсчета для ввода текста
кодовый адреспорталКодVue
источник вдохновения
«Должно быть, кто-то сделал то, что вы хотите сделать, и вы не должны быть первым, кто столкнулся с этой проблемой» — это предложение справедливо для 80% (28 раз) людей, и я получил от него много пользы.
Мой первый эталонный случай — это поле выпуска разговора в пространстве qq && поле отправки сообщения webqq, Выгоды от него следующие:
- можно использовать
div+contenteditable
Реализовать окно отправки сообщений - Использовать в Chrome
button
тег для выделения @users, используйте в Firefoximg
Теги для выделения @users (отлично) Использование различных тегов здесь очень специфично, учитывая совместимость с браузерами. - Вставив тему, выберите текст, чтобы улучшить взаимодействие с пользователем. Здесь также есть ссылка на него.Блог учителя Чжан Синьсюй Второй эталонный случай — это коробка динамического выпуска Наггетсов, а урожай выглядит следующим образом.
- В правом нижнем углу показано количество слов, которые еще можно ввести.
-
placeholder
реализация
Некоторые детали реализации
contenteditable
Я читаю статью г-на Чжан СиньсюяПеревод — 28 функций, хитростей и приемов HTML5, которые вы должны знатьПри первом контакте с ним можно пройтиdiv+contenteditable
заменятьtextarea
Реализуйте поле редактирования. прочитай позжеDiv имитирует текстовое поле textarea, чтобы легко адаптироваться к высотеОткройте для себя силу этого свойства.
Кроме того, если вы хотите, чтобы элемент на веб-странице был выделен, сначала вам понадобится HTML-тег, которому можно назначить CSS для его выбора, а затем измените тег, чтобы выполнить эту задачу.textarea
, инлайнить теги крайне сложно, можно сказать, что нельзя, ноdiv
Различные встроенные теги являются обычным явлением, и истории успеха Nuggets и пространства QQ не нужно упоминать.
оcontenteditable
Свойства атрибута можно посмотреть по двум ссылкам выше, одним словом, тег с этим атрибутом и вложенные в него теги будут установлены как редактируемые атрибуты.
Реализация заполнителя
картинаinput
а такжеtextarea
Эти теги идут сplaceholder
свойства, ноdiv
Нет, для этого нужно смоделировать JS и CSS.
через два слояdiv
Для достижения во внешнем слое, отслеживая, есть ли текст в поле редактирования, чтобы выбрать, отображать лиplaceholder
,placeholder
Реализовано с помощью псевдоэлементов и абсолютного позиционирования, плавающего над полем редактирования без стандартного потока документов.
<div
class="edit-panel"
:class="{'show-placeholder' : showPlaceholder}"
:placeholder="placeholder"
>
<div contenteditable="true" ref="editor" class="editor"></div>
<span class="count" :class="{'font-red':textCount < 0}">{{ textCount }}</span>
</div>
.edit-panel {
position: relative;
width: 100%;
height: auto;
font-size: 14px;
line-height: 20px;
border: 1px solid;
}
.show-placeholder::before {
content: attr(placeholder);
position: absolute;
top: 4px;
left: 8px;
color: #555;
pointer-events: none;
}
количество панелей
надplaceholder
Реализовать то же намерение
.edit-panel .count {
position: absolute;
color: #555;
right: 1rem;
bottom: 0.5rem;
user-select: none;
pointer-events: none;
}
Адаптивная высота текстового поля
Только здесь нужно установитьmin-height
а такжеmax-height
просто хорошо
вставить смайлик
При вставке выражения нельзя считать само собой разумеющимся, что можно использовать операцию dom для вставки выражения.img
Label, вот сравнение функций, реализованных Nuggets, и функций, реализованных пространством QQ. Я обнаружил, что поле ввода будет мигать, когда самородки вставят смайлик, а пробел QQ — нет. Мое разумное предположение состоит в том, что Nuggets вставляет выражения через операции dom, а затем записывает перед вставкой.range
объект, восстановленный после вставкиrange
Таким образом, вы не потеряете позицию курсора,range
Объекты используются для управления и получения текущего выбора курсора. Подробная ссылкаМДН — Диапазон. Пространство QQ вставляет выражения другими способами, аналогичными другим редакторам форматированного текста, и не мерцает при вставке. Я пошел исследовать здесь, используя следующий метод для вставки, создавdom片段
, затем используйтеrange
Объект вставляется в поле редактирования так, чтобы курсор не терялся.
Здесь следует отметить, что если с DOM неправильно манипулировать, позиция курсора будет смещена.Хороший пользовательский опыт заключается в том, что позиция курсора остается неизменной.
function insertHtmlAtCaret (html) {
var sel, range, frag
if (window.getSelection) {
sel = window.getSelection()
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0)
range.deleteContents()
var el = document.createElement('div')
el.innerHTML = html
frag = document.createDocumentFragment()
var node
var lastNode
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node)
}
range.insertNode(frag)
if (lastNode) {
range = range.cloneRange()
range.setStartAfter(lastNode)
range.collapse(true)
sel.removeAllRanges()
sel.addRange(range)
}
}
}
}
Выберите текст после вставки темы
тут надо пониматьrange
Четыре важных свойства объектовstartContainer
,startOffset
,endContainer
,endOffset
.在不同情况下指代的意思是不一样的,我这里就是轻描淡写的提一下,我理解的不是很透彻就不误导大家了。
addTopic (event) {
this.$refs.editor.focus()
insertHtmlAtCaret('#')
insertHtmlAtCaret('请输入一个话题')
insertHtmlAtCaret('#')
var range = window.getSelection().getRangeAt(0)
console.log(range)
range.selectNodeContents(range.startContainer.childNodes[range.startOffset - 2])
}
Получить обычный текстовый контент
Использовать напрямуюtextContent
Нет, ты не можешь получить этоimg
Содержимое ярлыка, оно будет использоваться после добавленияbutton
илиinput[type=button]
Чтобы реализовать некоторые функции выделения, вам необходимо определить метод для самостоятельного получения текстового содержимого. Я реализовал это относительно просто
function getDomValue (elem) {
var res = ''
Array.from(elem.childNodes).forEach((child) => {
if (child.nodeName === '#text') {
res += child.nodeValue
} else if (child.nodeName === 'BR') {
res += '\n'
} else if (child.nodeName === 'BUTTON') {
res += getDomValue(child)
} else if (child.nodeName === 'IMG') {
res += child.alt
} else if (child.nodeName === 'DIV') {
res += '\n' + getDomValue(child)
}
})
return res
}
Заметки и перспективы
- Поле редактирования расширенного текста должно учитывать множество проблем XSS, фильтрацию меток при назначении и вставке и т. д.
- проблемы с совместимостью браузера,
range
операции с объектами разные,contenteditable
Проблемы со свойствами - Унифицируйте стиль вставляемого текста, иначе при вводе текста будет использоваться предыдущий стиль
- Проблемы совместимости браузера, отмеченные @user
благодарный
Я могу выполнить эту функцию, спасибо@Жареный рис июньс помощь. Отличная помощь во время стажировки.