jsでキーを押す度に特定の要素にフォーカス移動させたい
以下の方法で試した結果、最初の「id="txt1"」を飛ばして2個目の「id="txt1"」に飛んでくれましたが、引き続きエンターキーを押しても3、個目4個目の「id="txt1"」に飛んでくれません。
js
1function keydown(e){ 2 if (e.keyCode === 13){ 3var obj = document.getElementById("txt1").nextElementSibling.focus(); 4 5 } 6}; 7 8window.onkeydown = keydown;
html
1<body> 2 <input type="text" /> 3 <input type="checkbox" /> 4 <input type="text" /> 5 <input type="radio" /> 6 7<input type="text" id="txt1" value="1234567890"> 8<input type="text" id="txt1" value="1234567890"> 9<input type="text" id="txt2" value="1234567890"> 10 11<input type="text" class="LC20lb" value="1234567890"> 12<input type="text" class="LC20lb" value="1234567890"> 13 14<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 15<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 16<a href=""><h3 id="txt1"><span>BELIEVE</span></h3></a> 17<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 18<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 19</body>
Classの要素を獲得して移動して欲しかったのですが
document.getElementsByClassName
では反応してくれず、ID獲得にしています。
Class要素でも獲得してフォーカス移動はできるのでしょうか。
なお、先ほど「引き続きエンターキーを押しても」と書きましたが。
var obj = document.getElementById("txt1").nextElementSibling.focus();
を消して
js
1var obj = document.activeElement; 2obj.nextElementSibling.focus();
にしたところ、どんどん飛んでくれましたが「特定の要素」ではなく「全要素」に飛んでくれました。
1番参考にしたサイトのUrlをなくしてしまいました。。。
次に参考にしてたサイトです
参考2サイト
もしかしたらIF文だけでは実現できないことをしようとしている。
とかでなければいいのですが。
補足・修正がありましたら追記します。
追記:どうしても達成したいこと
html
1<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 2<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 3 4<a href=""><h3 id="txt1"><span>BELIEVE</span></h3></a> 5<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 6 7<input type="text" id="txt2" value="1234567890"> 8<a href=""><h3 class="LC20lb"><span>BELIEVE</span></h3></a>
上記の要素の中からtxt1やtxt2などにフォーカスせずに
Jsでクラス名LC20lbを指定して
キーを押す旅に連続で飛べるようにしたい。
試してみたこと
js
1function keydown(e){ 2 if (e.keyCode === 13){ 3 4var = obj document.querySelectorAll ('.LC20lb')[1].parentNode; 5obj.nextElementSibling.focus(); 6 7 } 8}; 9 10window.onkeydown = keydown;
やはりとんでくれません。
何が間違っているのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
window.onkeydown
JavaScript
1window.onkeydown = keydown;
window.onkeydown
はどこで [Enter] キーを押下しても反応します。
考えられる対策は二通り。
- keydownイベントハンドラ処理で
event.target
を読んで<input type="text">
だった場合にのみ処理されるように変更 <input type="text">
にkeydownイベントハンドラを指定する
次のfocus対象ノードを検出する
JavaScript
1var obj = document.activeElement; 2obj.nextElementSibling.focus();
にしたところ、どんどん飛んでくれましたが「特定の要素」ではなく「全要素」に飛んでくれました。
二通りの解決手段。
nextElementSibling
を while 文で<input type="text">
がくるまで繰り返す- 親ノードから
querySelectorAll()
でinput:focus~input[type=text]
実装例
HTML
1<form id="hoge" action="test.php"> 2 <input type="text" name="a" /><br> 3 <input type="checkbox" name="c1" /><br> 4 <input type="text" name="b" /><br> 5 <input type="checkbox" name="c2" /><br> 6 <input type="text" name="c" /><br> 7 <input type="text" name="d" /><br> 8 <input type="text" name="e" /><br> 9</form> 10<script> 11document.getElementById('hoge').addEventListener('keydown', function handleKeydown (event) { 12var input = event.target; 13 14if (event.code !== 'Enter' || input.tagName !== 'INPUT' || input.type !== 'text') return; 15 16var nextInput = input.form.querySelector('input:focus~input[type=text]'); 17 18if (nextInput) nextInput.focus(); 19}, false); 20</script>
HTML
1<h2>getElementsByClassName() ver</h2> 2<form id="sample1" action="test.php"> 3 <input class="focusable" type="text" name="a" /><br> 4 <input type="checkbox" name="c1" /><br> 5 <input class="focusable" type="text" name="b" /><br> 6 <input type="checkbox" name="c2" /><br> 7 <input class="focusable" type="text" name="c" disabled /><br> 8 <input class="focusable" type="text" name="d" /><br> 9 <input class="focusable" type="text" name="e" /><br> 10</form> 11<script> 12document.getElementById('sample1').addEventListener('keydown', function handleKeydown (event) { 13 const input = event.target; 14 15 if (event.code !== 'Enter' || input.tagName !== 'INPUT' || input.type !== 'text') return; 16 17 const targets = document.getElementsByClassName('focusable'); 18 let i = Array.prototype.indexOf.call(targets, input), nextInput; 19 20 while (nextInput = targets[++i], nextInput && nextInput.disabled); 21 22 if (nextInput) nextInput.focus(); 23}, false); 24</script> 25 26<h2>querySelectorAll() ver</h2> 27<form id="sample2" action="test.php"> 28 <input class="focusable" type="text" name="a" /><br> 29 <input type="checkbox" name="c1" /><br> 30 <input class="focusable" type="text" name="b" /><br> 31 <input type="checkbox" name="c2" /><br> 32 <input class="focusable" type="text" name="c" disabled /><br> 33 <input class="focusable" type="text" name="d" /><br> 34 <input class="focusable" type="text" name="e" /><br> 35</form> 36<script> 37document.getElementById('sample2').addEventListener('keydown', function handleKeydown (event) { 38 const input = event.target; 39 40 if (event.code !== 'Enter' || input.tagName !== 'INPUT' || input.type !== 'text') return; 41 42 const nextInput = input.form.querySelector('.focusable:focus~.focusable:enabled'); 43 44 if (nextInput) nextInput.focus(); 45}, false); 46</script>
Re: ryooma さん
投稿2021/02/28 05:00
編集2021/02/28 12:21総合スコア18162
0
idは同一ページ内に唯一のものでなければいけません。
これはHTMLのルールです。
そもそもidentityですしね。
唯一であると保証されてないといけないので、同一ページ内に複数あるとJavaScriptは特定ができない、動作保証されません。
それは、メソッド名にも表れています。
getElementById
getElementsByClassName
後者には「s」があり複数形となっています。
まずはこの問題を解消してください。
投稿2021/02/28 00:21
総合スコア80850
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/28 05:10
0
前回の回答があまりにも適当過ぎたので書き直しました。
think49 さんからの指摘で、summary などに対応しました。
js
1<!DOCTYPE html><title></title><meta charset="utf-8"> 2<style> 3 a:focus, datalist:focus, input:focus { 4 background: rgba(255,0,0,.2); 5 } 6</style> 7 8<body> 9<nav> 10 <p>最初に[Tab]でフォーカスを移動した場合テストできる<br> 11 <a href="#C">ABC</a> 12 <a href="#C">DEF</a> 13 <a href="#A">GHI</a><br> 14</nav> 15 16<form> 17 <p>フォーム内のアンカータグを移動する<br> 18 <a href="#C">ABC</a> 19 <a href="#C">DEF</a> 20 <a href="#A">GHI</a> 21 22 <p>通常の INPUT要素<br> 23 1.<input name="d0" value=""> 24 2.<input name="d1" value=""> 25 26 <p>表示されていない要素<br> 27 1.<input type="hidden" name="d2"> 28 2.<input type="hidden" name="d2" style="display:none;"> 29 3.<input type="hidden" name="d2" style="visibility:hidden;"> 30 4.<input type="hidden" name="d2" style="opacity: 0;"> 31 32 <p>INPUT[type=radio]要素の場合<br> 33 <label>1.<input type="radio" name="d3" value="1">abc</label> 34 <label>2.<input type="radio" name="d3" value="2">def</label> 35 <label>3.<input type="radio" name="d3" value="3">ghi</label> 36 37 <p>INPUT[type=checkbox]要素の場合<br> 38 <label><input type="checkbox" name="d4" value="1">abc</label> 39 <label><input type="checkbox" name="d4" value="2">def</label> 40 <label><input type="checkbox" name="d4" value="3">ghi</label><br> 41 42 <p>SELECT要素<br> 43 <select name="d5"><option value="">-- <option value="1">abc <option value="2">def</select> 44 45 <p>TEXTAREA要素<br> 46 <textarea name="d6" cols="80" rows="5"> 47 改行すると、その行の最初のインデントが継続されます 48 改行せずに移動する場合は[Ctrl]+[Enter]、設定で逆の動作をします 49 改行すると、その行の最初のインデントが継続されます 50 </textarea> 51 52 <p>DATALIST要素にSUMMARYがある場合<br> 53 <details> 54 <summary>Summary OPEN1</summary> 55 <ol><li>abc <li>def <li>ghi</ol> 56 </details> 57 <details open> 58 <summary>Summary OPEN2</summary> 59 <ol><li>abc <li>def <li>ghi</ol> 60 </details> 61 62 <p>INPUT[type=button] / BUTTON 要素の場合<br> 63 <input type="button" value="フォームの移動を無効にする" onclick="F.disabled=true"> 64 <input type="button" value="フォームの移動を有効にする" onclick="F.disabled=false"> 65 </p> 66 67</form> 68<script> 69 70/* 71 [Enter] 要素を次に移動する 72 [Shift]+[Enter] 前に移動する 73 [Ctrl]+[Enter]: 作用する 74*/ 75 76class ExEnter { 77 78 constructor (root = document.documentElement, option = { }) { 79 const 80 filter = this.filter.bind (this), 81 Nfilter = NodeFilter.SHOW_ELEMENT; 82 83 this.root = root; 84 this.walker = root.ownerDocument.createTreeWalker (root, Nfilter, filter, true); 85 this.option = Object.assign ({ }, this.constructor.defaultOption, option); 86 87 //IME日本語入力中で未変換文字があり Enterが押されたことを感知するには 88 //keypress イベントがが実行されないことを利用する 89 this.imeFlag = null; //ime 90 this.disabled = false; //機能停止用 91 } 92 93 94 //ルートの中の最初の要素を返す 95 get firstElement () { 96 this.walker.currentNode = this.root; 97 return this.walker.firstChild (); 98 } 99 100 101 //ルートの最後の要素を返す 102 get lastElement () { 103 this.walker.currentNode = this.root; 104 return this.walker.lastChild (); 105 } 106 107 108 //要素を移動する 109 move (target, direction = false) { 110 if (this.disabled) 111 return; 112 113 const 114 walker = this.walker, 115 isLoop = this.option.loop; 116 117 walker.currentNode = target; 118 let e = (direction) 119 ? walker.previousNode () || (isLoop ? this.lastElement: null) 120 : walker.nextNode () || (isLoop ? this.firstElement: null); 121 122 if (e) e.focus (); 123 } 124 125 126 //TreeWalker用のフィルター関数(要.bind(this)) 127 filter (node) { 128 const 129 accept = NodeFilter.FILTER_ACCEPT, 130 skip = NodeFilter.FILTER_SKIP; 131 132 switch (node.nodeName) { 133 case 'INPUT' : case 'TEXTAREA' : case 'SELECT' : case 'BUTTON' : 134 if (node.disabled) break; 135 if (node.readOnly) break; 136 if (this.option.tabIndex && ('-1' === node.getAttribute ('tabIndex'))) break; 137 if (isHide (node)) break; 138 return accept; 139 140 case 'A' : //href = '#...' で始まるもののみ対象とする 141 if (this.option.anchor) { 142 let href = node.getAttribute ('href'); 143 if (href) 144 if (! href.indexOf ('#')) 145 return accept; 146 } 147 break; 148 149 case 'SUMMARY' : 150 return accept; 151 } 152 return skip; 153 154 //__ 155 //祖先の要素が隠された状態にあるか? 156 function isHide (node) { 157 const chks = ['display', 'visibility', 'opacity', 'height', 'width']; 158 159 for (let e = node; e !== document.body; e = e.parentNode) { 160 let cs = getComputedStyle (e, null); 161 let [d, v, o, h, w] = chks.map (p=> cs.getPropertyValue (p)); 162 if ( 163 'none' === d || 'hidden' === v || 0 == parseFloat (o) || 164 ! ('auto' === h || 0 < parseInt (h, 10)) || 165 ! ('auto' === w || 0 < parseInt (w, 10)) 166 ) return true; 167 } 168 return false; 169 } 170 } 171 172 173 //_____ 174 175 //[CTRL]が押されていれば、適用させる 176 apply (e, sw, prev) { 177 let stay = false, tag = e.nodeName; 178 179 if ('TEXTAREA' === tag && !prev) { 180 if (sw ^ this.option.textarea) { 181 this.constructor.insertCRLF (e, this.option.autoIndent); 182 stay = true; 183 } 184 } 185 else if (sw) { 186 stay = this.option.stay; 187 switch (tag) { 188 case 'SUMMARY' : 189 let parent = e.parentNode; 190 parent.hasAttribute ('open') 191 ? parent.removeAttribute ('open') 192 : parent.setAttribute ('open', ''); 193 break; 194 195 case 'A' : 196 fireEvent (e); 197 break; 198 199 case 'INPUT' : 200 switch (e.type) { 201 case 'radio': case 'checkbox' : 202 e.checked = !e.checked; 203 break; 204 205 case 'button' : case 'submit' : case 'reset' : 206 fireEvent (e); 207 break; 208 } 209 break; 210 } 211 } 212 //値が有効か? 213 if (this.option.invalidStop && e.checkValidity) 214 stay = ! e.checkValidity (); 215 216 return stay; 217 218 //__ 219 220 function fireEvent (e) { 221 let event = document.createEvent ('MouseEvents'); 222 event.initEvent ('click', false, true); 223 e.dispatchEvent (event); 224 return event; 225 } 226 } 227 228 229 //_____ 230 231 //イベントハンドラ(各typeによって分岐) 232 handleEvent (event) { 233 this[event.type + 'Handler'].call (this, event); 234 } 235 236 //キーアップハンドラ 237 keyupHandler (event) { 238 let { code, shiftKey, ctrlKey, target: e } = event; 239 if ('Enter' !== code) return; 240 if (! this.imeFlag) //IMEの動作で未変換中の文字があると判断してスルー 241 return event.preventDefault (); 242 this.imeFlag = null; 243 if (! this.apply (e, ctrlKey, shiftKey)) 244 this.move (e, shiftKey); 245 } 246 247 //キープレスハンドラ 248 keypressHandler (event) { 249 let { target: { nodeName: n, type: t }, code } = event; 250 if ('Enter' == code) 251 if (/^(submit|reset|button|textarea)$/.test (t) || 'SUMMARY' === n || 'A' == n) 252 event.preventDefault (); 253 this.imeFlag = true;//未変換文字がある場合の対処として 254 } 255 256 //________ 257 258 //インスタンスの作成 259 static create (root = document.documentElement, option = { }) { 260 let obj = new this (root, option); 261 root.addEventListener ('keyup', obj, false); 262 root.addEventListener ('keypress', obj, false); 263 return obj; 264 } 265 266 //textarea要素に改行を挿入する 267 static insertCRLF (t, autoIndent = false, start = t.selectionStart || 0) { 268 let 269 str = '\n', 270 value = t.value, 271 first = value.slice (0, start), 272 last = value.slice (start).replace (/^([\t\u3000\u0020]+)/, ''); 273 274 if (autoIndent) { 275 let spc = /(?:\n|^)([\t\u3000\u0020]+).*$/.exec (first); 276 if (spc) str += spc[1]; 277 } 278 279 t.value = first + str + last; 280 t.selectionStart = t.selectionEnd = start + str.length; 281 } 282 283 284 285 //初期設定オプション値 286 static defaultOption = { 287 stay: true, //true: radio,checkbox,submit,button,summary を作用させた後も留まる 288 loop: true, //要素を巡回する 289 tabIndex: true, //tabIndex="-1" を有効にする 290 anchor: true, //アンカータグを有効にする(但し href属性の値が "#"から始まる場合) 291 textarea: true, //true:テキストエリア内では改行する, false:次に移動する(改行は、[Ctrl]+[Enter]) 292 autoIndent: true, //textarea要素内でのオートインデントを行う 293 invalidStop: false,//要素の値が不正な場合でも移動する 294 }; 295} 296 297const 298 nav = ExEnter.create (document.querySelector ('nav')), 299 F = ExEnter.create (document.querySelector ('form')); 300 301</script> 302 303
js
1<a href="#"><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 2<a href="#"><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 3<a href="#"><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 4<a href="#"><h3 class="LC20lb"><span>BELIEVE</span></h3></a> 5 6 7<script> 8const walker = document.createTreeWalker (document.body, NodeFilter.SHOW_ELEMENT, filter, true); 9 10function filter (node) { 11 return 'A' === node.nodeName 12 ? NodeFilter.FILTER_ACCEPT 13 : NodeFilter.FILTER_SKIP; 14} 15 16function handler ({ ctrlKey, key, target: e }, n) { 17 (ctrlKey && 'ArrowDown' === key) && 18 (walker.currentNode = document.activeElement, n = walker.nextNode (), n && n.focus ()); 19} 20 21document.addEventListener ('keydown', handler, true);
投稿2021/02/28 06:20
編集2021/03/05 09:23総合スコア616
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/28 07:12
2021/02/28 07:20
2021/02/28 11:22
2021/02/28 11:39
2021/02/28 11:39
2021/02/28 13:51
2021/02/28 23:46 編集
2021/03/01 12:02
2021/03/01 12:47
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/02/28 06:17
2021/02/28 07:11
2021/02/28 07:17
2021/02/28 08:14 編集
2021/02/28 09:35
2021/02/28 09:46
2021/02/28 10:08
2021/02/28 10:15
2021/02/28 11:59
2021/02/28 12:04
2021/02/28 12:08 編集
2021/02/28 12:19
2021/02/28 12:21
2021/02/28 13:29 編集
2021/02/28 14:00
2021/02/28 23:40
2021/03/01 07:04
2021/03/01 14:00 編集
2021/03/01 14:08 編集
2021/03/01 14:07
2021/03/01 14:10
2021/03/01 14:23
2021/03/01 21:58 編集
2021/03/01 22:02
2021/03/02 08:13 編集
2021/03/02 06:51
2021/03/02 08:03
2021/03/02 18:05
2021/03/02 18:16
2021/03/07 06:19 編集
2021/03/07 06:36