textarea 在开发中常常被使用到,但默认的 textarea 效果并不能满足我们的需求,比如信息发送框,如果直接使用 input 的话,在长文本内容中会显得十分拥挤,如果直接使用 textarea 则在未填充内容时显得过于空旷,因此我们需要自定义 textarea 的样式,使其在未填充内容时也能保持一定的宽度,同时也能在长文本内容中自动换行并调整高度。效果如下:
这里主要通过监听 textarea 的 input 事件,从而获取 textarea 的内容区域高度,从而调整 textarea 的高度,实现文本内容超出宽度时高度调整的效果。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {padding: 0;margin: 0;box-sizing: border-box;}
textarea {outline: none;border: none;resize: none;line-height: 20px;font-size: 14px;font-family: SF Pro Display, -apple-system, BlinkMacSystemFont, Segoe UI, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Helvetica Neue, Helvetica, Arial, sans-serif;}
button.send {margin-left: 12px;font-size: 14px;font-weight: bold;transition: all .6s;color: #c6c6cd;outline: none;border: 0;background-color: unset;cursor: pointer;}
button.send:hover {color: #4d53e8;}
.textarea-with-top-rows {position: fixed;left: 50%;top: 50%;transform: translateX(-50%) translateY(-50%);}
.textarea-with-top-rows {width: 548px;min-height: 48px;padding: 12px 12px 12px 16px;border: 1px solid #ccc;border-radius: 24px;display: flex;align-items: center;}
.textarea-with-top-rows.input-focus {border-color: #4d53e8;}
.textarea-with-top-rows textarea {flex: 1;padding: 2px;overflow-y: hidden;}
.textarea-with-top-rows textarea::selection {background-color: #d0d2fb;}
.textarea-with-top-rows textarea::placeholder {color: #ccc;}
</style>
</head>
<body>
<div class="textarea-with-top-rows">
<textarea style="min-height: 24px;height: 24px;" placeholder="发送消息..."></textarea>
<button type="button" class="send">发送</button>
</div>
<script>
const textareaWithTopRows = document.querySelector('.textarea-with-top-rows');
const textareaWithInput = document.querySelector('.textarea-with-top-rows textarea');
const textareaWithSend = document.querySelector('.textarea-with-top-rows .send');
// 最多显示的行数
const rows = 6;
// 基础高度
const baseHeight = 24;
// 每行高度
const lineHeight = 20;
const handlerTextAreaSend = function () {
textareaWithInput.value = '';
// 重新处理高度
handlerTextAreaInput.apply(textareaWithInput);
}
// 监听 textarea 的输入事件
const handlerTextAreaInput = function () {
this.style.height = `${baseHeight}px`;
const scrollHeight = this.scrollHeight;
const height = scrollHeight - baseHeight;
const row = Math.ceil(height / lineHeight);
if (row >= rows) {
this.style.height = `${rows * lineHeight + lineHeight}px`;
return;
}
this.style.height = `${scrollHeight}px`;
}
// textarea 聚焦事件
const handlerTextAreaFocus = function () {
textareaWithTopRows.classList.add('input-focus');
}
// textarea 失焦事件
const handlerTextAreaBlur = function () {
textareaWithTopRows.classList.remove('input-focus');
}
textareaWithSend.addEventListener('click', handlerTextAreaSend);
textareaWithInput.addEventListener('input', handlerTextAreaInput);
textareaWithInput.addEventListener('focus', handlerTextAreaFocus);
textareaWithInput.addEventListener('blur', handlerTextAreaBlur);
textareaWithInput.addEventListener('change', handlerTextAreaInput);
</script>
</body>
</html>
知识点:
textarea标签的样式操作
- resize: none; 禁用textarea的拖拽
- outline: none; 去除textarea的轮廓
- ::placeholder 伪元素调整textarea中的占位符样式
- ::selection 伪元素调整textarea中选中文本时的样式
通过
input
事件监听 textarea 内容变化- input事件: 输入数据时触发,比如键盘输入、粘贴操作或者拖放内容等。
通过 textarea 的
scrollHeight
属性获取 textarea 的高度- scrollHeight: 获取元素的内容区域的总高度,包括由于溢出而不可见的部分。它是一个只读属性,返回一个以像素为单位的整数值。
步骤:
- 基本 html 结构以及 css 样式搭建
- 通过 input 事件监听 textarea 内容变化
2.1 通过 scrollHeight 属性获取内容区域高度,从而调整 textarea 高度
2.2 获取内容区域高度前对 textarea 高度进行初始化,如果没有此步骤则无法在文本区域缩小时进行同步调整 textarea 高度
问题:
输入内容如何再文本内容超过 textarea 宽度时进行换行
- 解决:通过 input 事件监听 textarea 内容变化,并通过 scrollHeight 进行调整 textarea 的高度,从而实现文本内容超出宽度时高度调整的效果。
当 textarea 高度有所增高时删除文本内容高度并不会降低
- 解决:在获取文本内容高度之前对 textarea 高度进行初始化
测试:
- 普通长文本输入时自动换行并自动调整 textarea 高度
- 执行 Enter 键时换行并自动调整 textarea 高度
- 复制长内容时换行并自动调整 textarea 高度
- 删除文本内容时自动调整 textarea 高度