Teknik DOM: orang tua, anak, dan saudara kandung. Teknik DOM: Orang Tua, Anak, dan Saudara Kandung Menambah dan Menghapus Anak

Aplikasi web yang kompleks dan berat adalah hal yang umum akhir-akhir ini. Pustaka silang dan pustaka yang mudah digunakan seperti jQuery, dengan fungsionalitasnya yang kaya, dapat sangat membantu dalam memanipulasi DOM dengan cepat. Oleh karena itu, tidak mengherankan bahwa banyak pengembang menggunakan pustaka semacam itu lebih sering daripada bekerja dengan API DOM asli, yang menyebabkan banyak masalah. Dan meskipun perbedaan browser masih menjadi masalah, DOM sekarang dalam kondisi yang lebih baik daripada 5-6 tahun yang lalu ketika jQuery mulai populer.

Pada artikel ini, saya akan mendemonstrasikan kemampuan manipulasi HTML DOM, dengan fokus pada hubungan orang tua, anak, dan saudara. Sebagai kesimpulan, saya akan memberikan data tentang dukungan untuk fitur-fitur ini di browser, tetapi perlu diingat bahwa pustaka seperti jQuery masih merupakan pilihan yang baik karena bug dan ketidakkonsistenan dalam implementasi fungsionalitas asli.

Menghitung node anak

Saya akan menggunakan markup HTML berikut untuk demonstrasi, dan kami akan mengubahnya beberapa kali selama artikel ini:

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam


Var myList \u003d document.getElementById ("myList"); console.log (myList.children.length); // 6 console.log (myList.childElementCount); // 6

Seperti yang Anda lihat, hasilnya sama, meskipun tekniknya berbeda. Dalam kasus pertama, saya menggunakan properti anak-anak. Properti ini hanya-baca dan mengembalikan kumpulan elemen HTML yang ada di dalam elemen yang diminta; untuk menghitung berapa, saya menggunakan properti panjang dari koleksi ini.

Dalam contoh kedua, saya menggunakan metode childElementCount, yang menurut saya merupakan cara yang lebih rapi dan berpotensi lebih dapat dipelihara (kita akan membahas ini lebih detail nanti, saya rasa Anda tidak akan memiliki masalah dalam memahami apa itu).

Saya bisa mencoba menggunakan childNodes.length (bukan children.length), tetapi lihat hasilnya:

Var myList \u003d document.getElementById ("myList"); console.log (myList.childNodes.length); // tiga belas

Ini mengembalikan 13 karena childNodes adalah kumpulan dari semua node, termasuk spasi - pertimbangkan ini jika Anda peduli tentang perbedaan antara node anak dan node elemen anak.

Memeriksa keberadaan node anak

Untuk memeriksa apakah suatu elemen memiliki node anak, saya bisa menggunakan metode hasChildNodes (). Metode ini mengembalikan nilai boolean yang menunjukkan ada atau tidaknya:

Var myList \u003d document.getElementById ("myList"); console.log (myList.hasChildNodes ()); // benar

Saya tahu ada simpul anak dalam daftar saya, tapi saya bisa mengubah HTML sehingga tidak ada; sekarang markupnya terlihat seperti ini:



Dan berikut adalah hasil dari menjalankan hasChildNodes () baru:

Console.log (myList.hasChildNodes ()); // benar

Metode ini masih mengembalikan nilai true. Meskipun daftar tidak berisi elemen apa pun, daftar tersebut berisi spasi, yang merupakan jenis node yang valid. Metode ini mempertimbangkan semua node, bukan hanya node elemen. Agar hasChildNodes () mengembalikan false, kita perlu mengubah markup lagi:



Dan sekarang output yang diharapkan dicetak ke konsol:

Console.log (myList.hasChildNodes ()); // Salah

Tentu saja, jika saya tahu bahwa saya mungkin menemukan spasi, maka pertama-tama saya memeriksa keberadaan node anak, kemudian menggunakan properti nodeType saya menentukan apakah ada node elemen di antara mereka.

Menambah dan menghapus anak

Ada teknik yang bisa digunakan untuk menambah dan menghapus elemen dari DOM. Yang paling terkenal di antaranya didasarkan pada kombinasi metode createElement () dan appendChild ().

Var myEl \u003d document.createElement ("div"); document.body.appendChild (myEl);

Dalam hal ini, saya membuat

menggunakan metode createElement () lalu menambahkannya ke badan. Sangat sederhana dan Anda mungkin pernah menggunakan teknik ini sebelumnya.

Tapi alih-alih memasukkan elemen yang dibuat khusus, saya juga bisa menggunakan appendChild () dan hanya memindahkan elemen yang ada. Misalkan kita memiliki markup berikut:

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam

Contoh teks

Saya dapat mengubah lokasi daftar dengan kode berikut:

Var myList \u003d document.getElementById ("myList"), container \u003d document.getElementById ("c"); container.appendChild (myList);

DOM yang dihasilkan akan terlihat seperti ini:

Contoh teks

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam

Perhatikan bahwa seluruh daftar telah dihapus dari tempatnya (di atas paragraf) dan kemudian disisipkan setelahnya, sebelum badan penutup. Meskipun metode appendChild () biasanya digunakan untuk menambahkan elemen yang dibuat dengan createElement (), metode ini juga dapat digunakan untuk memindahkan elemen yang ada.

Saya juga bisa sepenuhnya menghapus anak dari DOM menggunakan removeChild (). Inilah cara daftar kami dihapus dari contoh sebelumnya:

Var myList \u003d document.getElementById ("myList"), container \u003d document.getElementById ("c"); container.removeChild (myList);

Item tersebut sekarang telah dihapus. Metode removeChild () mengembalikan item yang dihapus dan saya dapat menyimpannya jika saya membutuhkannya nanti.

Var myOldChild \u003d document.body.removeChild (myList); document.body.appendChild (myOldChild);

Jadi ada metode ChildNode.remove (), yang relatif baru-baru ini ditambahkan ke spesifikasi:

Var myList \u003d document.getElementById ("myList"); myList.remove ();

Metode ini tidak mengembalikan objek jarak jauh dan tidak berfungsi di IE (hanya Edge). Dan kedua metode tersebut menghapus node teks dengan cara yang sama seperti node elemen.

Mengganti anak

Saya bisa mengganti anak yang ada dengan yang baru, apakah elemen baru ini ada atau saya membuatnya dari awal. Inilah markupnya:

Contoh Teks

Var myPar \u003d document.getElementById ("par"), myDiv \u003d document.createElement ("div"); myDiv.className \u003d "contoh"; myDiv.appendChild (document.createTextNode ("Teks elemen baru")); document.body.replaceChild (myDiv, myPar);

Teks elemen baru

Seperti yang Anda lihat, metode replaceChild () mengambil dua argumen: elemen baru dan elemen lama yang digantikannya.

Saya juga dapat menggunakan metode ini untuk memindahkan item yang sudah ada. Lihat HTML berikut:

Contoh teks 1

Contoh teks 2

Contoh teks 3

Saya bisa mengganti paragraf ketiga dengan paragraf pertama dengan kode berikut:

Var myPar1 \u003d document.getElementById ("par1"), myPar3 \u003d document.getElementById ("par3"); document.body.replaceChild (myPar1, myPar3);

Sekarang DOM yang dihasilkan terlihat seperti ini:

Contoh teks 2

Contoh teks 1

Mengambil anak-anak tertentu

Ada beberapa cara berbeda untuk memilih item tertentu. Seperti yang ditunjukkan sebelumnya, saya bisa mulai dengan menggunakan koleksi anak atau properti childNodes. Tapi mari kita lihat opsi lain:

Properti firstElementChild dan lastElementChild melakukan persis seperti yang disarankan namanya: mereka memilih elemen anak pertama dan terakhir. Mari kembali ke markup kita:

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam


Saya dapat memilih elemen pertama dan terakhir menggunakan properti ini:

Var myList \u003d document.getElementById ("myList"); console.log (myList.firstElementChild.innerHTML); // "Contoh satu" console.log (myList.lastElementChild.innerHTML); // "Contoh enam"

Saya juga dapat menggunakan properti priorElementSibling dan nextElementSibling jika saya ingin memilih elemen turunan selain yang pertama atau terakhir. Ini dilakukan dengan menggabungkan properti firstElementChild dan lastElementChild:

Var myList \u003d document.getElementById ("myList"); console.log (myList.firstElementChild.nextElementSibling.innerHTML); // "Contoh dua" console.log (myList.lastElementChild.previousElementSibling.innerHTML); // "Contoh lima"

Ada juga properti serupa firstChild, lastChild, PreviousSibling, dan nextSibling, tetapi properti tersebut memperhitungkan semua jenis node, bukan hanya elemen. Biasanya, properti yang hanya mempertimbangkan node elemen akan lebih berguna daripada properti yang memilih semua node.

Memasukkan konten ke dalam DOM

Saya sudah melihat cara untuk memasukkan elemen ke dalam DOM. Mari beralih ke topik terkait dan melihat opsi penyisipan konten baru.

Pertama, ada metode insertBefore () sederhana, yang sangat mirip dengan replaceChild (), menerima dua argumen dan pada saat yang sama bekerja dengan elemen baru dan yang sudah ada. Inilah markupnya:

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam

Contoh Paragraf

Perhatikan paragrafnya, saya akan menghapusnya terlebih dahulu dan kemudian menyisipkannya sebelum daftar, semuanya dalam satu gerakan:

Var myList \u003d document.getElementById ("myList"), container \u003d document.getElementBy ("c"), myPar \u003d document.getElementById ("par"); container.insertBefore (myPar, myList);

Dalam HTML yang dihasilkan, paragraf akan ditempatkan sebelum daftar dan ini adalah cara lain untuk membungkus elemen.

Contoh Paragraf

  • Contoh satu
  • Contoh dua
  • Contoh tiga
  • Contoh empat
  • Contoh lima
  • Contoh Enam

Seperti replaceChild (), insertBefore () mengambil dua argumen: elemen yang akan ditambahkan dan elemen yang sebelumnya ingin kita sisipkan.

Cara ini sederhana. Sekarang mari kita coba cara yang lebih ampuh untuk menyisipkan: metode sisipanHTML ().

Biasanya, pengembang menggunakan jQuery saat mereka perlu melakukan sesuatu dengan DOM. Namun, hampir semua manipulasi DOM dapat dilakukan dalam JavaScript murni menggunakan API DOM-nya.

Mari kita lihat lebih dekat API ini:

Pada akhirnya, Anda akan menulis perpustakaan DOM Anda sendiri yang dapat digunakan dalam proyek apa pun.

Permintaan DOM

Kueri DOM dibuat menggunakan metode .querySelector (), yang menggunakan pemilih CSS arbitrer sebagai argumen.

Const myElement \u003d document.querySelector ("# foo\u003e div.bar")

Ini akan mengembalikan item pertama yang cocok. Atau, Anda dapat memeriksa apakah suatu elemen cocok dengan selektor:

MyElement.matches ("div.bar") \u003d\u003d\u003d benar

Jika Anda ingin mendapatkan semua elemen yang cocok dengan selektor, gunakan konstruksi berikut:

Const myElements \u003d document.querySelectorAll (". Bar")

Jika Anda mengetahui orang tua mana yang harus dirujuk, Anda dapat menelusuri turunannya alih-alih seluruh kode:

Const myChildElemet \u003d myElement.querySelector ("input") // Sebagai ganti: // document.querySelector ("# foo\u003e div.bar input")

Muncul pertanyaan: mengapa kemudian menggunakan metode lain yang kurang nyaman seperti .getElementsByTagName ()? Ada masalah kecil - keluaran dari keluaran .querySelector () tidak diperbarui, dan ketika kita menambahkan elemen baru (lihat) itu tidak berubah.

Konst // Salah

Juga querySelectorAll () mengumpulkan semuanya ke dalam satu daftar, yang membuatnya tidak terlalu efisien.

Bagaimana cara saya bekerja dengan daftar?

Selain itu, .querySelectorAll () memiliki dua nuansa kecil. Anda tidak bisa begitu saja memanggil metode pada hasil dan mengharapkannya berlaku untuk masing-masing (seperti yang mungkin biasa Anda lakukan dengan jQuery). Bagaimanapun, Anda perlu mengulang semua elemen dalam loop. Kedua, objek yang dikembalikan adalah daftar elemen, bukan array. Karenanya, metode array tidak akan berfungsi. Tentu saja, ada metode untuk daftar, seperti .forEach (), tetapi, sayangnya, mereka tidak cocok untuk semua kasus. Jadi lebih baik mengonversi daftar menjadi array:

// Menggunakan Array.from () Array.from (myElements) .forEach (doSomethingWithEachElement) // Atau prototipe Array (sebelum ES6) Array.prototype.forEach.call (myElements, doSomethingWithEachElement) // Lebih sederhana: .forEach.call (myElements , doSomethingWithEachElement)

Setiap elemen memiliki beberapa properti yang merujuk pada "keluarga".

MyElement.children myElement.firstElementChild myElement.lastElementChild myElement.previousElementSibling myElement.nextElementSibling

Karena antarmuka Elemen diwarisi dari antarmuka Node, properti berikut juga ada:

MyElement.childNodes myElement.firstChild myElement.lastChild myElement.previousSibling myElement.nextSibling myElement.parentNode myElement.parentElement

Properti sebelumnya merujuk ke elemen, sedangkan yang terakhir (dengan pengecualian .parentElement) bisa berupa daftar jenis elemen apa pun. Karenanya, Anda dapat memeriksa jenis elemen:

MyElement.firstChild.nodeType \u003d\u003d\u003d 3 // elemen ini akan menjadi node teks

Menambahkan Kelas dan Atribut

Sangat mudah untuk menambahkan kelas baru:

MyElement.classList.add ("foo") myElement.classList.remove ("bar") myElement.classList.toggle ("baz")

Menambahkan properti ke elemen sama persis dengan objek apa pun:

// Dapatkan nilai atribut const value \u003d myElement.value // Setel atribut sebagai properti elemen myElement.value \u003d "(! LANG: foo" // Для установки нескольких свойств используйте.Object.assign() Object.assign(myElement, { value: "foo", id: "bar" }) // Удаление атрибута myElement.value = null !}

Anda bisa menggunakan metode .getAttibute (), .setAttribute (), dan .removeAttribute (). Mereka akan segera mengubah atribut HTML elemen (sebagai lawan dari properti DOM), yang akan memicu penggambaran ulang browser (Anda dapat melihat semua perubahan dengan memeriksa elemen menggunakan alat pengembang browser). Gambar ulang seperti itu tidak hanya membutuhkan lebih banyak sumber daya daripada menyetel properti DOM, tetapi juga dapat menyebabkan kesalahan yang tidak terduga.

Biasanya, mereka digunakan untuk elemen yang tidak memiliki properti DOM yang sesuai, seperti colspan. Atau jika penggunaannya benar-benar diperlukan, misalnya, untuk properti HTML dalam warisan (lihat).

Menambahkan Gaya CSS

Mereka ditambahkan dengan cara yang sama seperti properti lainnya:

MyElement.style.marginLeft \u003d "2em"

Beberapa properti tertentu dapat disetel menggunakan .style, tetapi jika Anda ingin mendapatkan nilai setelah beberapa penghitungan, lebih baik menggunakan window.getComputedStyle (). Metode ini mengambil elemen dan mengembalikan CSSStyleDeclaration yang berisi gaya dari elemen itu sendiri dan induknya:

Window.getComputedStyle (myElement) .getPropertyValue ("margin-left")

Perubahan DOM

Anda dapat memindahkan elemen:

// Tambahkan elemen1 sebagai anak terakhir dari elemen2 elemen1.appendChild (elemen2) // Masukkan elemen2 sebagai anak elemen1 sebelum elemen3 elemen1.insertBefore (elemen2, elemen3)

Jika Anda tidak ingin pindah, tetapi perlu menyisipkan salinan, gunakan:

// Buat clone const myElementClone \u003d myElement.cloneNode () myParentElement.appendChild (myElementClone)

Metode .cloneNode () menggunakan nilai boolean sebagai argumen, jika benar, elemen turunan juga akan digandakan.

Anda tentu saja dapat membuat elemen baru:

Const myNewElement \u003d document.createElement ("div") const myNewTextNode \u003d document.createTextNode ("beberapa teks")

Dan kemudian masukkan seperti yang ditunjukkan di atas. Anda tidak akan dapat menghapus elemen secara langsung, tetapi Anda dapat melakukannya melalui elemen induk:

MyParentElement.removeChild (myElement)

Anda juga dapat melamar secara tidak langsung:

MyElement.parentNode.removeChild (myElement)

Metode untuk elemen

Setiap elemen memiliki properti seperti .innerHTML dan .textContent, mereka berisi kode HTML dan, karenanya, teks itu sendiri. Contoh berikut mengubah konten suatu elemen:

// Ubah HTML myElement.innerHTML \u003d `

Konten baru

beep boop beep boop

`// Ini menghapus konten myElement.innerHTML \u003d null // Tambahkan ke HTML myElement.innerHTML + \u003d` lanjutkan membaca ...

Mengubah HTML sebenarnya adalah ide yang buruk, karena ia kehilangan semua perubahan yang telah dibuat sebelumnya, dan juga membebani penangan acara. Lebih baik menggunakan metode ini hanya dengan membuang semua HTML dan menggantinya dengan salinan dari server. Seperti ini:

Const link \u003d document.createElement ("a") const text \u003d document.createTextNode ("lanjutkan membaca ...") const hr \u003d document.createElement ("hr") link.href \u003d "foo.html" link.appendChild ( teks) myElement.appendChild (tautan) myElement.appendChild (hr)

Namun, ini akan memerlukan dua penggambaran ulang di browser, sementara .innerHTML hanya akan menghasilkan satu. Anda dapat mengatasinya dengan terlebih dahulu menambahkan semuanya ke DocumentFragment, lalu menambahkan fragmen yang Anda inginkan:

Const fragment \u003d document.createDocumentFragment () fragment.appendChild (teks) fragment.appendChild (hr) myElement.appendChild (fragment)

Penangan acara

Salah satu penangan paling sederhana:

MyElement.onclick \u003d function onclick (event) (console.log (event.type + "dipecat"))

Tapi sebagai aturan, itu harus dihindari. Di sini .onclick adalah properti elemen, dan secara teori Anda dapat mengubahnya, tetapi Anda tidak dapat menambahkan penangan lain menggunakan fungsi lain yang merujuk ke yang lama.

Lebih baik menggunakan .addEventListener () untuk menambahkan penangan. Dibutuhkan tiga argumen: jenis acara, fungsi yang akan dipanggil setiap kali dipicu, dan objek konfigurasi (kita akan kembali ke ini nanti).

MyElement.addEventListener ("click", function (event) (console.log (event.type + "dipecat"))) myElement.addEventListener ("click", function (event) (console.log (event.type + ") dipecat lagi ")))

Properti event.target mengacu pada elemen tempat kejadian dilampirkan.

Dan inilah cara Anda dapat mengakses semua properti:

// Properti `forms` adalah larik yang berisi referensi ke semua bentuk const myForm \u003d document.forms const myInputElements \u003d myForm.querySelectorAll (" input ") Array.from (myInputElements) .forEach (el \u003d\u003e (el.addEventListener (" ubah ", fungsi (event) (console.log (event.target.value)))))

Mencegah tindakan default

Untuk ini, metode .preventDefault () digunakan, yang memblokir tindakan standar. Misalnya, ini akan memblokir pengiriman formulir jika otorisasi sisi klien tidak berhasil:

MyForm.addEventListener ("submit", function (event) (const name \u003d this.querySelector ("# name") if (name.value \u003d\u003d\u003d "(! LANG: Donald Duck") { alert("You gotta be kidding!") event.preventDefault() } }) !}

Metode .stopPropagation () akan membantu jika Anda memiliki penangan kejadian tertentu yang dilampirkan ke anak dan penangan kedua untuk acara yang sama yang dilampirkan ke induk.

Seperti disebutkan sebelumnya, metode .addEventListener () mengambil argumen ketiga opsional, yang merupakan objek konfigurasi. Objek ini harus berisi salah satu properti boolean berikut (secara default, semuanya salah):

  • capture: acara akan dilampirkan ke elemen ini sebelum elemen lain di bawah ini di DOM;
  • satu kali: acara hanya dapat disematkan sekali;
  • pasif: event.preventDefault () akan diabaikan (pengecualian selama kesalahan).

Properti yang paling umum adalah .capture, dan sangat umum sehingga ada cara singkat untuk menuliskannya: daripada meneruskannya ke objek config, cukup tentukan nilainya di sini:

MyElement.addEventListener (jenis, pendengar, benar)

Penangan dihapus menggunakan metode .removeEventListener (), yang mengambil dua argumen: jenis kejadian dan referensi ke penangan yang akan dihapus. Misalnya, properti Once dapat diimplementasikan seperti ini:

MyElement.addEventListener ("change", function listener (event) (console.log (event.type + "dipicu pada" + this) this.removeEventListener ("change", listener)))

Warisan

Katakanlah Anda memiliki sebuah elemen dan ingin menambahkan sebuah event handler untuk semua anaknya. Kemudian Anda harus mengulanginya menggunakan metode myForm.querySelectorAll ("input") seperti yang ditunjukkan di atas. Namun, Anda cukup menambahkan elemen ke formulir dan memeriksa kontennya menggunakan event.target.

MyForm.addEventListener ("change", function (event) (const target \u003d event.target if (target.matches ("input")) (console.log (target.value))))

Dan satu keuntungan lagi dari metode ini adalah bahwa handler akan secara otomatis mengikat ke elemen anak baru.

Animasi

Cara termudah untuk menambahkan animasi menggunakan CSS dengan properti transisi. Tetapi untuk lebih banyak fleksibilitas (misalnya, untuk permainan), JavaScript lebih cocok.

Memanggil metode window.setTimeout () hingga animasi selesai bukanlah ide yang baik, karena aplikasi Anda mungkin macet, terutama pada perangkat seluler. Lebih baik menggunakan window.requestAnimationFrame () untuk menyimpan semua perubahan hingga gambar ulang berikutnya. Ini mengambil fungsi sebagai argumen, yang pada gilirannya menerima stempel waktu:

Const mulai \u003d window.performance.now () durasi const \u003d 2000 window.requestAnimationFrame (fungsi fadeIn (sekarang)) (kemajuan const \u003d sekarang - mulai myElement.style.opacity \u003d kemajuan / durasi if (kemajuan< duration) { window.requestAnimationFrame(fadeIn) } }

Dengan cara ini, animasi yang sangat halus tercapai. Dalam artikelnya, Mark Brown membahas topik ini.

Menulis perpustakaan Anda

Fakta bahwa di DOM Anda harus mengulang elemen sepanjang waktu untuk melakukan operasi apa pun padanya bisa tampak sangat membosankan dibandingkan dengan sintaks jQuery $ (". Foo"). Css ((color: "red")). Tetapi mengapa tidak menulis beberapa metode Anda sendiri untuk membuat tugas ini lebih mudah?

Const $ \u003d function $ (selector, context \u003d document) (const elements \u003d Array.from (context.querySelectorAll (selector)) return (elemen, html (newHtml) (this.elements.forEach (element \u003d\u003e (element.innerHTML \u003d newHtml)) kembalikan ini), css (newCss) (this.elements.forEach (element \u003d\u003e (Object.assign (element.style, newCss))) kembalikan ini), on (event, handler, options) (this.elements .forEach (element \u003d\u003e (element.addEventListener (event, handler, options))) kembalikan ini)))



Pseudocode

$ (". rightArrow"). click (function () (rightArrowParents \u003d this.dom (); //. dom (); adalah fungsi pseudo ... itu harus menampilkan seluruh alert (rightArrowParents);));

Pesan alarmnya adalah:

body div.lol a.rightArrow

Bagaimana saya bisa mendapatkannya menggunakan javascript / jquery?

Menggunakan jQuery seperti ini (diikuti dengan solusi yang tidak menggunakan jQuery kecuali untuk sebuah acara, apalagi panggilan fungsi jika itu penting):

Contoh langsung:

$ (". rightArrow"). click (function () (var rightArrowParents \u003d; $ (this) .parents (). addBack (). not ("html"). each (function () (var entry \u003d this.tagName .toLowerCase (); if (this.className) (entry + \u003d "." + this.className.replace (/ / g, ".");) rightArrowParents.push (entry);)); alert (rightArrowParents.join ("")); return false;));

Klik disini

(Dalam contoh langsung, saya telah memperbarui atribut class pada div menjadi lol multi untuk mendemonstrasikan penanganan beberapa kelas.)

Berikut adalah solusi untuk mencocokkan item dengan tepat.

Penting untuk dipahami bahwa selector ( tidak nyata) yang ditampilkan alat chrome tidak secara unik mengidentifikasi elemen di DOM. ( misalnya, ini tidak akan membedakan antara daftar elemen rentang yang berurutan. Tidak ada informasi pemosisian / pengindeksan)

$ .fn.fullSelector \u003d function () (var path \u003d this.parents (). addBack (); var quickCss \u003d path.get (). map (function (item) (var self \u003d $ (item), id \u003d item .id? "#" + item.id: "", clss \u003d item.classList.length? item.classList.toString (). split ("") .map (function (c) (return "." + c; )). join (""): "", name \u003d item.nodeName.toLowerCase (), index \u003d self.siblings (name) .length? ": nth-child (" + (self.index () + 1) + ")": ""; if (name \u003d\u003d\u003d "html" || name \u003d\u003d\u003d "body") (return name;) return name + index + id + clss;)). join ("\u003e") ; kembali quickCss;);

Dan Anda bisa menggunakannya seperti ini:

Console.log ($ ("some-selector"). FullSelector ());

Saya memindahkan potongan dari T.J. Crowder ke plugin jQuery kecil. Saya menggunakan versi jQuery, meskipun dia benar bahwa itu benar-benar overhead yang tidak perlu, tetapi saya hanya menggunakannya untuk tujuan debugging, jadi saya tidak peduli.

Menggunakan:

Rentang bersarang
Rentang sederhana
Pra


// hasil (larik): ["body", "div.sampleClass"] $ ("span"). getDomPath (false) // result (string): body\u003e div.sampleClass $ ("span"). getDomPath ( ) // hasil (larik): ["body", "div # test"] $ ("pre"). getDomPath (false) // result (string): body\u003e div # test $ ("pre"). getDomPath ()

Var obj \u003d $ ("# show-editor-button"), path \u003d ""; while (typeof obj.prop ("tagName")! \u003d "undefined") (if (obj.attr ("class")) (path \u003d "." + obj.attr ("class"). replace (/ \\ s / g, ".") + jalur;) if (obj.attr ("id")) (jalur \u003d "#" + obj.attr ("id") + jalur;) jalur \u003d "" + obj.prop ( "tagName"). toLowerCase () + jalur; obj \u003d obj.parent ();) console.log (jalur);

halo fungsi ini menyelesaikan kesalahan yang terkait dengan elemen saat ini yang tidak ditampilkan di jalur

Lihat sekarang

$ j (". wrapper"). click (function (event) (selectedElement \u003d $ j (event.target); var rightArrowParents \u003d; $ j (event.target) .parents (). bukan ("html, body") .each (function () (var entry \u003d this.tagName.toLowerCase (); if (this.className) (entri + \u003d "." + this.className.replace (/ / g, ".");) lain jika (this.id) (entri + \u003d "#" + this.id;) entri \u003d replaceAll (entri, "..", "."); rightArrowParents.push (entri);)); rightArrowParents.reverse (); //if(event.target.nodeName.toLowerCase()\u003d\u003d"a "|| event.target.nodeName.toLowerCase () \u003d\u003d" h1 ") (var entry \u003d event.target.nodeName.toLowerCase (); jika (event.target.className) (entri + \u003d "." + event.target.className.replace (/ / g, ".");) else if (event.target.id) (entri + \u003d "#" + event.target.id;) rightArrowParents.push (entri); //)

Dimana $ j \u003d jQuery Variable

juga memecahkan masalah dengan .. di nama kelas

inilah fungsi ganti:

Fungsi escapeRegExp (str) (kembalikan str.replace (/ ([. * +? ^ \u003d !: $ () () | \\ [\\] \\ / \\\\]) / g, "\\\\ $ 1");) function replaceAll (str, find, replace) (return str.replace (new RegExp (escapeRegExp (find), "g"), replace);)

Berikut adalah versi JS asli yang mengembalikan jalur jQuery. Saya juga menambahkan ID untuk elemen, jika ada. Ini akan memberi Anda kemampuan untuk membuat jalur terpendek jika Anda melihat id dalam larik.

Var path \u003d getDomPath (elemen); console.log (path.join ("\u003e"));

Body\u003e section: eq (0)\u003e div: eq (3)\u003e section # content\u003e section # firehose\u003e div # firehoselist\u003e article # firehose-46813651\u003e header\u003e h2\u003e span # title-46813651

Ini fungsinya.

Fungsi getDomPath (el) (var stack \u003d; while (el.parentNode! \u003d Null) (console.log (el.nodeName); var sibCount \u003d 0; var sibIndex \u003d 0; for (var i \u003d 0; i< el.parentNode.childNodes.length; i++) { var sib = el.parentNode.childNodes[i]; if (sib.nodeName == el.nodeName) { if (sib === el) { sibIndex = sibCount; } sibCount++; } } if (el.hasAttribute("id") && el.id != "") { stack.unshift(el.nodeName.toLowerCase() + "#" + el.id); } else if (sibCount > 1) (stack.unshift (el.nodeName.toLowerCase () + ": eq (" + sibIndex + ")");) else (stack.unshift (el.nodeName.toLowerCase ());) el \u003d el.parentNode ; ) mengembalikan stack.slice (1); // menghapus elemen html)