我最近需要在 HTML 输入字段中强制使用正确的大小写。 CSS Text-Transform:大写为 90%,但没有小写多个大写。所以我写了下面的Javascript。
令我惊讶的是,您会看到自动完成输入(用户单击自动完成选项之一)会导致失去任何“键”属性的 keyup 和 keydown 事件:-( 正如您在代码中也可以看到的,我必须在事件中搜索“密钥”,如果它不存在,我认为它是自动完成的。
有更好/有记录的方法吗?自动完成肯定更像是“粘贴”事件吗?有人有规范的指示吗?
<!DOCTYPE html>
<html>
<head>
<script type="application/javascript">
'use strict';
document.addEventListener("DOMContentLoaded", isDOMIsGood);
function isDOMIsGood()
{
// Handle autocomplete
document.body.addEventListener('keyup',
(e) => {
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
if ("key" in e) // not autocomplete
return true;
e.target.value = e.target.value.toLowerCase();
return true;
}
);
// Handle normal keyboard input
document.body.addEventListener('keydown',
(e) => {
const WORD_DELIMS = ".,& -:"; // Needs work
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT")
return true;
if (!("key" in e)) // autocomplete
return true;
if (e.key.length > 1 ||
e.altKey ||
e.ctrlKey ||
e.isComposing ||
e.metaKey ||
e.target.value.length == 0 ||
e.target.selectionStart == 0 ||
e.key > "Z" ||
e.key < "A" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
) ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
WORD_DELIMS.indexOf(e.target.value.substr(e.target.selectionStart - 1, 1)) != -1)
return true;
let cursorPos = e.target.selectionStart;
e.target.value = e.target.value.substring(0, cursorPos) +
String.fromCharCode(e.key.charCodeAt(0) + 32) +
e.target.value.substring(cursorPos);
e.target.selectionStart = ++cursorPos;
e.target.selectionEnd = cursorPos;
e.preventDefault();
e.stopPropagation();
return false;
}
);
// Handle paste
document.body.addEventListener("paste",
(e) => {
const WORD_DELIMS = ".,& -:"; // Needs work
if (e.target.tagName.toUpperCase() != "INPUT" ||
e.target.type.toUpperCase() != "TEXT" ||
getComputedStyle(e.target).textTransform.toUpperCase()
!= "CAPITALIZE" ||
(
"transform" in e.target.dataset &&
e.target.dataset.transform.toLowerCase()
== "standard"
))
return true;
let paste = (e.clipboardData || window.clipboardData).getData('text');
if (paste.length == 0)
return true;
e.target.value = (e.target.value.substring(0, e.target.selectionStart) +
paste + e.target.value.substring(e.target.selectionStart)).toLowerCase();
e.preventDefault();
e.stopPropagation();
return true;
}
);
// Allow the user, config file, etc set the enforcement level
document.getElementById("properRules").addEventListener("click",
(e) => {
if (e.target.tagName.toLowerCase() == "input" &&
e.target.type.toLowerCase() == "radio" &&
e.target.name == "properCase")
{
var enhanced = document.getElementById("enhanced");
enhanced.dataset.transform = e.target.value;
if (enhanced.dataset.transform == "none")
enhanced.style.textTransform = "none";
else
enhanced.style.textTransform = "capitalize";
}
return true;
}
);
}
</script>
<style type="text/css">
input[type=radio]:checked {
accent-color: lightblue;;
}
</style>
</head>
<body>
<h1>Supplementing CSS Text-Transform: Capitalize</h1>
<h2>How to enforce "Proper Case" on HTML input?</h2>
<p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p>
<div id="outer">
<div>
<label for="enhanced">Enhanced Capitalize:</label>
<input id="enhanced" type="text" style="text-transform: capitalize; background-color: lightblue;"
autocomplete="new-password" autofocus spellcheck="false" >
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" enforcement level:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked >
<label for="pc1">Strict</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">Relaxed</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">None</label><br>
</div>
</div>
</body>
</html>
以下是无需更改 html 即可完成此操作的方法。但我建议更好的方法是为用户提供输入或粘贴文本的输入,以及根据单选按钮选择转换文本的输出。
HTML
<h1>Supplementing CSS Text-Transform: Capitalize</h1>
<h2>How to enforce "Proper Case" on HTML input?</h2>
<p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p>
<div id="outer">
<div>
<label for="enhanced">Enhanced Capitalize:</label>
<input id="enhanced" type="text" style="background-color: lightblue;" autocomplete="new-password" autofocus spellcheck="false">
<button id="copy">Copy</button>
<br><br>
</div>
<div id="properRules">
<p>"Proper Case" enforcement level:</p>
<input type="radio" id="pc1" name="properCase" value="strict" checked=checked>
<label for="pc1">Strict</label><br>
<input type="radio" id="pc2" name="properCase" value="standard">
<label for="pc2">Relaxed</label><br>
<input type="radio" id="pc3" name="properCase" value="none">
<label for="pc3">None</label><br>
</div>
</div>
CSS
input[type=radio]:checked {
accent-color: lightblue;
}
.capitalize {
text-transform: capitalize;
}
JS
const textCopy = document.getElementById("copy");
const textInput = document.getElementById("enhanced");
const radioStrict = document.getElementById("pc1");
const radioRelaxed = document.getElementById("pc2");
const radioNone = document.getElementById("pc3");
textCopy.addEventListener('click', () => {
textInput.select();
const range = document.getSelection();
const value = range.toString();
navigator.clipboard.writeText( value );
console.log( value );
alert( value );
});
textInput.addEventListener('input', () => {
if (radioStrict.checked) {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
return true;
}
if (radioRelaxed.checked) {
textInput.classList.add('capitalize');
return true;
}
if (radioNone.checked) {
textInput.classList.remove('capitalize');
return true;
}
});
radioStrict.addEventListener('input', () => {
textInput.value = textInput.value.toLowerCase();
textInput.classList.add('capitalize');
});
radioRelaxed.addEventListener('input', () => {
textInput.classList.add('capitalize');
});
radioNone.addEventListener('input', () => {
textInput.classList.remove('capitalize');
});