input源码: (本文记录的是过程, 要想直接看最正确的代码, 划到最下面是完整的源码)
<!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>
/* 样式调整 */
.input-container {
display: flex;
align-items: center; /* 垂直居中对齐 */
}
#input {
/* flex: 1; *//* 输入框占据剩余空间 */
margin-right: 10px; /* 右侧留出一定的间隔 */
}
#counter {
font-size: 12px; /* 字号调整 */
}
.max-length-reached {
color: red; /* 计数器文字变成红色 */
}
</style>
</head>
<body>
<div class="input-container">
<input id="input" type="text" maxlength="30">
<div id="counter">0/30</div>
</div>
<script>
// 获取输入框和计数器的元素
const input = document.getElementById('input');
const counter = document.getElementById('counter');
const maxLength = parseInt(input.getAttribute('maxlength')); // 获取最大输入长度并转换为整数
// 监听输入框的输入事件
input.addEventListener('input', function() {
// 获取已输入的字数
const enteredLength = input.value.length;
// 更新计数器的文本内容
counter.textContent = `${enteredLength}/${maxLength}`;
// 如果已输入的字数达到最大限制,将计数器的颜色设为红色
if (enteredLength === maxLength) {
counter.classList.add('max-length-reached');
} else {
counter.classList.remove('max-length-reached');
}
});
</script>
</body>
</html>
运行结果:
textarea源码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Textarea Character Counter with Draggable Resizing</title>
<style>
.container {
position: relative;
width: 100%;
max-width: 280px; /* Adjust as needed */
}
#inputText {
width: 100%;
min-width: 280px; /* Minimum width to prevent shrinking */
height: 100px; /* Adjust initial height as needed */
min-height: 100px; /* Minimum height to prevent shrinking */
box-sizing: border-box;
padding: 10px;
font-size: 14px; /* Adjust font size as needed */
overflow: auto; /* Handle text overflow */
}
.counter {
position: absolute;
bottom: 10px;
right: 10px;
color: black;
font-size: 12px; /* Adjust font size as needed */
}
.counter.max {
color: red;
}
</style>
</head>
<body>
<div class="container">
<textarea id="inputText" rows="6" maxlength="150"></textarea>
<div id="charCount" class="counter">0/150</div>
</div>
<script>
const textArea = document.getElementById('inputText');
const charCount = document.getElementById('charCount');
const minWidth = 280; // Minimum width for the textarea
textArea.addEventListener('input', function() {
const textLength = textArea.value.length;
charCount.textContent = `${textLength}/150`;
if (textLength >= 150) {
charCount.classList.add('max');
} else {
charCount.classList.remove('max');
}
});
// Function to handle mousemove event for resizing
function handleResize(event) {
const mouseX = event.clientX;
const textareaRect = textArea.getBoundingClientRect();
const containerRect = textArea.parentNode.getBoundingClientRect();
let newWidth = mouseX - textareaRect.left;
// Ensure new width respects minimum width
if (newWidth < minWidth) {
newWidth = minWidth;
}
// Set new width to textarea
textArea.style.width = newWidth + 'px';
// Adjust counter position based on textarea width change
charCount.style.right = `${containerRect.right - textareaRect.right + 10}px`;
}
// Listen for mousedown event on textarea for starting resize
textArea.addEventListener('mousedown', function(event) {
if (event.offsetX > textArea.offsetWidth - 10) {
// Only start resize if mouse is near the right edge
document.addEventListener('mousemove', handleResize);
}
});
// Stop resizing on mouseup event
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', handleResize);
});
// Initial check on load
window.addEventListener('load', function() {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
});
</script>
</body>
</html>
运行效果:
完整源码:
/* 样式调整 */
/* .form-inline { */
/* display: flex; */
/* align-items: center; 垂直居中对齐 */
/* } */
#title {
/* flex: 1; *//* 输入框占据剩余空间 */
margin-right: 10px; /* 右侧留出一定的间隔 */
}
#counter {
font-size: 12px; /* 字号调整 */
display: contents;
}
.max-length-reached {
color: red; /* 计数器文字变成红色 */
}
.con {
display: flex;
}
/* .con label { */
/* margin-right: 0; */
/* } */
.containerTextarea {
position: relative;
width: 100%;
max-width: 280px;
/* Adjust as needed */
}
#alert {
width: 100%;
min-width: 280px;
/* Minimum width to prevent shrinking */
height: 100px;
/* Adjust initial height as needed */
min-height: 100px;
/* Minimum height to prevent shrinking */
box-sizing: border-box;
padding: 10px;
font-size: 14px;
/* Adjust font size as needed */
overflow: auto;
/* Handle text overflow */
}
.counter {
position: absolute;
bottom: 10px;
right: 10px;
color: black;
font-size: 12px;
/* Adjust font size as needed */
}
.counter.max {
color: red;
}
.selectClass {
width: 50px;
}
.inputDiv {
width: 620px;
}
.selectDiv {
padding-left: 114px;
}
.littleSelect {
padding-bottom: 10px;
}
<!-- 新修改 input 和 textarea -->
<div class="form-inline">
<label for="exampleInputEmail1">提示语</label>
<input maxlength="30" type="text" class="form-control" placeholder="非必填,最多30个字符" id="title">
<div id="counter">0/30</div>
</div>
<div class="form-inline">
<div class="con">
<label for="">推荐内容</label>
<div class="containerTextarea">
<textarea maxlength="150" name="" id="alert" cols="30" rows="5" class="isNull form-control"
placeholder="必填,最多150个字符"></textarea>
<div id="charCount" class="counter">0/150</div>
</div>
</div>
</div>
// input 和 textarea 逻辑
// input 和 textarea 逻辑
const input = document.getElementById('title');
const counter = document.getElementById('counter');
const maxInputChars = 30; // 最大字符数
input.addEventListener('input', function() {
let value = input.value;
let charCount = 0;
let index = 0;
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) > 255) {
charCount += 2; // 汉字计为两个字符
} else {
charCount++; // 英文计为一个字符
}
if (charCount <= maxInputChars) {
index = i + 1; // 记录合法字符数位置
}
}
if (charCount > maxInputChars) {
value = value.slice(0, index); // 截取到达限制前的字符位置
}
charCount = Math.min(charCount, maxInputChars); // 修正字符计数不超过最大限制
counter.textContent = `${charCount}/${maxInputChars}`;
// 根据是否超过或等于最大字符数添加或移除样式类
if (charCount >= maxInputChars) {
counter.classList.add('max-length-reached');
} else {
counter.classList.remove('max-length-reached');
}
input.value = value; // 更新输入框中的值
});
// 获取文本域和计数器的元素
const textArea = document.getElementById('alert');
const charCount = document.getElementById('charCount');
const minWidth = 280; // 最小宽度
textArea.addEventListener('input', function() {
const value = textArea.value;
let charCountValue = 0;
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) > 255) {
charCountValue += 2; // Chinese character
} else {
charCountValue++; // English character
}
}
charCount.textContent = `${charCountValue}/150`;
if (charCountValue >= 150) {
charCount.classList.add('max');
} else {
charCount.classList.remove('max');
}
});
function handleResize(event) {
const mouseX = event.clientX;
const textareaRect = textArea.getBoundingClientRect();
const containerRect = textArea.parentNode.getBoundingClientRect();
let newWidth = mouseX - textareaRect.left;
if (newWidth < minWidth) {
newWidth = minWidth;
}
textArea.style.width = newWidth + 'px';
charCount.style.right = `${containerRect.right - textareaRect.right + 10}px`;
}
textArea.addEventListener('mousedown', function(event) {
if (event.offsetX > textArea.offsetWidth - 10) {
document.addEventListener('mousemove', handleResize);
}
});
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', handleResize);
});
window.addEventListener('load', function() {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
});
运行效果:
拖拽后:
对于中英文标点符号的疑问:
输入框一个英文一个字符一个汉字两个字符,已经完成了,那么对于英文和汉语的标点需要加上相同的逻辑吗?还是不用修改统一按照一个标点一个字符呢?
回答:
对于英文和汉语的标点符号,通常应该按照一个标点一个字符的逻辑处理。在处理输入框中的字符时,无论是英文标点还是中文标点,都应该分别计算为一个字符,以保持统一性。
放在单独的html源码:
<!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>
/* 样式调整 */
/* .form-inline { */
/* display: flex; */
/* align-items: center; 垂直居中对齐 */
/* } */
.form-inline {
display: flex;
}
#title {
/* flex: 1; */
/* 输入框占据剩余空间 */
margin-right: 10px;
/* 右侧留出一定的间隔 */
}
#counter {
font-size: 12px;
/* 字号调整 */
display: contents;
}
.max-length-reached {
color: red;
/* 计数器文字变成红色 */
}
.con {
display: flex;
}
/* .con label { */
/* margin-right: 0; */
/* } */
label {
display: block;
width: 5rem;
}
.form-control {
padding-left: 10px;
}
.containerTextarea {
position: relative;
width: 100%;
max-width: 280px;
/* Adjust as needed */
}
#alert {
width: 100%;
min-width: 280px;
/* Minimum width to prevent shrinking */
height: 100px;
/* Adjust initial height as needed */
min-height: 100px;
/* Minimum height to prevent shrinking */
box-sizing: border-box;
padding: 10px;
font-size: 14px;
/* Adjust font size as needed */
overflow: auto;
/* Handle text overflow */
}
.counter {
position: absolute;
bottom: 10px;
right: 10px;
color: black;
font-size: 12px;
/* Adjust font size as needed */
}
.counter.max {
color: red;
}
.selectClass {
width: 50px;
}
.inputDiv {
width: 620px;
}
.selectDiv {
padding-left: 114px;
}
.littleSelect {
padding-bottom: 10px;
}
</style>
</head>
<body>
<div class="form-inline">
<label for="exampleInputEmail1">提示语</label>
<input maxlength="30" type="text" class="form-control" placeholder="非必填,最多30个字符" id="title">
<div id="counter">0/30</div>
</div>
<div class="form-inline">
<div class="con">
<label for="">推荐内容</label>
<div class="containerTextarea">
<textarea maxlength="150" name="" id="alert" cols="30" rows="5" class="isNull form-control"
placeholder="必填,最多150个字符"></textarea>
<div id="charCount" class="counter">0/150</div>
</div>
</div>
</div>
</body>
<script>
// input 和 textarea 逻辑
const input = document.getElementById('title');
const counter = document.getElementById('counter');
const maxInputChars = 30; // 最大字符数
input.addEventListener('input', function () {
let value = input.value;
let charCount = 0;
let index = 0;
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) > 255) {
charCount += 2; // 汉字计为两个字符
} else {
charCount++; // 英文计为一个字符
}
if (charCount <= maxInputChars) {
index = i + 1; // 记录合法字符数位置
}
}
if (charCount > maxInputChars) {
value = value.slice(0, index); // 截取到达限制前的字符位置
}
charCount = Math.min(charCount, maxInputChars); // 修正字符计数不超过最大限制
counter.textContent = `${charCount}/${maxInputChars}`;
// 根据是否超过或等于最大字符数添加或移除样式类
if (charCount >= maxInputChars) {
counter.classList.add('max-length-reached');
} else {
counter.classList.remove('max-length-reached');
}
input.value = value; // 更新输入框中的值
});
// 获取文本域和计数器的元素
const textArea = document.getElementById('alert');
const charCount = document.getElementById('charCount');
const minWidth = 280; // 最小宽度
const maxChars = 150; // 最大字符数
textArea.addEventListener('input', function () {
let value = textArea.value;
let charCountValue = countCharacters(value);
if (charCountValue > maxChars) {
const slicedValue = sliceText(value, maxChars);
textArea.value = slicedValue;
charCountValue = countCharacters(slicedValue);
}
charCount.textContent = `${charCountValue}/${maxChars}`;
if (charCountValue >= maxChars) {
charCount.classList.add('max');
} else {
charCount.classList.remove('max');
}
});
textArea.addEventListener('keydown', function (event) {
const value = textArea.value;
const charCountValue = countCharacters(value);
if (charCountValue >= maxChars && event.key !== 'Backspace' && event.key !== 'Delete') {
event.preventDefault();
}
});
function countCharacters(input) {
let count = 0;
for (let i = 0; i < input.length; i++) {
if (input.charCodeAt(i) > 255) {
count += 2; // 汉字
} else {
count++; // 英文
}
}
return count;
}
function sliceText(text, maxLength) {
let slicedText = '';
let charCount = 0;
for (let i = 0; i < text.length; i++) {
if (text.charCodeAt(i) > 255) {
charCount += 2; // 汉字
} else {
charCount++; // 英文
}
if (charCount <= maxLength) {
slicedText += text[i];
} else {
break;
}
}
return slicedText;
}
function handleResize(event) {
const mouseX = event.clientX;
const textareaRect = textArea.getBoundingClientRect();
const containerRect = textArea.parentNode.getBoundingClientRect();
let newWidth = mouseX - textareaRect.left;
if (newWidth < minWidth) {
newWidth = minWidth;
}
textArea.style.width = newWidth + 'px';
charCount.style.right = `${containerRect.right - textareaRect.right + 10}px`;
}
textArea.addEventListener('mousedown', function (event) {
if (event.offsetX > textArea.offsetWidth - 10) {
document.addEventListener('mousemove', handleResize);
}
});
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', handleResize);
});
window.addEventListener('load', function () {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
});
</script>
</html>
上述是完整的代码,
出现的问题:
问题:
现在textarea输入框输入英文和数字是正常的,但是输入汉字可以超过150个字符,请问哪里出了问题,一个英文字符是一个字符,一个汉字是两个字符
错误的代码片段和正确的代码片段:
// 获取文本域和计数器的元素
const textArea = document.getElementById('alert');
const charCount = document.getElementById('charCount');
const minWidth = 280; // 最小宽度
const maxChars = 150; // 最大字符数
textArea.addEventListener('input', function() {
const value = textArea.value;
let charCountValue = 0;
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) > 255) {
charCountValue += 2; // 汉字
} else {
charCountValue++; // 英文
}
}
charCount.textContent = `${charCountValue}/${maxChars}`;
if (charCountValue >= maxChars) {
charCount.classList.add('max');
// 截断文本,保证不超过150个字符
textArea.value = value.slice(0, maxChars);
charCount.textContent = `${maxChars}/${maxChars}`;
} else {
charCount.classList.remove('max');
}
});
textArea.addEventListener('keydown', function(event) {
const value = textArea.value;
const charCountValue = countCharacters(value);
// 当输入达到最大字符数时,阻止继续输入
if (charCountValue >= maxChars && event.key !== 'Backspace' && event.key !== 'Delete') {
event.preventDefault();
}
});
function countCharacters(input) {
let count = 0;
for (let i = 0; i < input.length; i++) {
if (input.charCodeAt(i) > 255) {
count += 2; // 汉字
} else {
count++; // 英文
}
}
return count;
}
function handleResize(event) {
const mouseX = event.clientX;
const textareaRect = textArea.getBoundingClientRect();
const containerRect = textArea.parentNode.getBoundingClientRect();
let newWidth = mouseX - textareaRect.left;
if (newWidth < minWidth) {
newWidth = minWidth;
}
textArea.style.width = newWidth + 'px';
charCount.style.right = `${containerRect.right - textareaRect.right + 10}px`;
}
textArea.addEventListener('mousedown', function(event) {
if (event.offsetX > textArea.offsetWidth - 10) {
document.addEventListener('mousemove', handleResize);
}
});
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', handleResize);
});
window.addEventListener('load', function() {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
});
// 获取文本域和计数器的元素
const textArea = document.getElementById('alert');
const charCount = document.getElementById('charCount');
const minWidth = 280; // 最小宽度
const maxChars = 150; // 最大字符数
textArea.addEventListener('input', function() {
let value = textArea.value;
let charCountValue = countCharacters(value);
if (charCountValue > maxChars) {
const slicedValue = sliceText(value, maxChars);
textArea.value = slicedValue;
charCountValue = countCharacters(slicedValue);
}
charCount.textContent = `${charCountValue}/${maxChars}`;
if (charCountValue >= maxChars) {
charCount.classList.add('max');
} else {
charCount.classList.remove('max');
}
});
textArea.addEventListener('keydown', function(event) {
const value = textArea.value;
const charCountValue = countCharacters(value);
if (charCountValue >= maxChars && event.key !== 'Backspace' && event.key !== 'Delete') {
event.preventDefault();
}
});
function countCharacters(input) {
let count = 0;
for (let i = 0; i < input.length; i++) {
if (input.charCodeAt(i) > 255) {
count += 2; // 汉字
} else {
count++; // 英文
}
}
return count;
}
function sliceText(text, maxLength) {
let slicedText = '';
let charCount = 0;
for (let i = 0; i < text.length; i++) {
if (text.charCodeAt(i) > 255) {
charCount += 2; // 汉字
} else {
charCount++; // 英文
}
if (charCount <= maxLength) {
slicedText += text[i];
} else {
break;
}
}
return slicedText;
}
function handleResize(event) {
const mouseX = event.clientX;
const textareaRect = textArea.getBoundingClientRect();
const containerRect = textArea.parentNode.getBoundingClientRect();
let newWidth = mouseX - textareaRect.left;
if (newWidth < minWidth) {
newWidth = minWidth;
}
textArea.style.width = newWidth + 'px';
charCount.style.right = `${containerRect.right - textareaRect.right + 10}px`;
}
textArea.addEventListener('mousedown', function(event) {
if (event.offsetX > textArea.offsetWidth - 10) {
document.addEventListener('mousemove', handleResize);
}
});
document.addEventListener('mouseup', function() {
document.removeEventListener('mousemove', handleResize);
});
window.addEventListener('load', function() {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
});
分析一下为什么:
- 第一段代码在
input
事件中,当字符数超过最大限制时直接使用slice
方法截断文本,但未考虑汉字的双字节问题,导致截断不准确。 - 第二段代码引入了
sliceText
函数,在input
事件中判断字符数是否超过最大限制后,调用sliceText
函数来准确地截取文本,确保不会出现截断错误的情况 - 第一段代码���通过字符数来判断是否超过限制,而没有考虑汉字的双字节字符,导致截取位置不准确。
- 第二段代码在
sliceText
函数中精确计算字符数,根据字符数进行准确的截取操作,确保不会出现截断错误的情况 - 第二段代码在
keydown
事件中也进行了字符数的判断和处理,以防止用户继续输入超过限制的字符
Math.min
(xxx, xxx) 解释:
这段代码的作用是确保
charCount
变量的值不超过指定的最大字符限制maxInputChars
。让我们逐步解释:
charCount = Math.min(charCount, maxInputChars);
Math.min(charCount, maxInputChars)
:这个语句使用Math.min
函数来比较charCount
和maxInputChars
两者的值,并返回较小的那个值。
charCount
:是之前计算得到的字符个数。
maxInputChars
:是一个预先设定的最大允许输入字符数。因此,这行代码的效果是,将
charCount
的值修正为不超过maxInputChars
。如果charCount
的计算结果超过了maxInputChars
,则charCount
将被设定为maxInputChars
,以确保输入的字符数不会超过预定的限制
charCodeAt疑问:
if (value.charCodeAt(i) > 255) {
charCount += 2; // 汉字计为两个字符
}这段代码什么意思
回答:
这段代码是在计算字符串中字符的个数,特别是对于汉字的处理。让我们逐行解释:
if (value.charCodeAt(i) > 255) {
charCount += 2; // 汉字计为两个字符
}
-
value.charCodeAt(i)
:这个方法是获取字符串value
中索引为i
的字符的 Unicode 编码值。 -
if (value.charCodeAt(i) > 255)
:这个条件判断语句检查当前字符的 Unicode 编码值是否大于 255。在许多字符编码中,包括常见的字符集(如 ASCII 和 Latin-1),255 是一个界限,超过这个值通常意味着字符可能是非常用字符或者非拉丁字母。 -
charCount += 2;
:如果当前字符的 Unicode 编码值大于 255,那么charCount
变量会增加 2。这是因为作者假设超过 255 的字符是汉字或者其他双字节字符,例如日文、韩文等,这些字符在计算长度时通常算作两个字符长度。
因此,这段代码的作用是遍历字符串 value
,检查每个字符的 Unicode 编码值是否大于 255,如果是,则将 charCount
增加 2,以便正确计算包含汉字或其他双字节字符的字符串的字符个数。
上述代码放在新建页面是没问题的, 但是放在编辑页面会出现问题, 当编辑的情况下,进入编辑页面input和textarea里面已经有后端传回的文字了,但是输入框没有进行计数,怎么解决?
在上面代码的最下面的window.addEventListener('load', function() {函数中增加一段代码:
整体为:
window.addEventListener('load', function() {
const currentWidth = textArea.clientWidth;
if (currentWidth < minWidth) {
textArea.style.width = minWidth + 'px';
}
// // 手动触发一次输入框的 input 事件来初始化字符计数
// input.dispatchEvent(new Event('input'));
// textArea.dispatchEvent(new Event('input'));
setTimeout(function() {
input.dispatchEvent(new Event('input'));
textArea.dispatchEvent(new Event('input'));
}, 100); // 100ms 延迟
});
将这段代码更新后, 编辑页面的输入框就可以正常的进入界面实时更新当前input和textarea中的文字个数了,
以下是chatGPT的回答:
根据你描述的情况,你希望页面加载完成后自动触发输入框的 `input` 事件来初始化字符计数,但目前在进入界面后并没有显示计数,需要手动刷新页面才能看到计数。这可能是因为你的事件监听器绑定顺序或者页面加载时机不够理想所致。
让我们来逐步检查可能的解决方案:
1. **确保事件监听器的绑定顺序正确:**确保在给 `input` 和 `textArea` 元素添加 `input` 事件监听器之前,这些元素已经在DOM中正确地加载和获取。你的代码中已经使用了 `window.addEventListener('load', function() { ... })` 来确保页面加载完成后执行,这是一个不错的做法。但需要确保事件监听器的绑定在这之后。
2. **手动触发 `input` 事件的位置:**你在 `window` 的 `load` 事件处理程序中手动触发了 `input` 事件,这本应该有效。但有时候,可能需要稍微延迟触发事件,以确保其他初始化任务已完成。你可以尝试使用 `setTimeout` 来稍微延迟触发事件,例如:
window.addEventListener('load', function() {
setTimeout(function() {
input.dispatchEvent(new Event('input'));
textArea.dispatchEvent(new Event('input'));
}, 100); // 100ms 延迟
});
这样做可以确保在所有初始化操作完成后再触发 `input` 事件,确保计数器能正确显示。
3. **检查控制台错误信息:**打开浏览器的开发者工具(通常是按 F12 键),切换到控制台标签,查看是否有任何错误消息。可能的错误消息会给出一些线索,帮助你理解为何计数器没有正确显示。
通过这些步骤,你应该能够更好地理解问题所在,并找到解决办法,使计数器在页面加载后自动显示正确的字符计数。