Web production note

 【更新日 :

【脱jQuery】jQueryを使わずにJavaScriptで要素を操作するメモ

Category:
JavaScript

よく使うJavaScriptのコードをピックアップしてまとめました。

要素の取得

//IDを持つ要素を取得
document.getElementById('hoge'); 

//cssセレクタで単一要素を取得
document.querySelector('.hoge');

//cssセレクタで全件取得(Nodelistを返す)
document.querySelectorAll('.hoge');

//htmlタグ取得
document.documentElement

//bodyタグ取得
document.body;

//次の要素
elm.nextElementSibling;

//前の要素
elm.previousElementSibling;

//親要素
elm.parentNode;

//親要素よりも上の要素
elm.closest('.hoge');

//子要素(Nodelistを返す)
elm.children;

//特定の子要素を全て取得
elm.querySelectorAll(':scope > .targets');

//最初の子要素
elm.firstElementChild;

//最後の子要素
elm.lastElementChild;


//要素の中身を取得
elm.innerHTML

//要素を取得
elm.outerHTML

//要素のテキストを取得
elm.textContent

querySelectorAll()やchildrenで取得した要素の処理

複数取得するquerySelectorAll()はNodeList、childrenはHTMLCollectionが返ってきますが、そのまま操作はできないためforEachなどループ系の処理と組み合わせて操作します。

//NodeList
const elms = document.querySelectorAll('.hoge');
elms.forEach(function(elm){
  console.log(elm);
});

//NodeListでfor()
const elements = document.querySelectorAll('.targets');
for (let i = 0; i < elms.length; i++) {
  const elm = elms[i];
  console.log(elm);
}

//IE11を考慮する場合(Nodelistを配列に変換してから利用する)
const elms = Array.prototype.slice.call(document.querySelectorAll('a[href^=http]'),0);
elms.forEach(function(elm){
  console.log(elm);
});


//HTMLCollection
for (let i = 0; i < children.length; i++) {
  const child = children[i];
  console.log(child);
}
//HTMLCollectionでforEach
Array.from(children).forEach(child => {
  console.log(child);
});

要素が存在するかどうか判別

単一取得のgetElementById()や、querySelector()は要素が存在しなければnullが返ってきますので、そのまま判別に利用できます。

//IDを持つ要素を取得
const elm = document.getElementById('hoge'); 

if(elm){
  // #hogeが存在する場合のみ処理
}

if(!elm){
  // #hogeが存在しない場合のみ処理
}

複数取得するquerySelectorAll()は要素が存在しなければ空のNodeListが返ってきますので、lengthを用いることで判別することができます。

//cssセレクタで全件取得
const elms = document.querySelectorAll('.hoge');

if(targets.length > 0){
  // #hogeが存在する場合のみ処理
}

if(targets.length === 0){
  // #hogeが存在しない場合のみ処理
}

要素の削除・置換・複製

//要素の削除
elm.remove();

//要素の置換
elm.replace(replaceElm);
elm.outerHTML = 'outerHTMLで自分ごと中身を一式書き換え';

//要素の複製
elm.cloneNode(true);

要素の挿入・移動

//グループの最後に挿入
elm.parentNode.insertBefore(addElm, null);

//指定した要素の前に挿入
elm.parentNode.insertBefore(addElm, elm);

//指定した要素の前に挿入
elm.before(addElm01, '追加テキスト');

//指定した要素の後に挿入
elm.after(addElm01, '追加テキスト');

//指定した要素内の最初に追加
elm.prepend(addElm01, '追加テキスト');

//指定した要素内の最後に追加
elm.append(addElm01, '追加テキスト');


//要素の指定した位置に要素を追加  {beforebegin}{afterbegin} テキスト {beforeend}{afterend}
elm.insertAdjacentElement('beforebegin', addElement);

//要素の指定した位置に文字列で追加  {beforebegin}<div>{afterbegin} テキスト {beforeend}</div>{afterend}
elm.insertAdjacentHTML('beforebegin' ,'<div>追加要素</div>');


//jQueryの$.wrap() 簡易
elm = "<div>" + elm.outerHTML + "</div>";

//jQueryの$.wrap() 要素ノードの作成・挿入
const newElm = document.createElement("div");
//モダンブラウザ
elm.before(newElm);
newElm.append(elm);


//jQueryの$.unwrap()
const fragment = document.createDocumentFragment();
while(elm.firstChild) {
  fragment.appendChild(elm.firstChild);
}
elm.before(fragment);
elm.remove();

classの操作

//classの追加
elm.classList.add('hoge');

//classの削除
elm.classList.remove('hoge');

//classのトグル
elm.classList.toggle('hoge');
//第2引数に条件の設定も可能
elm.classList.toggle('hoge', a > b);

//特定のclassがあるか
if (elm.classList.contains('hoge')) {
  //.hoge を持っている場合の処理
}

属性の操作

//属性の取得
elm.getAttribute('href');

//属性の設定
elm.setAttribute('target', '_blank');

//属性の削除
elm.removeAttribute('href');

//data-hoge-Fuga属性の取得
elm.dataset.hogeFuga

cssの反映・取得

//cssの反映
elm.style.display = 'block';
elm.style.backgroundColor = '#ccc';
//setAttribute()で設定する方が処理速度が早い
element.setAttribute('style', 'display:block;');

//cssの取得
const styles = getComputedStyle(elm);
const display = styles.display;
//数値のみ取得
const marginTop = parseFloat(styles.marginTop);

//変数の処理
//値の取得
styles.getPropertyValue('--my-var');

//値の設定
elm.style.setProperty('--my-var', '10px');

イベント設定

//DOMツリーが出来上がったら実行
document.addEventListener('DOMContentLoaded', function(){
});

//ページ読み込みイベント
window.addEventListener('load', function(){
});

//スクロールイベント
window.addEventListener('scroll', function(){
}, {passive: true});

//クリックイベント
elm.addEventListener('click', function(){
});

//クリックイベント1回のみ
elm.addEventListener('click', function(){
},{once: true});


//TransitionEvent e.propertyName(プロパティ名)
//transition発火イベント(delay開始前) 
elm.addEventListener('transitionrun', function(){
});
//transition開始イベント
elm.addEventListener('transitionstart', function(){
});
//transition終了イベント
elm.addEventListener('transitionend', function(e){
//transitionstartからの経過時間
e.elapsedTime;
});


//AnimationEvent e.animationName、e.elapsedTime(経過時間)
//css animation開始イベント
elm.addEventListener('animationstart', function(){
});
//AnimationEvent css animation終了イベント
elm.addEventListener('animationend', function(){
});
//AnimationEvent css animation繰り替え医師
elm.addEventListener('animationiteration', function(){
});


//イベント削除
elm.removeEventListener('click', hoge);

幅・高さの取得

//画面の幅・高さ
window.innerWidth
window.innerHeight

//スクロールバーを含まない画面幅
const bodyWidth = document.body.clientWidth;

//正確な高さ(小数点込み)border, paddingを含み margin は含まない
elm.getBoundingClientRect().height;

//要素の幅
//padding、borderを含むがmarginは含まない
elm.offsetWidth;
//paddingを含むがborder、margin、スクロールバーを含まない
elm.clientWidth;

//要素の高さ
//padding、borderを含むがmarginは含まない
elm.offsetHeight;
//paddingを含むがborder、margin、スクロールバーを含まない
elm.clientHeight;

//marginを含む取得はないのでstyle値より取得し加算する
const styles = getComputedStyle(elm);
//padding、border、marginを含めた要素の幅
const marginLeft = parseFloat(styles.marginLeft);
const marginRight = parseFloat(styles.marginRight);
const outerHeight = elm.offsetHeight + marginLeft + marginRight;

//padding、border、marginを含めた要素の高さ
const marginTop = parseFloat(styles.marginTop);
const marginBottom = parseFloat(styles.marginBottom);
const outerHeight = elm.offsetHeight + marginTop + marginBottom;

位置の取得・スクロール操作

//スクロール量(ウィンドウの上端)取得
const scrollTop = window.scrollY;
//スクロール位置の移動
window.scrollTo(0, 200);

//要素の位置取得
elm.getBoundingClientRect().top + scrollTop;
elm.getBoundingClientRect().left + scrollTop;
elm.getBoundingClientRect().right + scrollTop;
elm.getBoundingClientRect().bottom + scrollTop;


//ページの一番上からの位置($('.target').offset().top と同じ)
const scrollTop = window.scrollY;
const top = elm.getBoundingClientRect().top;
const offsetTop = top + scrollTop;

CSSアニメーションの操作

//Web Animations API
const element = document.querySelector('.target');
element.animate(
  {
    opacity: [0,1]
  },
  {
    fill: 'forwards', //アニメーション後に値を維持する
    duration: 800,
    easing: 'cubic-bezier(.16, .8, .2, 1)'
  }
)

非同期通信(ajax)

//パラメータで送り先で処理したい各設定を追加する
let params = new URLSearchParams();
params.append('action', 'my_ajax_action');
params.append('sample_param_text', '送信するテキスト');
params.append('sample_param_id', 10);

const option = {
  method: 'POST',
  body:params
}
async function getJson() {
  const response = await fetch('jsonファイルなどアクセスするURLを指定', option);
  const json = await response.json();
  console.log(json);
}
getJson();

数値操作

// 切り捨て
Math.floor();

// 切り上げ
Math.ceil();

// 四捨五入
Math.round();

//小数点第1位まで取得し四捨五入
Math.round(value * 10) / 10

// 絶対値
Math.abs();
Math.abs('-1');     // 1
Math.abs(-2);       // 2
Math.abs(null);     // 0
Math.abs('');       // 0
Math.abs([]);       // 0
Math.abs([2]);      // 2
Math.abs([1,2]);    // NaN
Math.abs({});       // NaN
Math.abs('string'); // NaN
Math.abs();         // NaN

//数値が小数点を含むか整数かを判定する方法
Number.isInteger(value);

fadeIn()、fadeOut()、fadeToggle() の代わり

デフォルトで代替できる機能は存在しないため、fadeAnime() 関数を作成しました。

【脱Jquery】javascriptでフェード系アニメーション(fadeIn、fadeOut、fadeToggle)を実装する

slideDown()、slideUp()、slideToggle() の代わり

デフォルトで代替できる機能は存在しないため、slideAnime() 関数を作成しました。

【脱Jquery】javascriptでスライド系アニメーション(slideDown、slideUp、slideToggle)を実装する

スムーススクロール

jQueryだと animate() を利用したコードが有名ですが、代替としてrequestAnimationFrame() を利用したスムーススクロールを作成しました。任意でイージングと時間のカスタマイズが可能です。

【脱Jquery】javascriptでスムーススクロールを実装する

スライダーslickの代わり

Splide

ベーシックなスライダーなら軽量でアクセシビリティにも対応しているSplideが重宝しています。
動作も安定しており、国産なのでドキュメントが全て日本語で解説もとても丁寧に記載されています。

公式ドキュメント

タッチデバイスのスワイプ操作でスライダーを操作した後、ドラッグ検知がスライダーのスクロール動作に残ってしまい上下スクロールが阻害される問題がしばし見られるため、個人的によく以下のコードを追加し対応しています。
※iOSでスライダー内のリンクが効かなくなることがあるので、利用する場合は注意してください。

/*
  splideのスワイプ操作後のドラッグ検知が敏感すぎて
  上下スクロールが阻害される時の対処案
  ※speedなどのオプションは各自の環境に合わせて調整してください。
*/
//スライダー定義
const slider = new Splide('.splide').mount();

//スライダーの動作開始後に強制的にドラッグ検知を外す
//タッチ動作の判別
const sliderBody = document.querySelector('.splide__track');
let isTouch = false;
sliderBody.addEventListener('touchstart', () => {
  isTouch = true;
  //スワイプ操作中はスライド時間を短縮して
  //強制ドラッグ解除の時間を短縮する
  slider.options = {
    speed: 170,
    //flickPowerやeasingなどはサイトのトンマナに合わせて必要に応じて任意調整してください
    //flickPower: 500,
    //easing: 'cubic-bezier(0.25, 1, 0.5, 1)',
  };
}, {passive: true});

//スライダーのmoveイベント
let timer;
slider.on('move', () => {
  //スワイプ動作の時のみ処理
  if(isTouch) {
    clearTimeout(timer);
    sliderBody.style.pointerEvents = 'none';
    /*
      ※touchstartでpointerEvents = 'none'を設定すると
      スライダー要素内のクリッカブル要素が動作しなくなるので
      スライダーのmoveイベント中に設定して回避する
    */
  }
});
//スワイプ終了後(スライドアニメーション後)少しだけ時間を置いて
//強制的にドラッグ検知を外す設定を解除
sliderBody.addEventListener('touchend', () => {
  isTouch = false;
  timer = setTimeout(()=> {
    sliderBody.style.pointerEvents = '';
    //スライド時間を戻す
    slider.options = {
      speed: 400 //時間は各自の環境に合わせてください
    };
  },195);
});

See the Pen Splide slide test by web_corder (@web_walking_nak) on CodePen.

Swiper

Splideでは実現できない時は多機能なSwiperがおすすめです。

公式ドキュメント

参考リンク