0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

jQuery使いだった人がJavaScriptに移行する際の対比集

0
Last updated at Posted at 2025-02-02

jQuery ↔ JavaScript 完全対比リファレンス

ページ読み込みタイミングと初期化

読み込みタイミングの種類と使い分け

1. DOM構築完了時点(HTMLの解析完了、画像等は未完了)

// jQuery - 最もよく使われるパターン
$(function() {
    console.log("DOM準備完了")
})

// jQuery - 同じ意味の書き方
$(document).ready(function() {
    console.log("DOM準備完了")
})

// jQuery - アロー関数版
$(() => {
    console.log("DOM準備完了")
})

// JavaScript - 標準的な方法
document.addEventListener("DOMContentLoaded", function() {
    console.log("DOM準備完了")
})

// JavaScript - アロー関数版
document.addEventListener("DOMContentLoaded", () => {
    console.log("DOM準備完了")
})

// JavaScript - 関数分離版
function initApp() {
    console.log("DOM準備完了")
}
document.addEventListener("DOMContentLoaded", initApp)

2. 全リソース読み込み完了時点(画像、CSS、JSファイル等すべて完了)

// jQuery
$(window).on("load", function() {
    console.log("全リソース読み込み完了")
})

// JavaScript
window.addEventListener("load", function() {
    console.log("全リソース読み込み完了")
})

3. 即座実行(DOMの状態を問わず)

// jQuery - ページ読み込み前でも実行される
console.log("即座実行")

// JavaScript - 同じく即座実行
console.log("即座実行")

// JavaScript - DOMの状態を確認して分岐
if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initApp)
} else {
    initApp() // すでに読み込み済みなら即座実行
}

4. 実用的な汎用関数(jQueryっぽい動作をJSで再現)

// JavaScript - jQueryのready()を再現
function ready(callback) {
    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", callback)
    } else {
        callback()
    }
}

// 使用例
ready(function() {
    console.log("DOM準備完了またはすでに完了済み")
})

// さらに短縮版
const $ = callback => ready(callback)
$(function() {
    console.log("jQueryっぽい書き方")
})

5. 読み込みタイミングの流れ

1. HTMLファイルのダウンロード開始
2. HTMLの解析開始 (document.readyState = "loading")
3. 外部CSS、JSファイルの読み込み開始
4. HTMLの解析完了 → DOMContentLoaded発火 ← ★ここで$(function(){})実行
5. 外部リソース(画像、CSS、JS)の読み込み完了
6. 全リソース完了 → load発火 ← ★ここで$(window).on("load")実行

🔍 要素の選択・取得

基本的な選択

// jQuery
$("#myId")                    // ID選択
$(".myClass")                // クラス選択
$("div")                     // タグ選択
$("div.myClass")             // タグ+クラス
$("#myId .child")            // 子孫選択
$("#myId > .child")          // 直接の子選択
$(".class1, .class2")        // 複数選択
$("input[type='text']")      // 属性選択

// JavaScript
document.getElementById("myId")
document.querySelector(".myClass")
document.querySelector("div")
document.querySelector("div.myClass")
document.querySelector("#myId .child")
document.querySelector("#myId > .child")
document.querySelectorAll(".class1, .class2")
document.querySelector("input[type='text']")

複数要素の選択

// jQuery
$(".myClass")                // 全ての.myClassを取得
$("div")                     // 全てのdivを取得

// JavaScript
document.querySelectorAll(".myClass")     // NodeList(推奨)
document.getElementsByClassName("myClass") // HTMLCollection
document.querySelectorAll("div")
document.getElementsByTagName("div")

高度な選択

// jQuery
$("div:first")               // 最初のdiv
$("div:last")                // 最後のdiv
$("div:eq(2)")               // 3番目のdiv
$("div:not(.exclude)")       // .excludeクラス以外
$("div:contains('テキスト')") // テキストを含む

// JavaScript
document.querySelector("div")                    // 最初のdiv
document.querySelector("div:last-child")         // 最後の子div
document.querySelectorAll("div")[2]              // 3番目のdiv
document.querySelector("div:not(.exclude)")      // .excludeクラス以外
// containsはカスタム関数が必要
Array.from(document.querySelectorAll("div")).find(el => 
    el.textContent.includes("テキスト"))

要素の関係性

// jQuery
$("#element").parent()        // 親要素
$("#element").children()      // 子要素
$("#element").siblings()      // 兄弟要素
$("#element").next()          // 次の兄弟
$("#element").prev()          // 前の兄弟
$("#element").find(".class")  // 子孫から検索
$("#element").closest(".parent") // 最も近い祖先

// JavaScript
const el = document.getElementById("element")
el.parentElement              // 親要素
el.children                   // 子要素(HTMLCollection)
// 兄弟要素は配列操作が必要
Array.from(el.parentElement.children).filter(child => child !== el)
el.nextElementSibling         // 次の兄弟
el.previousElementSibling     // 前の兄弟
el.querySelectorAll(".class") // 子孫から検索
el.closest(".parent")         // 最も近い祖先

📝 DOM操作

テキスト・HTML の取得・設定

// jQuery
$("#element").text()                    // テキスト取得
$("#element").text("新しいテキスト")     // テキスト設定
$("#element").html()                    // HTML取得
$("#element").html("<b>太字</b>")       // HTML設定

// JavaScript
const el = document.getElementById("element")
el.textContent                          // テキスト取得
el.textContent = "新しいテキスト"        // テキスト設定
el.innerHTML                            // HTML取得
el.innerHTML = "<b>太字</b>"            // HTML設定

// 安全なHTML挿入(XSS対策)
el.insertAdjacentHTML("afterbegin", "<b>太字</b>")

フォーム要素の値操作

// jQuery
$("#input").val()                       // 値取得
$("#input").val("新しい値")              // 値設定
$("#select").val()                      // 選択値取得
$("#checkbox").prop("checked")          // チェック状態
$("#checkbox").prop("checked", true)    // チェック設定

// JavaScript
const input = document.getElementById("input")
input.value                             // 値取得
input.value = "新しい値"                 // 値設定
document.getElementById("select").value // 選択値取得
const checkbox = document.getElementById("checkbox")
checkbox.checked                        // チェック状態
checkbox.checked = true                 // チェック設定

属性の操作

// jQuery
$("#element").attr("href")              // 属性取得
$("#element").attr("href", "/page")     // 属性設定
$("#element").removeAttr("disabled")    // 属性削除
$("#element").prop("disabled", true)    // プロパティ設定
$("#element").data("id")                // data属性取得
$("#element").data("id", "123")         // data属性設定

// JavaScript
const el = document.getElementById("element")
el.getAttribute("href")                 // 属性取得
el.setAttribute("href", "/page")        // 属性設定
el.removeAttribute("disabled")          // 属性削除
el.disabled = true                      // プロパティ設定
el.dataset.id                          // data属性取得
el.dataset.id = "123"                  // data属性設定

CSS クラスの操作

// jQuery
$("#element").addClass("newClass")      // クラス追加
$("#element").removeClass("oldClass")   // クラス削除
$("#element").toggleClass("active")     // クラス切り替え
$("#element").hasClass("active")        // クラス存在確認

// JavaScript
const el = document.getElementById("element")
el.classList.add("newClass")            // クラス追加
el.classList.remove("oldClass")         // クラス削除
el.classList.toggle("active")           // クラス切り替え
el.classList.contains("active")         // クラス存在確認

// 複数クラス操作
el.classList.add("class1", "class2")    // 複数追加
el.classList.remove("class1", "class2") // 複数削除

CSS スタイルの操作

// jQuery
$("#element").css("color")              // スタイル取得
$("#element").css("color", "red")       // スタイル設定
$("#element").css({                     // 複数スタイル設定
    "color": "red",
    "font-size": "16px",
    "margin": "10px"
})

// JavaScript
const el = document.getElementById("element")
getComputedStyle(el).color              // 計算済みスタイル取得
el.style.color = "red"                  // スタイル設定
// 複数スタイル設定
Object.assign(el.style, {
    color: "red",
    fontSize: "16px",
    margin: "10px"
})

// CSS変数の操作
el.style.setProperty("--main-color", "blue")

👁️ 表示・非表示・アニメーション

基本的な表示制御

// jQuery
$("#element").show()                    // 表示
$("#element").hide()                    // 非表示
$("#element").toggle()                  // 切り替え
$("#element").is(":visible")            // 表示状態確認

// JavaScript
const el = document.getElementById("element")
el.style.display = "block"              // 表示
el.style.display = "none"               // 非表示
// 切り替え
el.style.display = el.style.display === "none" ? "block" : "none"
// 表示状態確認
getComputedStyle(el).display !== "none"

フェード効果(CSS Transition使用)

// jQuery
$("#element").fadeIn(500)               // フェードイン
$("#element").fadeOut(500)              // フェードアウト
$("#element").fadeTo(500, 0.5)          // 透明度指定

// JavaScript - CSS Transitionを使った実装
const el = document.getElementById("element")

// CSS設定(初期化時に設定)
el.style.transition = "opacity 0.5s ease"

// フェードイン
function fadeIn(element) {
    element.style.display = "block"
    element.style.opacity = "0"
    setTimeout(() => element.style.opacity = "1", 10)
}

// フェードアウト
function fadeOut(element) {
    element.style.opacity = "0"
    setTimeout(() => element.style.display = "none", 500)
}

// 透明度指定
function fadeTo(element, opacity) {
    element.style.opacity = opacity
}

スライド効果

// jQuery
$("#element").slideDown(500)            // スライドダウン
$("#element").slideUp(500)              // スライドアップ
$("#element").slideToggle(500)          // スライド切り替え

// JavaScript - CSS Transitionを使った実装
function slideDown(element, duration = 500) {
    element.style.display = "block"
    element.style.height = "0"
    element.style.overflow = "hidden"
    element.style.transition = `height ${duration}ms ease`
    
    const height = element.scrollHeight + "px"
    setTimeout(() => element.style.height = height, 10)
    
    setTimeout(() => {
        element.style.height = ""
        element.style.overflow = ""
        element.style.transition = ""
    }, duration)
}

function slideUp(element, duration = 500) {
    element.style.height = element.scrollHeight + "px"
    element.style.overflow = "hidden"
    element.style.transition = `height ${duration}ms ease`
    
    setTimeout(() => element.style.height = "0", 10)
    
    setTimeout(() => {
        element.style.display = "none"
        element.style.height = ""
        element.style.overflow = ""
        element.style.transition = ""
    }, duration)
}

🎯 イベント処理

基本的なイベント

// jQuery
$("#button").click(function() {})       // クリック
$("#input").change(function() {})       // 値変更
$("#input").keyup(function() {})        // キー離し
$("#element").hover(                    // マウスホバー
    function() { /* enter */ },
    function() { /* leave */ }
)

// JavaScript
const button = document.getElementById("button")
button.addEventListener("click", function() {})

const input = document.getElementById("input")
input.addEventListener("change", function() {})
input.addEventListener("keyup", function() {})

const element = document.getElementById("element")
element.addEventListener("mouseenter", function() {})
element.addEventListener("mouseleave", function() {})

複数イベントの監視

// jQuery
$("#input").on("keyup change paste", function() {
    // 複数のイベントで同じ処理
})

// JavaScript
const input = document.getElementById("input")
const events = ["keyup", "change", "paste"]
events.forEach(event => {
    input.addEventListener(event, function() {
        // 複数のイベントで同じ処理
    })
})

// または
function handleInput() {
    // 処理内容
}
input.addEventListener("keyup", handleInput)
input.addEventListener("change", handleInput)
input.addEventListener("paste", handleInput)

イベント委譲(動的要素対応)

// jQuery
$(document).on("click", ".dynamic-button", function() {
    console.log("動的に追加されたボタンがクリックされた")
})

// JavaScript
document.addEventListener("click", function(e) {
    if (e.target.matches(".dynamic-button")) {
        console.log("動的に追加されたボタンがクリックされた")
    }
})

// より具体的な委譲
document.addEventListener("click", function(e) {
    const button = e.target.closest(".dynamic-button")
    if (button) {
        console.log("動的ボタンまたはその子要素がクリックされた")
    }
})

カスタムイベント

// jQuery
$("#element").trigger("myEvent", {data: "test"})
$("#element").on("myEvent", function(e, data) {
    console.log(data)
})

// JavaScript
const element = document.getElementById("element")

// カスタムイベント発火
const customEvent = new CustomEvent("myEvent", {
    detail: {data: "test"}
})
element.dispatchEvent(customEvent)

// カスタムイベント監視
element.addEventListener("myEvent", function(e) {
    console.log(e.detail.data)
})

イベントの削除

// jQuery
$("#element").off("click")              // 全クリックイベント削除
$("#element").off("click", handler)     // 特定ハンドラー削除

// JavaScript
const element = document.getElementById("element")
// 特定ハンドラー削除(参照を保持しておく必要がある)
element.removeEventListener("click", handler)

// 全イベント削除は新しい要素で置換
const newElement = element.cloneNode(true)
element.parentNode.replaceChild(newElement, element)

🏗️ DOM要素の作成・挿入・削除

要素の作成

// jQuery
$("<div>")                              // 空のdiv作成
$("<div>", {                           // 属性付きdiv作成
    "class": "myClass",
    "id": "myId",
    "text": "Hello World"
})

// JavaScript
const div = document.createElement("div")
// 属性設定
div.className = "myClass"
div.id = "myId"
div.textContent = "Hello World"

// またはテンプレートリテラル使用
const template = `
    <div class="myClass" id="myId">
        Hello World
    </div>
`

要素の挿入

// jQuery
$("#parent").append("<div>末尾に追加</div>")
$("#parent").prepend("<div>先頭に追加</div>")
$("#element").after("<div>後ろに挿入</div>")
$("#element").before("<div>前に挿入</div>")

// JavaScript
const parent = document.getElementById("parent")
const element = document.getElementById("element")

// HTML文字列での挿入
parent.insertAdjacentHTML("beforeend", "<div>末尾に追加</div>")
parent.insertAdjacentHTML("afterbegin", "<div>先頭に追加</div>")
element.insertAdjacentHTML("afterend", "<div>後ろに挿入</div>")
element.insertAdjacentHTML("beforebegin", "<div>前に挿入</div>")

// 要素オブジェクトでの挿入
const newDiv = document.createElement("div")
newDiv.textContent = "新しい要素"
parent.appendChild(newDiv)              // 末尾に追加
parent.insertBefore(newDiv, parent.firstChild) // 先頭に追加

要素の削除・置換

// jQuery
$("#element").remove()                  // 要素削除
$("#element").empty()                   // 中身削除
$("#element").replaceWith("<div>新要素</div>")

// JavaScript
const element = document.getElementById("element")
element.remove()                        // 要素削除
element.innerHTML = ""                  // 中身削除
element.outerHTML = "<div>新要素</div>" // 要素置換

🔄 ループ処理

each ループ

// jQuery
$(".items").each(function(index, element) {
    $(this).text("アイテム " + index)
    console.log(element)
})

// JavaScript
const items = document.querySelectorAll(".items")
items.forEach(function(element, index) {
    element.textContent = "アイテム " + index
    console.log(element)
})

// for文版
for (let i = 0; i < items.length; i++) {
    items[i].textContent = "アイテム " + i
}

// for...of文版
for (const [index, element] of items.entries()) {
    element.textContent = "アイテム " + index
}

配列・オブジェクトのループ

// jQuery
$.each(["a", "b", "c"], function(index, value) {
    console.log(index, value)
})

// JavaScript
["a", "b", "c"].forEach(function(value, index) {
    console.log(index, value)
})

// オブジェクトのループ
const obj = {a: 1, b: 2, c: 3}
Object.entries(obj).forEach(([key, value]) => {
    console.log(key, value)
})

🌐 Ajax(非同期通信)

GET リクエスト

// jQuery
$.get("/api/data")
    .done(function(data) {
        console.log("成功:", data)
    })
    .fail(function(xhr, status, error) {
        console.log("エラー:", error)
    })

// JavaScript (Fetch API)
fetch("/api/data")
    .then(response => {
        if (!response.ok) {
            throw new Error("Network response was not ok")
        }
        return response.json()
    })
    .then(data => console.log("成功:", data))
    .catch(error => console.log("エラー:", error))

// async/await版
async function fetchData() {
    try {
        const response = await fetch("/api/data")
        if (!response.ok) throw new Error("Network error")
        const data = await response.json()
        console.log("成功:", data)
    } catch (error) {
        console.log("エラー:", error)
    }
}

POST リクエスト

// jQuery
$.post("/api/data", {
    name: "太郎",
    email: "taro@example.com"
})
.done(function(data) {
    console.log("送信成功:", data)
})

// JavaScript (Fetch API)
fetch("/api/data", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
    },
    body: JSON.stringify({
        name: "太郎",
        email: "taro@example.com"
    })
})
.then(response => response.json())
.then(data => console.log("送信成功:", data))
.catch(error => console.log("エラー:", error))

フォームデータの送信

// jQuery
$("#form").serialize()                  // URLエンコード形式
$("#form").serializeArray()             // 配列形式

// JavaScript
const form = document.getElementById("form")
const formData = new FormData(form)     // FormDataオブジェクト

// URLエンコード形式に変換
const params = new URLSearchParams(formData)
console.log(params.toString())

// オブジェクト形式に変換
const data = {}
for (let [key, value] of formData.entries()) {
    data[key] = value
}

// Fetchで送信
fetch("/api/submit", {
    method: "POST",
    body: formData  // FormDataをそのまま送信
})

📐 要素のサイズ・位置

サイズ情報

// jQuery
$("#element").width()                   // 幅(コンテンツのみ)
$("#element").height()                  // 高さ(コンテンツのみ)
$("#element").innerWidth()              // 幅(パディング含む)
$("#element").outerWidth()              // 幅(ボーダー含む)
$("#element").outerWidth(true)          // 幅(マージン含む)

// JavaScript
const el = document.getElementById("element")
const rect = el.getBoundingClientRect()
const style = getComputedStyle(el)

el.clientWidth                          // 幅(パディング含む)
el.clientHeight                         // 高さ(パディング含む)
el.offsetWidth                          // 幅(ボーダー含む)
el.offsetHeight                         // 高さ(ボーダー含む)
rect.width                              // 幅(ボーダー含む、小数点あり)
rect.height                             // 高さ(ボーダー含む、小数点あり)

// コンテンツのみの幅(jQueryのwidth()相当)
el.clientWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight)

位置情報

// jQuery
$("#element").offset()                  // ドキュメントからの位置
$("#element").position()                // 親要素からの位置

// JavaScript
const el = document.getElementById("element")
const rect = el.getBoundingClientRect()

// ドキュメントからの位置(offset相当)
const offset = {
    top: rect.top + window.scrollY,
    left: rect.left + window.scrollX
}

// 親要素からの位置(position相当)
const position = {
    top: el.offsetTop,
    left: el.offsetLeft
}

// ビューポートからの位置
const viewport = {
    top: rect.top,
    left: rect.left
}

スクロール情報

// jQuery
$(window).scrollTop()                   // スクロール位置取得
$(window).scrollTop(100)                // スクロール位置設定
$("#element").scrollTop()               // 要素内スクロール

// JavaScript
window.scrollY                          // スクロール位置取得
window.scrollTo(0, 100)                 // スクロール位置設定
window.scrollTo({                       // スムーススクロール
    top: 100,
    behavior: "smooth"
})

const el = document.getElementById("element")
el.scrollTop                            // 要素内スクロール取得
el.scrollTop = 100                      // 要素内スクロール設定

📋 フォーム操作

フォーム値の取得・設定

// jQuery
$("#text").val()                        // テキスト値
$("#select").val()                      // 選択値
$("#radio:checked").val()               // 選択されたラジオボタン
$("#checkbox:checked").map(function() { // チェックされたチェックボックス
    return $(this).val()
}).get()

// JavaScript
document.getElementById("text").value
document.getElementById("select").value
document.querySelector("input[name='radio']:checked")?.value
Array.from(document.querySelectorAll("input[name='checkbox']:checked"))
    .map(input => input.value)

フォームバリデーション

// jQuery
$("#email").val().includes("@")         // メール形式チェック
$("#required").val() !== ""             // 必須チェック

// JavaScript
const email = document.getElementById("email").value
email.includes("@") && email.includes(".")
document.getElementById("required").value.trim() !== ""

// HTML5バリデーション
document.getElementById("email").checkValidity()
document.getElementById("form").checkValidity()

🎨 便利なユーティリティ

文字列操作

// jQuery
$.trim("  文字列  ")                    // 前後空白削除

// JavaScript
"  文字列  ".trim()                     // 前後空白削除
"  文字列  ".trimStart()                // 前空白削除
"  文字列  ".trimEnd()                  // 後空白削除

数値・型判定

// jQuery
$.isNumeric("123")                      // 数値判定
$.isArray([1, 2, 3])                   // 配列判定
$.isEmptyObject({})                     // 空オブジェクト判定

// JavaScript
!isNaN(parseFloat("123")) && isFinite("123") // 数値判定
Array.isArray([1, 2, 3])                     // 配列判定
Object.keys({}).length === 0                 // 空オブジェクト判定

オブジェクト操作

// jQuery
$.extend({}, obj1, obj2)                // オブジェクト結合
$.extend(true, {}, obj1, obj2)          // ディープコピー結合

// JavaScript
Object.assign({}, obj1, obj2)           // オブジェクト結合
{...obj1, ...obj2}                      // スプレッド構文版
JSON.parse(JSON.stringify(obj))         // ディープコピー(単純な場合)
structuredClone(obj)                    // ディープコピー(モダン)

配列操作

// jQuery
$.map([1, 2, 3], function(item) {       // マップ
    return item * 2
})
$.grep([1, 2, 3, 4], function(item) {   // フィルター
    return item > 2
})

// JavaScript
[1, 2, 3].map(item => item * 2)         // マップ
[1, 2, 3, 4].filter(item => item > 2)   // フィルター
[1, 2, 3].reduce((sum, item) => sum + item, 0) // リデュース
[1, 2, 3].find(item => item > 2)        // 検索
[1, 2, 3].includes(2)                   // 含有チェック

💡 実用的なパターン集

アコーディオン

// jQuery
$(".accordion-header").click(function() {
    $(this).next(".accordion-content").slideToggle()
    $(this).toggleClass("active")
})

// JavaScript
document.querySelectorAll(".accordion-header").forEach(header => {
    header.addEventListener("click", function() {
        const content = this.nextElementSibling
        const isVisible = content.style.display !== "none"
        
        content.style.display = isVisible ? "none" : "block"
        this.classList.toggle("active")
    })
})

タブ切り替え

// jQuery
$(".tab-button").click(function() {
    const target = $(this).data("target")
    $(".tab-button").removeClass("active")
    $(".tab-content").removeClass("active")
    $(this).addClass("active")
    $("#" + target).addClass("active")
})

// JavaScript
document.querySelectorAll(".tab-button").forEach(button => {
    button.addEventListener("click", function() {
        const target = this.dataset.target
        
        // 全てのタブボタンとコンテンツからactiveクラスを削除
        document.querySelectorAll(".tab-button").forEach(btn => 
            btn.classList.remove("active"))
        document.querySelectorAll(".tab-content").forEach(content => 
            content.classList.remove("active"))
            
        // クリックされたタブボタンと対応するコンテンツにactiveクラスを追加
        this.classList.add("active")
        document.getElementById(target).classList.add("active")
    })
})

モーダルウィンドウ

// jQuery
$(".modal-trigger").click(function() {
    const modalId = $(this).data("modal")
    $("#" + modalId).fadeIn()
})
$(".modal-close, .modal-overlay").click(function() {
    $(this).closest(".modal").fadeOut()
})

// JavaScript
document.querySelectorAll(".modal-trigger").forEach(trigger => {
    trigger.addEventListener("click", function() {
        const modalId = this.dataset.modal
        const modal = document.getElementById(modalId)
        modal.style.display = "flex"
        // フェードイン効果
        modal.style.opacity = "0"
        setTimeout(() => modal.style.opacity = "1", 10)
    })
})

document.querySelectorAll(".modal-close, .modal-overlay").forEach(closeElement => {
    closeElement.addEventListener("click", function() {
        const modal = this.closest(".modal")
        modal.style.opacity = "0"
        setTimeout(() => modal.style.display = "none", 300)
    })
})

// Escキーでモーダルを閉じる
document.addEventListener("keydown", function(e) {
    if (e.key === "Escape") {
        const openModal = document.querySelector(".modal[style*='flex']")
        if (openModal) {
            openModal.style.display = "none"
        }
    }
})

ドロップダウンメニュー

// jQuery
$(".dropdown-toggle").click(function(e) {
    e.stopPropagation()
    $(this).next(".dropdown-menu").toggle()
})
$(document).click(function() {
    $(".dropdown-menu").hide()
})

// JavaScript
document.querySelectorAll(".dropdown-toggle").forEach(toggle => {
    toggle.addEventListener("click", function(e) {
        e.stopPropagation()
        const menu = this.nextElementSibling
        
        // 他のドロップダウンを閉じる
        document.querySelectorAll(".dropdown-menu").forEach(otherMenu => {
            if (otherMenu !== menu) {
                otherMenu.style.display = "none"
            }
        })
        
        // クリックされたドロップダウンを切り替え
        menu.style.display = menu.style.display === "block" ? "none" : "block"
    })
})

document.addEventListener("click", function() {
    document.querySelectorAll(".dropdown-menu").forEach(menu => {
        menu.style.display = "none"
    })
})

無限スクロール

// jQuery
$(window).scroll(function() {
    if ($(window).scrollTop() + $(window).height() >= $(document).height() - 100) {
        loadMoreContent()
    }
})

// JavaScript
let isLoading = false

window.addEventListener("scroll", function() {
    if (isLoading) return
    
    const scrollTop = window.scrollY
    const windowHeight = window.innerHeight
    const documentHeight = document.documentElement.scrollHeight
    
    if (scrollTop + windowHeight >= documentHeight - 100) {
        isLoading = true
        loadMoreContent().then(() => {
            isLoading = false
        })
    }
})

// Intersection Observer API を使った効率的な方法
const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting && !isLoading) {
            isLoading = true
            loadMoreContent().then(() => {
                isLoading = false
            })
        }
    })
})

// 監視対象要素(ページ底部に配置)
const loadTrigger = document.getElementById("load-trigger")
observer.observe(loadTrigger)

画像の遅延読み込み(Lazy Loading)

// jQuery
$(window).scroll(function() {
    $("img[data-src]").each(function() {
        const $img = $(this)
        if ($(window).scrollTop() + $(window).height() > $img.offset().top) {
            $img.attr("src", $img.data("src")).removeAttr("data-src")
        }
    })
})

// JavaScript - Intersection Observer API使用(推奨)
const imageObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target
            img.src = img.dataset.src
            img.removeAttribute("data-src")
            imageObserver.unobserve(img)
        }
    })
})

document.querySelectorAll("img[data-src]").forEach(img => {
    imageObserver.observe(img)
})

スムーススクロール

// jQuery
$("a[href^='#']").click(function(e) {
    e.preventDefault()
    const target = $($(this).attr("href"))
    $("html, body").animate({
        scrollTop: target.offset().top
    }, 500)
})

// JavaScript
document.querySelectorAll("a[href^='#']").forEach(link => {
    link.addEventListener("click", function(e) {
        e.preventDefault()
        const targetId = this.getAttribute("href")
        const target = document.querySelector(targetId)
        
        if (target) {
            target.scrollIntoView({
                behavior: "smooth",
                block: "start"
            })
        }
    })
})

// より細かい制御が必要な場合
function smoothScrollTo(element, duration = 500) {
    const targetPosition = element.offsetTop
    const startPosition = window.scrollY
    const distance = targetPosition - startPosition
    let startTime = null
    
    function animation(currentTime) {
        if (startTime === null) startTime = currentTime
        const timeElapsed = currentTime - startTime
        const run = easeInOutQuad(timeElapsed, startPosition, distance, duration)
        window.scrollTo(0, run)
        
        if (timeElapsed < duration) {
            requestAnimationFrame(animation)
        }
    }
    
    // イージング関数
    function easeInOutQuad(t, b, c, d) {
        t /= d / 2
        if (t < 1) return c / 2 * t * t + b
        t--
        return -c / 2 * (t * (t - 2) - 1) + b
    }
    
    requestAnimationFrame(animation)
}

🔧 実用的なヘルパー関数

jQueryライクなヘルパー関数

// 簡易的な$関数を作成
function $(selector) {
    if (typeof selector === "function") {
        // $(function() {}) のパターン
        if (document.readyState === "loading") {
            document.addEventListener("DOMContentLoaded", selector)
        } else {
            selector()
        }
        return
    }
    
    // 要素選択のパターン
    return document.querySelector(selector)
}

// 複数要素選択
function $(selector) {
    return document.querySelectorAll(selector)
}

// 使用例
$(function() {
    console.log("DOM準備完了")
})

const element = $("#myId")
const elements = $(".myClass")

よく使う処理をまとめたユーティリティ

const Utils = {
    // 要素の表示/非表示
    show: (element) => element.style.display = "block",
    hide: (element) => element.style.display = "none",
    toggle: (element) => {
        element.style.display = element.style.display === "none" ? "block" : "none"
    },
    
    // クラス操作
    addClass: (element, className) => element.classList.add(className),
    removeClass: (element, className) => element.classList.remove(className),
    toggleClass: (element, className) => element.classList.toggle(className),
    hasClass: (element, className) => element.classList.contains(className),
    
    // 配列化
    toArray: (nodeList) => Array.from(nodeList),
    
    // 要素作成
    createElement: (tag, options = {}) => {
        const element = document.createElement(tag)
        Object.entries(options).forEach(([key, value]) => {
            if (key === "text") {
                element.textContent = value
            } else if (key === "html") {
                element.innerHTML = value
            } else if (key === "class") {
                element.className = value
            } else {
                element.setAttribute(key, value)
            }
        })
        return element
    },
    
    // 簡易Ajax
    get: async (url) => {
        const response = await fetch(url)
        if (!response.ok) throw new Error("Network error")
        return response.json()
    },
    
    post: async (url, data) => {
        const response = await fetch(url, {
            method: "POST",
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify(data)
        })
        if (!response.ok) throw new Error("Network error")
        return response.json()
    }
}

// 使用例
const element = document.getElementById("myElement")
Utils.show(element)
Utils.addClass(element, "active")

const newDiv = Utils.createElement("div", {
    class: "my-class",
    id: "my-id",
    text: "Hello World"
})

⚠️ 移行時の注意点とベストプラクティス

1. エラー対策

// jQuery - 要素が存在しなくてもエラーにならない
$("#nonexistent").hide()

// JavaScript - 要素の存在確認が必要
const element = document.getElementById("nonexistent")
if (element) {
    element.style.display = "none"
}

// Optional Chaining(ES2020以降)
document.getElementById("nonexistent")?.style.setProperty("display", "none")

2. NodeListとHTMLCollectionの違い

// NodeList(querySelectorAllで取得)- forEachが使える
const nodeList = document.querySelectorAll(".class")
nodeList.forEach(element => {
    console.log(element)
})

// HTMLCollection(getElementsで取得)- 配列変換が必要
const htmlCollection = document.getElementsByClassName("class")
Array.from(htmlCollection).forEach(element => {
    console.log(element)
})

3. イベントリスナーのメモリリーク対策

// 悪い例 - 匿名関数では削除できない
element.addEventListener("click", function() {
    console.log("クリック")
})

// 良い例 - 関数に名前をつけて削除可能にする
function handleClick() {
    console.log("クリック")
}
element.addEventListener("click", handleClick)
// 必要に応じて削除
element.removeEventListener("click", handleClick)

4. パフォーマンス最適化

// 悪い例 - DOMを何度も検索
for (let i = 0; i < 100; i++) {
    document.getElementById("element").textContent = i
}

// 良い例 - 一度だけ検索して変数に保存
const element = document.getElementById("element")
for (let i = 0; i < 100; i++) {
    element.textContent = i
}

5. ブラウザ対応

// モダンブラウザのみ対応
element.remove()
element.closest(".parent")
Array.from(nodeList)

// IE対応が必要な場合
element.parentNode.removeChild(element)
// polyfillの使用を検討
// またはbabelでトランスパイル

📚 学習リソース

段階的な学習アプローチ

  1. 基本的な要素選択から始める - getElementById, querySelector
  2. イベント処理を覚える - addEventListener
  3. DOM操作をマスターする - createElement, appendChild
  4. Ajax通信を学ぶ - fetch API
  5. モダンJSの機能を活用 - async/await, アロー関数, テンプレートリテラル

実践的な練習方法

  1. 既存のjQueryコードを1つずつバニラJSに変換
  2. 小さなコンポーネント(アコーディオン、タブ等)を作成
  3. エラーハンドリングを必ず含める
  4. console.logでデバッグしながら理解を深める

追加

メソッド 戻り値 注意点
parentNode Node(要素以外も含む) テキストノード、コメント等も返す可能性
parentElement Element(要素のみ) HTMLElement のみ返す(安全)
closest() Element(条件にマッチする祖先) セレクタで条件指定可能(最も便利)
// 元のjQuery
id = $(this).parents("[id]").attr("id");

// 1. parentNode版(非推奨)
let parent = this.parentNode;
while (parent && parent.nodeType === 1) {
    if (parent.id) {
        id = parent.id;
        break;
    }
    parent = parent.parentNode;
}

// 2. parentElement版(まあまあ)
let parent = this.parentElement;
while (parent) {
    if (parent.id) {
        id = parent.id;
        break;
    }
    parent = parent.parentElement;
}

// 3. closest版(推奨)
id = this.closest("[id]").id;
0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?