假设我添加了一个长度为50px的文本框,并且我想计算出完全适合该文本框的字符(包括空格)的确切数量,我的意思是不允许在文本框内键入任何字符需要整条线向左滑动;我的意思是,换句话说,当行达到文本框的长度时,我们需要禁止打字员进一步插入任何字母。我们可以通过JavaScrip解决这个问题吗?感谢您的事先帮助,我们将不胜感激。
答案 0 :(得分:3)
整个逻辑是有缺陷的,因为它还取决于输入中文本的大小。我会输入一个不能超过的字符数限制。使用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>
答案 1 :(得分:3)
正如@ mel-macaluso正确指出的那样,这是一个非常大的兔子漏洞,标准做法是使用maxlength属性来限制字符数。
*编辑:您也可以使用em来设置input
的宽度,该宽度与字体大小成比例。 (名称em最初是指所用字体和大小的大写字母M的宽度,通常与磅值ref相同)。em
和{ {1}}会大致估算出您可能要达到的目标。
但是,如果您真的希望能够限制基于输入的文本长度,那么这将作为开始的非常简化示例。
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();
}
})
那么为什么做这样的事情为什么这么复杂?字体是棘手的事情。您有variable width (proportional) fonts,kerning,ligatures等。这非常复杂,浏览器不提供对大多数此类信息的访问。
因此,如果您想知道一段文本的长度,通常必须将其放在具有相同字体设置的跨度中,然后请求边界尺寸。
答案 2 :(得分:2)
这是使用嵌套范围(内部范围为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>