プログラミンGOO

プログラミングナレッジ、ワードプレス、広告収入等について、気づき・備忘録を残していきます。

javascript備忘録 DOM操作編

【コンソールから操作する】

デベロッパーツール>コンソール

documentと打ち込むとDOMツリーを確認できる

jsのスクリプトからDOM(HTML)を操作する

【要素の取得】

■idで取得 :getElementById()

document.getElementById('target').textContent = 'Changed!';

■要素名、セレクタで取得 :getElementsByTagName()、querySelector()

document.getElementsByTagName('h1');

document.querySelector('h1').textContent = 'h1dayo!';
document.querySelectorAll('li').forEach(li => {
  li.textContent = 'list dayo!';
});

・クエリセレクタはノードを直接記述することもできる。
例)id="result"直下のp要素

let resultScore = document.querySelector('#result > p');

・フォーム部品の指定 input[type="text"]

const i = document.querySelector('input[type="text"]');

//textareaはHTMLでvalueが設定されていなくても.valueで値を取得する
const t = document.querySelector('textarea');
console.log(t.value);

//チェックボックス・ラジオボタン
~HTML~
<input type="checkbox" name="experience" value="done">
<input type="checkbox" name="decide" value="yes" checked>

~js~
console.log(document.querySelectorAll('input[type="checkbox"]')[1]);

//checked属性の指定
console.log(document.querySelectorAll('input[type="checkbox"]')[1].checked);

//プルダウン
~HTML~
<select>
  <option>item1</option>
  <option selected>item2</option>
</select>

~js~
>|??|
console.log(document.querySelectorAll('select > option')[1].selected); //true

・子要素の指定::nth-child()

document.querySelectorAll('li:nth-child(0)').forEach(li => {
  li.textContent = 'list dayo!';
}

//奇数の要素を取得
document.querySelectorAll('li:nth-child(odd)').forEach(li => {
  li.textContent = 'list dayo!';
}

■CSSクラス名で取得 :getElementsByClassName() //★Elementsとなることに注意!

■親要素の指定

const p = document.querySelector('li');
console.log(p.parentNode); //liの親要素であるul要素が取得できる

■子要素の指定

const p = document.querySelector('ul');
console.log(p.chilren);

複数要素がある場合はchildren[1]のようにアクセスできる
すべての要素を出力したい場合、HTMLコレクション(配列ではない)へのアクセスとなるのでforeachを使用すると以下のエラーが出力される。

forEach is not a function at HTMLDivElement

for文であればコレクションにも対応できるのでこちらで記述する。

const p = document.querySelector('ul');
  for (let i = 0; i < p.children.length; i++) {
    console.log(p.children[i]);
}

■カスタムデータ属性へのアクセス :dataset
HTMLで以下のようなカスタムデータ属性を設定していたとする。

<h1 title="this is title" data-app-id="app1">Title</h1>

その場合、以下の注意事項がある
┗データ属性名のハイフンは削る
┗2語目の文頭は大文字
┗jsからのアクセスはdataではなくdatasetとする

const h = document.querySelector('h1');
console.log(h.dataset.appId);

新たなカスタムデータ属性を付与する場合は以下のようにする

h.dataset.appIdd = 'this is changed';
>|??|
するとHTML側では以下のようになる
>|??|
<h1 title="this is title" data-app-idd="this is changed">Title</h1>

【要素の操作】

■基本

document.body.textContent = 'hello'; //bodyに文字を出力
document.title = 'catch me!' //タイトルを変更

基本的には定数に格納してそれに対して操作を用いることが多い

const h = document.querySelector('h1');
h1.textContent = 'hello!';

■テキストの挿入・変更

a.textContent = 'b'; //要素aのテキストをbにする

■属性の追加・変更

sample.setAttribute(name, value)
sample.setAttribute("href", "/sample")  //要素sampleにhref="/sample"が追加される

■CSSスタイルの追加

a.style.backgroundColor = 'gray';

■idの付与

const exam = "idname";  //id名を定数で定義
a.setAttribute("id", "idname");


■cssクラスの付与・変更 ※使いずらいので下のclassListの方がよく用いられる

a.className = 'b'; //要素aにクラスbを付与する

※上書きしてしまうので既存のクラスがある場合はそれも設定する
 例えばcというクラスがすでに設定されていた場合は、a.className = 'c b'; とする

■cssクラスの操作 :classList

a.classList.add('b') //要素aにクラスbを追加する
a.classList.remove('b') //要素aからクラスbを削除する

■特定のcssがあれば削除:contains

const d = document.querySelector('div');
if (d.classList.contains('border-pink')) {
  d.classList.remove('border-pink');
} else {
  d.classList.add('border-pink');
}

・単純な入れ替えは以下でもできる

d.classList.toggle('border-pink');

■要素の生成 :createElement()

const h = document.createElement('h1'); //要素を作成 ※まだ配置していない
h.textContent = 'Title';
document.body.appendChild(h); //bodyの最後の子要素に追加

※位置を指定する場合

const b = document.querySelector('body');
b.appendChild(b);

・要素の途中に追加するには?

const h = document.createElement('h1'); //要素を作成 ※まだ配置していない
h.textContent = 'Title';
const d = document.querySelector('div'); //HTMLの配置ポイントを取得
document.body.insertBefore(h, d); //hをdの直前に配置

※まだ配置していない要素に追加する場合はdocument.は不要

■要素のコピー

const d = document.querySelector('div');
const c = cloneNode(true); //falseにすると空の要素を作る

■要素の削除 ;removeChild

const d = document.getElementById(‘id’);
d.parentNode.removeChild(d); //親要素のノードからremoveChildすることで自身を削除

※複数の要素をリストに格納しfor文で削除する場合、削除のたびにリストの中身が変わるので、インデックスではなく常に先頭の要素を削除するなどの注意が必要。

■子要素をすべて削除

targetArea.innerHTML = '';

■要素のフォーカス
初期値でテキストエリアなど、要素にフォーカスさせたいとき

const t = document.querySelector('textarea');
t.focus();

・フォーカスさせつつ要素を全選択させたい場合 :select()

t.select();

・入力されないようグレーアウトさせる :disabled

t.disabled = true;

■イベントリスナーで関数を実行 :eventListener
ボタンがクリックされたとき、キーボードが操作された時など、様々なイベントをキーとして動作を追加できる

const b = document.querySelector('button');
b.addEventListener('click', () => {

  console.log('clicked!');
})

【appendix】

■スクロール
指定の要素までスクロール

targetNode.scrollIntoView()

・ゆっくりスクロールさせたい場合

targetNode.scrollIntoView({
  behavior: 'smooth'
})

・スクロール位置を微調整したい場合

const targetZahyou = targetNode.getBoundingClientRecte()
targetY = targetZahyou.top + window/pageYOffset

sindow.scrollTo({
  top: targetY,
  behavior: 'sooth'
})

■座標の取得 :mousemoveイベントのclientX,clientY

const d = document.querySelector('div'); //divに座標を表示するためにdを用意
document.addEventListener('mousemove', e => { //mousemoveイベントを実行。引数にeを設定
  d.textContent = `${e.clientX}:${e.clientY}`;  //eのclientXでX座標を取得できる
});

↑引数にeを渡してあげるとイベントオブジェクトが返ってくるので、それにアクセスすることで動作を指定できる。

・aタグに対し操作を行う際は href属性が空だと自身のページを読み込むためNG

★要素の規定の動作をキャンセル :preventDefault()
~HTML~

.hidden {
  display: none;
}

<p>テストだよ!<span class="hidden">隠しテキストだよ!</span><a href="">読み込む…</a></p>

~js~

const a = document.querySelector('a');
const s = document.querySelector('span');

a.addEventListener('click', e => {

  e.preventDefault(); //aタグの規定の動作(ページ遷移)をキャンセル
  a.classList.add('hidden');
  s.classList.remove('hidden');
});

■addEbentListenerいろいろ
参考:https://qiita.com/kogirix/items/77417702cbc474f49df1

■要素がクリックされたらイベントを起動

const st = document.getElementById('start'); //スタートボタンをidで取得
st.addEventListener('click', () => {

    sttime = Date.now(); //クリックされた時の処理
  });

■押されたキーボードの値を取得

window.addEventListener('keydown', (e) => {
  e.key //ウィンドウで押下されたキーの値を取得
})

■画面をクリックしたらイベントを起動

window.addEventListener('click', (e) => { //画面をクリックしたら
})

■アラートを表示

alert('Game Over'); //アラートを表示

■画面幅で改行が発生しているかを判定

window.addEventListener('DOMContentLoaded', () => {
	let range = new Range();
	range.selectNode(inlineNode);
	console.log(range.getClientRects().length) //行数が取得できる
})

【エラー対応】

■HTMLCollectionのlengthが取得できない
document.getElementsByClassNameで要素を取得するとHTMLCollectionが返ってくる。
console.logで出力するとlengthはしっかりカウントされている(ゼロでない)のだが、このlengthを取得しようとするとなぜか0になる。

const a = document.getElementsByClassName;
console.log(a);  //HTMLCollectionが表示され、プロパティのlengthは0ではなく、値も取得できている。
const b = a.length;
console.log(b);  //なぜか0になる

・解決方法
調べたところ、HTMLCollectionの値が取得される前にconsole.log(b)を実行してしまっている可能性。
正確な読み込みタイミングは調べていないが、以下の順?

  • 変数aが作成される
  • getElementsByClassNameが実行される(DOMがレンダリングされるまで待機)
  • 変数bが作成される
  • a.lengthが実行される(まだDOMレンダリング途中のためlength=0)
  • レンダリングが完了しaにHTMLCollectionが返る
window.addEventListener('DOMContentLoaded', () => {  //DOMが完全に読み込まれてから処理を行う
	if(document.getElementsByClassName('sample-class').length) {
		console.log('exist');
	} else {
		console.log('not');
	}
})

試してはいないけど、処理順の問題ならasinc、awaitでも解決できそう。

Uncaught ReferenceError: