在经过前端开发的一段时间学习,想必大家对于自适应有了不少的了解,那么今天我们继续来讲讲有关于:“在前端中textarea有几种高度自适应方法?”这方面的相关内容分享!下面是小编收集整理的相关内容希望对大家有所帮助!
阅读全文你将获得以下解决方案。
- 点击长文本编辑textarea,自动获得焦点
- 随着输入值自动伸缩高度
- 可复制添加信息
- 可粘贴文本
- 可粘贴图片
以下实例代码执行环境为Chrome80
方案一
HTML5 Textarea 元素
1. 自动获得焦点
点击编辑自动获得焦点后光标跳转到了最前面,why?
查文档 MDN,textarea
元素存在selectionEnd
和selectionStart
的属性用来表示选中的文本开始位置和结束位置,DOM接口实例是 HTMLTextAreaElement
, 它具有 setSelectionRange
方法,用来选中输入框中的文本,用法:TextAreaElement.setSelectionRange(selectionStart, selectionEnd, [optional] selectionDirection);
那么我们只要做到selectionStart === selectionEnd === value.length
, 这样光标就选中到最末尾。
edit.addEventListener("click", function() { | |
txt.classList.add("hidden"); | |
document.body.insertBefore(textarea, edit); | |
textarea.innerHTML = "这是需要编辑的信息"; | |
textarea.focus(); | |
// textarea.selectionEnd = textarea.innerHTML.length; | |
textarea.setSelectionRange( | |
textarea.innerHTML.length, | |
textarea.innerHTML.length | |
); | |
}); |
2. 自适应高度
当不设置高度时换行会出现滚动条,所以只要让textarea
滚动条消失,让其height = scrollHieght
, 那么如何监听textarea的变化,则需要input
事件,让textarea
高度动态等于它的scrollHeight
即可,代码如下:
textarea.addEventListener("input", function() { | |
this.style.height = `${this.scrollHeight}px`; | |
}); |
为什么每次输入都会使得高度增加(每次增加4px),经过测试Safari
同样也是这个效果,Firefox
符合预期高度不异常增加,查看Chrome控制台发现textarea
内置了很多样式,尝试将去掉padding
后,可以正常随着内容增加高度自适应了。
<style> | |
textarea { | |
padding: 0; | |
} | |
</style> | |
<textarea></textarea> | |
<script> | |
const textarea = document.createElement("textarea"); | |
textarea.addEventListener("input", function(e) { | |
this.style.height = `${this.scrollHeight}px`; | |
}); | |
</script> |
为什么去掉padding值,输入后高度就不增加了?(未找到合理的解释,欢迎留言讨论解答)
但是删除文本的情况下height
并未能自动缩放,分析原因, 当删除文本换行的时候scrollHeight
的大小并未发生改变,scrollHeight
作为只读属性( MDN-文档),如何让scrollHeight
高度重新计算哪?只有改变高度,于是:
textarea.addEventListener("input", function(e) { | |
this.style.height = "inherit"; | |
this.style.height = `${this.scrollHeight}px`; | |
}); |
到此高度自适应输入内容完成,但是每次换行的闪动很难受,transition
走一波,
textarea { | |
overflow: hidden; // 防止换行出现滚动条闪动 | |
padding: 5px 10px; | |
box-sizing: border-box; | |
transition: all 0.2s linear; | |
} |
结果transition
并没效果,原因height
初始值或者参考值必须为数值过渡动画才会生效,height
设置为auto
或者inherit
动画不会生效, 所以折中的办法就是当删除的时候重新重置高度,输入时不需要重置,这样输入时动画生效, 删除没有动画, 暂时没想到更好的办法。
textarea.addEventListener("keyup", function(e) { | |
if (e.keyCode === 8) { | |
this.style.height = "inherit"; | |
this.style.height = `${this.scrollHeight}px`; | |
} else { | |
this.style.height = `${this.scrollHeight}px`; | |
} | |
}); |
3. 支持粘贴文本,图片等
textarea只能输入文本,无法实现粘贴图片。
textarea.addEventListener( | |
"paste", | |
function(e) { | |
e.preventDefault(); | |
console.log( | |
"paste", | |
e.clipboardData.items, | |
e.clipboardData.types, | |
e.clipboardData.getData("text/html"), | |
e.clipboardData.getData("text/plain"), | |
e.clipboardData.getData("text/Files") | |
); | |
}, | |
false | |
); |
方案二
div contenteditable
替换textarea
1. 自动获得焦点
编辑div contenteditable
为true
,然后利用Range
和Selection
光标移动到最后的效果。
edit.addEventListener("click", () => { | |
textarea.setAttribute("contenteditable", true); | |
textarea.focus(); | |
const range = document.createRange(); | |
// range 包含的内容 range.selectNodeContents(textarea); | |
// range.setStart(textarea.firstChild, 0); // range.setStart(textarea.lastChild, textarea.innerHTML.length); | |
// 起始位置是否相同 range.collapse(false);const sel = window.getSelection(); | |
// 将所有的区域都从选区中移除。 | |
sel.removeAllRanges(); | |
// 一个区域(Range)对象将被加入选区。 | |
sel.addRange(range); | |
}); |
2. 自适应高度
div contenteditable
天然支持根据输入来自适应高度。
3. 粘贴图片, 文本等
textarea.addEventListener("paste", function(e) { | |
e.preventDefault(); | |
const clipboardData = e.clipboardData || e.originalEvent.clipboardData; | |
// 获取纯文本 let text = clipboardData.getData("text/plain");let file = clipboardData.getData("text/plain"); | |
// console.log(clipboardData.items, clipboardData.getData("text/Files")); | |
// 插入img,可以做一些上传图片的一些操作 insertImg(clipboardData); | |
// 只输入纯文本 document.execCommand("insertText", false, text); | |
}); |
此方法可以限定只能上传文本或者图片。
欢迎留言讨论其他textarea
高度自适应的方案。