假设我添加了一个长度为50px的文本框,并且我想计算完全适合该文本框内的确切字符数(包括空格),我的意思是不应该允许在需要该文本框的文本框中键入字符整条线向左滑动;我的意思是,在另一个词中,我们需要禁止打字员进一步插入任何字母,因为该行达到文本框的长度。我们能用JavaScrip解决这个问题吗?感谢您的帮助,任何帮助将不胜感激。
整个逻辑是有缺陷的,因为它还取决于输入内部文本的大小。相反,我会输入一个不超出的字符限制。使用maxlength
输入属性。
无论如何,如果你真的想走这条路线,我认为这是一种矫枉过正而且不需要,那么你可以:
CanvasRenderingContext2D.measureText
,docs here查找附加的示例代码段,未优化,我正在谈论的内容。
const form = document.querySelector('#form'),
input = form.querySelector('input')
const createAppendCanvas = form => {
const canvas = document.createElement('Canvas')
form.appendChild(canvas)
}
createAppendCanvas(form)
const getTextMetrics = inputText => {
const canvas = document.querySelector('canvas'),
textWidth = Math.ceil(canvas.getContext('2d').measureText(inputText).width) + 10
return textWidth
}
const disableTyping = (event, input) => {
const inputText = event.target.value,
inputWidth = input.clientWidth
if (getTextMetrics(inputText) >= inputWidth) {
event.preventDefault()
return false
}
}
input.addEventListener('keypress', event => disableTyping(event, input))
input {
width: 50px;
}
canvas {
display: none;
}
<form id="form">
<input type="text" />
</form>
正如@ mel-macaluso正确指出的那样,这是一个非常大的兔子洞,标准做法是使用maxlength属性来限制字符数。
*编辑:您还可以使用input
设置em的宽度,该宽度与字体大小成比例。 (名称em最初是对使用的字体和大小的大写字母M的宽度的引用,它通常与点大小ref相同)em
和maxlength
中的宽度组合将给出非常粗略的近似值你可能想要实现。
但是,如果您真的希望能够限制基于输入的文本长度,那么这将是一个非常简单的示例,说明如何开始。
getBoundingClientRect
.首先是一些免责声明:
getBoundingClientRect
的过程会强制浏览器重新加载文档内容。根据页面的大小,这可能是一个大问题,而且不是轻易做的事情。var inp = document.getElementById('test');
// get font for input
var style = getComputedStyle(inp);
var maxWidth = inp.getBoundingClientRect().width;
var sizeTest = document.createElement('span');
// set font for span to match input
sizeTest.style.font = style.font;
inp.addEventListener('keydown', function(e){
if(e.ctrlKey || e.altKey) return;
if(e.key && e.key.length===1) {
sizeTest.textContent = inp.value;
document.body.append(sizeTest);
var w = sizeTest.getBoundingClientRect().width;
sizeTest.remove();
console.log(maxWidth, w, e.key, e.code);
if(w>maxWidth) e.preventDefault();
}
})
<input id='test'/>
那么为什么做这样的事情会如此复杂呢?字体是棘手的事情。你有variable width (proportional) fonts,kerning,ligatures等。它非常复杂,浏览器无法访问大部分信息。
因此,如果您想知道一段文本的长度,通常必须将其放在具有相同字体设置的范围内,然后请求边界尺寸。
这是使用嵌套跨度(带有contenteditable
内跨)作为代理输入的简洁解决方案。
// Identifiers and dynamic styling
const innerSpan = document.querySelector("span.inner"),
outerSpan = document.querySelector("span.outer");
/* Threshold should be at least one character-width less than outerSpan.
(This formula was pretty close for my few tests;
for more precision and less flexibility, you can hard-code a value.) */
const estMaxCharWidth = innerSpan.offsetHeight / 1.7,
thresholdWidth = outerSpan.offsetWidth - estMaxCharWidth;
innerSpan.style.minWidth = `${Math.floor(thresholdWidth)-3}px`; // defaults to 0
innerSpan.style.minHeight = `${Math.floor(outerSpan.offsetHeight)-2}px`
// Listeners
innerSpan.addEventListener("focus", customOutline);
innerSpan.addEventListener("keydown", checkKeyAndWidth);
innerSpan.addEventListener("blur", removeOutlineAndHandleText);
// Functions
function checkKeyAndWidth(e){
// Runs when user presses a key, Conditionally prevents input
if(e.code == "Enter" || e.keyCode == 13){
e.preventDefault(); // Don't insert a new line
e.target.blur(); // (In production, set the focus to another element)
}
else{
// Some keys besides Enter are important, More could be added
const whitelistCodes = ["Backspace", "Tab", "Escape", "ArrowLeft", "ArrowRight", "Insert", "Delete"];
const whitelistKeyCodes = [8,9,27,37,39,45,46];
// If the inner span is wide enough, stop accepting characters
let acceptingCharacters = e.target.offsetWidth <= thresholdWidth;
if(!acceptingCharacters && !whitelistCodes.includes(e.code) && !whitelistKeyCodes.includes(e.keyCode) && !whitelistKeyCodes.includes(e.which)){
// Unauthorized incoming keystroke
e.preventDefault();
}
}
}
function customOutline(){
// Runs when span gets focus, Needed for accessibility due to CSS settings
outerSpan.style.borderColor = "DeepSkyBlue";
}
function removeOutlineAndHandleText(){
// Runs when focus is lost
outerSpan.style.borderColor = "Gray";
if(innerSpan.length < 1){ innerSpan.innerHTML = " "; } // force content
/* Since this is not a real input element, now might be the time to do something with the entered text */
}
.outer{
display: inline-block;
position: relative;
width: 100px; /* Defaults to 0 */
padding: 0;
border: 1px solid gray;
}
.inner{
display: inline-block;
position: relative;
top: 0;
height: 100%;
margin: 0;
outline: none; /* Don't do this without calling customOutline on focus */
}
<!-- requires that browser supports `contenteditable` -->
<span class="outer">
<!-- space character in innerSpan may improve cross-browser rendering -->
<span class="inner" contenteditable="true"> </span>
</span>