नोट: कीकोड को अब हटा दिया गया है।
यदि आप अवधारणा को समझें तो मल्टीपल कीस्ट्रोक का पता लगाना आसान है
जिस तरह से मैं यह करता हूं वह इस प्रकार है:
var map = {}; // You could also use an array
onkeydown = onkeyup = function(e){
e = e || event; // to deal with IE
map[e.keyCode] = e.type == 'keydown';
/* insert conditional here */
}
यह कोड बहुत सरल है: चूंकि कंप्यूटर केवल एक बार में एक कीस्ट्रोके से गुजरता है, इसलिए कई कुंजियों का ट्रैक रखने के लिए एक सरणी बनाई जाती है। तब सरणी का उपयोग एक बार में एक या अधिक कुंजियों की जांच के लिए किया जा सकता है।
बस समझाने के लिए, मान लीजिए कि आप प्रेस करते हैं Aऔर B, प्रत्येक keydown
उस घटना को आग लगाता है , जो map[e.keyCode]
मान के लिए सेट होती है e.type == keydown
, जो या तो सही या गलत का मूल्यांकन करती है । अब दोनों map[65]
और map[66]
पर सेट हैं true
। जब आप जाने देते हैं A
, तो keyup
घटना आग हो जाती है, जिसके कारण map[65]
(ए) के विपरीत परिणाम का निर्धारण करने के लिए एक ही तर्क होता है, जो अब झूठा है , लेकिन चूंकि map[66]
(बी) अभी भी "डाउन" है (यह कीप इवेंट को ट्रिगर नहीं किया है) यह सच है ।
map
सरणी, दोनों घटनाओं के माध्यम से, इस तरह दिखता है:
// keydown A
// keydown B
[
65:true,
66:true
]
// keyup A
// keydown B
[
65:false,
66:true
]
अब आप दो काम कर सकते हैं:
ए) एक कुंजी लकड़हारा ( उदाहरण ) बाद में एक संदर्भ के रूप में बनाया जा सकता है जब आप जल्दी से एक या अधिक कुंजी कोड का पता लगाना चाहते हैं। मान लें कि आपने एक HTML तत्व परिभाषित किया है और इसे चर के साथ इंगित किया है element
।
element.innerHTML = '';
var i, l = map.length;
for(i = 0; i < l; i ++){
if(map[i]){
element.innerHTML += '<hr>' + i;
}
}
नोट: आप आसानी से किसी तत्व को उसकी id
विशेषता से पकड़ सकते हैं ।
<div id="element"></div>
यह एक html तत्व बनाता है जिसे आसानी से जावास्क्रिप्ट में संदर्भित किया जा सकता है element
alert(element); // [Object HTMLDivElement]
तुम भी उपयोग document.getElementById()
या $()
इसे हड़पने के लिए नहीं है। लेकिन अनुकूलता के लिए, jQuery का उपयोग $()
अधिक व्यापक रूप से अनुशंसित है।
बस सुनिश्चित करें कि स्क्रिप्ट टैग HTML के शरीर के बाद आता है। ऑप्टिमाइज़ेशन टिप : अधिकांश बड़ी-नाम वाली वेबसाइट्स ऑप्टिमाइज़ेशन के लिए बॉडी टैग के बाद स्क्रिप्ट टैग लगाती हैं। इसका कारण यह है कि स्क्रिप्ट टैग आगे तत्वों को लोड होने से रोकता है जब तक कि इसकी स्क्रिप्ट डाउनलोड करना समाप्त नहीं हो जाती। इसे सामग्री के आगे रखने से सामग्री पहले से लोड करने की अनुमति मिलती है।
बी (जो आपकी रुचि निहित है) आप एक समय में एक या अधिक कुंजियों की जांच कर सकते /*insert conditional here*/
हैं कि यह कहां था, इसका उदाहरण लें:
if(map[17] && map[16] && map[65]){ // CTRL+SHIFT+A
alert('Control Shift A');
}else if(map[17] && map[16] && map[66]){ // CTRL+SHIFT+B
alert('Control Shift B');
}else if(map[17] && map[16] && map[67]){ // CTRL+SHIFT+C
alert('Control Shift C');
}
संपादित करें : यह सबसे पठनीय स्निपेट नहीं है। पठनीयता महत्वपूर्ण है, इसलिए आप इसे आंखों पर आसान बनाने के लिए कुछ इस तरह से आजमा सकते हैं:
function test_key(selkey){
var alias = {
"ctrl": 17,
"shift": 16,
"A": 65,
/* ... */
};
return key[selkey] || key[alias[selkey]];
}
function test_keys(){
var keylist = arguments;
for(var i = 0; i < keylist.length; i++)
if(!test_key(keylist[i]))
return false;
return true;
}
उपयोग:
test_keys(13, 16, 65)
test_keys('ctrl', 'shift', 'A')
test_key(65)
test_key('A')
क्या यह बेहतर है?
if(test_keys('ctrl', 'shift')){
if(test_key('A')){
alert('Control Shift A');
} else if(test_key('B')){
alert('Control Shift B');
} else if(test_key('C')){
alert('Control Shift C');
}
}
(संपादन का अंत)
यह उदाहरण , और CtrlShiftA, के लिए जाँच करता हैCtrlShiftBCtrlShiftC
यह बिल्कुल उसके जैसा सरल है :)
टिप्पणियाँ
KeyCodes का ट्रैक रखना
एक सामान्य नियम के रूप में, यह दस्तावेज़ कोड के लिए अच्छा अभ्यास है, विशेष रूप से कुंजी कोड (जैसे // CTRL+ENTER
) जैसी चीजें ताकि आप याद रख सकें कि वे क्या थे।
आपको दस्तावेज़ीकरण ( CTRL+ENTER => map[17] && map[13]
, नहीं map[13] && map[17]
) के समान कुंजी कोड भी उसी क्रम में रखना चाहिए । इस तरह आप कभी भी भ्रमित नहीं होंगे जब आपको वापस जाकर कोड को संपादित करने की आवश्यकता होगी।
If-चेन के साथ एक गोथा
यदि अलग-अलग मात्रा (जैसे CtrlShiftAltEnterऔर CtrlEnter) के कॉम्ब्स की जांच हो रही है, तो बड़े कॉम्ब्स के बाद छोटे कॉम्बोस डालें , या फिर छोटे कॉम्बोस बड़े कॉम्बोस को ओवरराइड करेंगे यदि वे समान हैं। उदाहरण:
// Correct:
if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
alert('Whoa, mr. power user');
}else if(map[17] && map[13]){ // CTRL+ENTER
alert('You found me');
}else if(map[13]){ // ENTER
alert('You pressed Enter. You win the prize!')
}
// Incorrect:
if(map[17] && map[13]){ // CTRL+ENTER
alert('You found me');
}else if(map[17] && map[16] && map[13]){ // CTRL+SHIFT+ENTER
alert('Whoa, mr. power user');
}else if(map[13]){ // ENTER
alert('You pressed Enter. You win the prize!');
}
// What will go wrong: When trying to do CTRL+SHIFT+ENTER, it will
// detect CTRL+ENTER first, and override CTRL+SHIFT+ENTER.
// Removing the else's is not a proper solution, either
// as it will cause it to alert BOTH "Mr. Power user" AND "You Found Me"
गोत्चा: "यह कुंजी कॉम्बो तब भी सक्रिय रहता है जब मैं चाबियाँ दबा नहीं रहा हूं"
अलर्ट या कुछ भी जो मुख्य विंडो से ध्यान केंद्रित करता है, के साथ काम करते समय, आप map = []
हालत को पूरा करने के बाद सरणी को रीसेट करने के लिए शामिल करना चाह सकते हैं । ऐसा इसलिए है क्योंकि कुछ चीजें, जैसे alert()
, मुख्य विंडो से ध्यान हटाएं और 'कीअप' इवेंट को ट्रिगर न करने का कारण बनें। उदाहरण के लिए:
if(map[17] && map[13]){ // CTRL+ENTER
alert('Oh noes, a bug!');
}
// When you Press any key after executing this, it will alert again, even though you
// are clearly NOT pressing CTRL+ENTER
// The fix would look like this:
if(map[17] && map[13]){ // CTRL+ENTER
alert('Take that, bug!');
map = {};
}
// The bug no longer happens since the array is cleared
गोटचा: ब्राउज़र डिफॉल्ट्स
यहाँ एक कष्टप्रद बात मुझे मिली, जिसमें समाधान शामिल है:
समस्या: चूंकि ब्राउज़र में आमतौर पर कुंजी कॉम्बोस पर डिफ़ॉल्ट क्रियाएं होती हैं (जैसे CtrlDबुकमार्क विंडो को सक्रिय करता है, या CtrlShiftCमैक्सथन पर स्किनोट को सक्रिय करता है), तो आप return false
बाद में भी जोड़ना चाह सकते हैं map = []
, इसलिए "डुप्लिकेट फ़ाइल" होने पर आपकी साइट के उपयोगकर्ता निराश नहीं होंगे। फ़ंक्शन, पर डाला जा रहा है CtrlD, इसके बजाय पृष्ठ को बुकमार्क करता है।
if(map[17] && map[68]){ // CTRL+D
alert('The bookmark window didn\'t pop up!');
map = {};
return false;
}
बिना return false
, बुकमार्क विंडो उपयोगकर्ता के विघटन के लिए पॉप अप होगी ।
रिटर्न स्टेटमेंट (नया)
ठीक है, इसलिए आप हमेशा उस बिंदु पर फ़ंक्शन से बाहर नहीं निकलना चाहते हैं। इसलिए event.preventDefault()
फंक्शन है। यह जो करता है वह एक आंतरिक ध्वज सेट करता है जो दुभाषिया को बताता है ब्राउज़र को अपनी डिफ़ॉल्ट कार्रवाई चलाने की अनुमति नहीं देता है। उसके बाद, फ़ंक्शन का निष्पादन जारी रहता है (जबकि return
तुरंत फ़ंक्शन से बाहर निकल जाएगा)।
उपयोग करने का निर्णय लेने से पहले इस भेद को समझें return false
याe.preventDefault()
event.keyCode
पदावनत किया गया है
उपयोगकर्ता SeanVieira को उन टिप्पणियों में इंगित किया गया है जो event.keyCode
पदावनत है।
वहां, उन्होंने एक उत्कृष्ट विकल्प दिया: event.key
जो कुंजी के एक स्ट्रिंग प्रतिनिधित्व को दबाता है, जैसे "a"
कि A, या"Shift"
के लिए Shift।
मैं आगे बढ़ा और एक उपकरण पकाया कहा कि स्ट्रिंग्स की जांच के लिए किया।
element.onevent
बनाम element.addEventListener
के साथ पंजीकृत संचालकों को addEventListener
ढेर किया जा सकता है, और पंजीकरण के क्रम में कहा जाता है, जबकि .onevent
सीधे सेट करना आक्रामक है और आपके पास पहले से कुछ भी ओवरराइड करता है।
document.body.onkeydown = function(ev){
// do some stuff
ev.preventDefault(); // cancels default actions
return false; // cancels this function as well as default actions
}
document.body.addEventListener("keydown", function(ev){
// do some stuff
ev.preventDefault() // cancels default actions
return false; // cancels this function only
});
.onevent
संपत्ति सब कुछ और के व्यवहार को ओवरराइड करने लगता है ev.preventDefault()
और return false;
नहीं बल्कि अप्रत्याशित हो सकते हैं।
या तो मामले में, के माध्यम से पंजीकृत संचालकों addEventlistener
को लिखना आसान लगता है और इसके बारे में कारण।
भी है attachEvent("onevent", callback)
इंटरनेट एक्सप्लोरर के गैर मानक कार्यान्वयन से है, लेकिन इस पदावनत से परे है और यहां तक कि जावास्क्रिप्ट (यह कहा जाता है एक गूढ़ भाषा से संबंधित है से संबंधित नहीं है JScript )। जितना हो सके पॉलीग्लॉट कोड से बचना आपके हित में होगा।
एक सहायक वर्ग
भ्रम / शिकायतों को दूर करने के लिए, मैंने एक "वर्ग" लिखा है जो इस अमूर्तता को करता है ( pastebin लिंक ):
function Input(el){
var parent = el,
map = {},
intervals = {};
function ev_kdown(ev)
{
map[ev.key] = true;
ev.preventDefault();
return;
}
function ev_kup(ev)
{
map[ev.key] = false;
ev.preventDefault();
return;
}
function key_down(key)
{
return map[key];
}
function keys_down_array(array)
{
for(var i = 0; i < array.length; i++)
if(!key_down(array[i]))
return false;
return true;
}
function keys_down_arguments()
{
return keys_down_array(Array.from(arguments));
}
function clear()
{
map = {};
}
function watch_loop(keylist, callback)
{
return function(){
if(keys_down_array(keylist))
callback();
}
}
function watch(name, callback)
{
var keylist = Array.from(arguments).splice(2);
intervals[name] = setInterval(watch_loop(keylist, callback), 1000/24);
}
function unwatch(name)
{
clearInterval(intervals[name]);
delete intervals[name];
}
function detach()
{
parent.removeEventListener("keydown", ev_kdown);
parent.removeEventListener("keyup", ev_kup);
}
function attach()
{
parent.addEventListener("keydown", ev_kdown);
parent.addEventListener("keyup", ev_kup);
}
function Input()
{
attach();
return {
key_down: key_down,
keys_down: keys_down_arguments,
watch: watch,
unwatch: unwatch,
clear: clear,
detach: detach
};
}
return Input();
}
यह वर्ग सब कुछ नहीं करता है और यह प्रत्येक बोधगम्य उपयोग के मामले को संभाल नहीं सकता है। मैं लाइब्रेरी का आदमी नहीं हूं। लेकिन सामान्य इंटरैक्टिव उपयोग के लिए यह ठीक होना चाहिए।
इस वर्ग का उपयोग करने के लिए, एक उदाहरण बनाएं और उस तत्व को इंगित करें जिसे आप कीबोर्ड इनपुट के साथ जोड़ना चाहते हैं:
var input_txt = Input(document.getElementById("txt"));
input_txt.watch("print_5", function(){
txt.value += "FIVE ";
}, "Control", "5");
यह क्या करेगा तत्व के साथ एक नया इनपुट श्रोता संलग्न करें #txt
(मान लें कि यह एक textarea है), और कुंजी कॉम्बो के लिए एक घड़ी सेट करें Ctrl+5
। जब दोनों Ctrl
और 5
नीचे होते हैं, तो आपके द्वारा पास किया गया कॉलबैक फ़ंक्शन (इस मामले में, एक फ़ंक्शन जो "FIVE "
टेक्सटेरिया में जोड़ता है) कहा जाएगा। कॉलबैक नाम के साथ जुड़ा हुआ है print_5
, इसलिए इसे हटाने के लिए, आप बस उपयोग करें:
input_txt.unwatch("print_5");
तत्व input_txt
से अलग करने के लिए txt
:
input_txt.detach();
इस तरह, कचरा संग्रह वस्तु को उठा सकता है ( input_txt
), इसे फेंक दिया जाना चाहिए, और आपके पास एक पुरानी ज़ोंबी इवेंट श्रोता नहीं होगी।
संपूर्णता के लिए, यहां सी / जावा शैली में प्रस्तुत की गई क्लास की एपीआई का एक त्वरित संदर्भ है, ताकि आप जान सकें कि वे क्या लौटाते हैं और क्या तर्क देते हैं।
Boolean key_down (String key);
true
अगर key
नीचे है तो लौटता है, अन्यथा झूठ।
Boolean keys_down (String key1, String key2, ...);
रिटर्न true
अगर सभी चाबियाँ key1 .. keyN
नीचे हैं, तो अन्यथा।
void watch (String name, Function callback, String key1, String key2, ...);
एक "वॉचपॉइंट" बनाता है जो सभी को दबाकर keyN
कॉलबैक को ट्रिगर करेगा
void unwatch (String name);
रिमेक ने अपने नाम के माध्यम से चौकीदारी की
void clear (void);
"कुंजी नीचे" कैश पोंछे। map = {}
ऊपर के बराबर
void detach (void);
Detaches ev_kdown
और ev_kup
पेरेंट तत्व से श्रोताओं, यह संभव बनाने सुरक्षित रूप से उदाहरण से छुटकारा पाने के
अद्यतन 2017/12/02 GitHub को यह प्रकाशित करने के लिए एक अनुरोध के जवाब में, मैं एक बनाया है सार ।
अपडेट 2018-07-21 मैं थोड़ी देर के लिए घोषणात्मक शैली की प्रोग्रामिंग के साथ खेल रहा हूं, और यह तरीका अब मेरा व्यक्तिगत पसंदीदा है: फिडेल , पास्टबिन
आम तौर पर, यह उन मामलों के साथ काम करेगा जिन्हें आप वास्तविक रूप से चाहते हैं (सीटीएल, एलटी, शिफ्ट), लेकिन अगर आपको हिट करने की आवश्यकता है, तो कहें, a+w
उसी समय, ए में दृष्टिकोण को "गठबंधन" करना बहुत मुश्किल नहीं होगा। बहु कुंजी देखने।
मुझे आशा है कि यह पूरी तरह से समझाया गया उत्तर मिनी-ब्लॉग उपयोगी था :)