Rumah >hujung hadapan web >tutorial js >Mendedahkan keajaiban javascript
Takeaways Key
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>Hasilnya adalah elemen
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>Kami menentukan kaedah utiliti kami sendiri StringTodom yang mencipta elemen
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>secara visual, pada halaman, tidak ada perbezaan. Walau bagaimanapun, jika kita menyemak markup yang dihasilkan dengan alat pemaju Chrome, kita akan mendapat hasil yang menarik:
Ia kelihatan seperti fungsi StringTodom kami yang dibuat hanya nod teks dan bukan tag
JQuery berjaya menyelesaikan masalah dengan mewujudkan konteks yang betul dan mengekstrak hanya bahagian yang diperlukan. Jika kita menggali sedikit ke dalam kod perpustakaan kita akan melihat peta seperti ini:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
Setiap elemen yang memerlukan rawatan khas mempunyai array yang diberikan. Idea ini adalah untuk membina elemen DOM yang betul dan bergantung kepada tahap sarang untuk mengambil apa yang kita perlukan. Sebagai contoh, untuk elemen
Mempunyai peta, kita perlu mengetahui jenis tag yang kita mahu pada akhirnya. Kod berikut mengekstrak TR dari
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
selebihnya mencari konteks yang betul dan mengembalikan elemen DOM. Berikut adalah varian akhir fungsi StringTodom:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
Perhatikan bahawa kami sedang menyemak jika terdapat tag dalam rentetan - padanan! = Null. Jika tidak kita hanya mengembalikan nod teks. Masih terdapat penggunaan sementara
Berikut adalah codepen yang menunjukkan pelaksanaan kami:
Lihat pena XLCGN oleh Krasimir Tsonev (@Krasimir) pada codepen.
mari kita teruskan dengan meneroka suntikan ketergantungan AngularJS yang indah.
Apabila kita mula menggunakan AngularJS, ia mengesankan dengan mengikat data dua hala. Perkara kedua yang kami perhatikan ialah suntikan pergantungan ajaibnya. Berikut adalah contoh mudah:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
Itulah pengawal AngularJS yang tipikal. Ia melakukan permintaan HTTP, mengambil data dari fail JSON, dan lulus ke skop semasa. Kami tidak melaksanakan fungsi Todoctrl - kami tidak mempunyai peluang untuk lulus sebarang hujah. Rangka kerja itu. Jadi, di manakah skop $ ini dan pembolehubah HTTP $ datang? Ia adalah ciri super sejuk, yang sangat menyerupai sihir hitam. Mari kita lihat bagaimana ia dilakukan.
Kami mempunyai fungsi JavaScript yang memaparkan pengguna dalam sistem kami. Fungsi yang sama memerlukan akses kepada elemen DOM untuk meletakkan HTML yang dihasilkan, dan pembungkus Ajax untuk mendapatkan data. Untuk memudahkan contoh, kami akan mengejek data dan HTTP meminta.
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
Kami akan menggunakan tag
sebagai pemegang kandungan. AjaxWrapper adalah objek yang mensimulasikan permintaan dan Datamockup adalah array yang mengandungi pengguna kami. Inilah fungsi yang akan kita gunakan:<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
Dan tentu saja, jika kita menjalankan paparan (badan, ajaxwrapper) kita akan melihat tiga nama yang dipaparkan pada halaman dan /API /pengguna yang diminta dalam konsol kami. Kita boleh mengatakan bahawa kaedah kita mempunyai dua kebergantungan - badan dan AjaxWrapper. Oleh itu, sekarang idea itu adalah untuk membuat fungsi berfungsi tanpa lulus argumen, iaitu kita perlu mendapatkan hasil yang sama dengan memanggil hanya displayusers (). Sekiranya kita berbuat demikian dengan kod setakat ini, hasilnya akan menjadi:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
dan itu normal kerana parameter Ajax tidak ditakrifkan.
Kebanyakan rangka kerja yang menyediakan mekanisme untuk suntikan ketergantungan mempunyai modul, biasanya dinamakan penyuntik . Untuk menggunakan kebergantungan, kita perlu mendaftarkannya di sana. Kemudian, pada satu ketika, sumber kami diberikan kepada logik aplikasi dengan modul yang sama.
mari buat penyuntik kami:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
kita hanya memerlukan dua kaedah. Yang pertama, mendaftar, menerima sumber (kebergantungan) kami dan menyimpannya secara dalaman. Yang kedua menerima sasaran suntikan kami - fungsi yang mempunyai kebergantungan dan perlu menerimanya sebagai parameter. Momen utama di sini ialah penyuntik tidak boleh memanggil fungsi kami. Itulah tugas kita dan kita harus dapat mengawalnya. Apa yang boleh kita lakukan dalam kaedah penyelesaian adalah untuk mengembalikan penutupan yang membungkus sasaran dan memanggilnya. Contohnya:
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>Menggunakan pendekatan itu, kita akan berpeluang memanggil fungsi dengan kebergantungan yang diperlukan. Dan pada masa yang sama kita tidak mengubah aliran kerja permohonan. Penyuntik masih sesuatu yang bebas dan tidak memegang fungsi berkaitan logik.
Sudah tentu, lulus fungsi Displayusers ke kaedah penyelesaian tidak membantu.
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>Kami masih mendapat ralat yang sama. Langkah seterusnya adalah untuk mengetahui keperluan sasaran yang diluluskan. Apakah kebergantungannya? Dan inilah bahagian rumit yang dapat kita pakai dari AngularJS. Saya, sekali lagi, menggali sedikit ke dalam kod rangka kerja dan mendapati ini:
<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>Kami sengaja melangkau beberapa bahagian, kerana mereka lebih seperti butiran pelaksanaan. Itulah kod yang menarik untuk kami. Fungsi Annotate adalah seperti kaedah penyelesaian kami. Ia menukarkan fungsi sasaran yang diluluskan ke rentetan, menghilangkan komen (jika ada), dan mengekstrak argumen. Mari kita gunakan dan lihat hasilnya:
<span>var dataMockup = ['John', 'Steve', 'David']; </span><span>var body = document.querySelector('body'); </span><span>var ajaxWrapper = { </span> <span>get: function(path<span>, cb</span>) { </span> <span>console.log(path + ' requested'); </span> <span>cb(dataMockup); </span> <span>} </span><span>}</span>inilah output dalam konsol:
Jika kita mendapat elemen kedua array argdecl kita akan dapati nama -nama kebergantungan yang diperlukan. Itulah yang kita perlukan, kerana mempunyai nama -nama kita akan dapat menyampaikan sumber dari penyimpanan penyuntik. Berikut adalah versi yang berfungsi dan berjaya merangkumi matlamat kami:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
Perhatikan bahawa kami menggunakan .split (/,?/g) untuk menukar rentetan domel, ajax ke array. Selepas itu kami menyemak jika kebergantungan didaftarkan dan jika ya kami lulus mereka ke fungsi sasaran. Kod di luar penyuntik kelihatan seperti itu:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
manfaat pelaksanaan sedemikian adalah bahawa kita boleh menyuntik elemen DOM dan pembalut Ajax dalam banyak fungsi. Kami juga boleh mengedarkan konfigurasi aplikasi kami seperti itu. Tidak perlu lulus objek dari kelas ke kelas. Ia hanya mendaftar dan menyelesaikan kaedah.
Sudah tentu penyuntik kami tidak sempurna. Masih terdapat beberapa ruang untuk penambahbaikan, seperti contoh sokongan definisi skop. Fungsi sasaran sekarang dipanggil dengan skop yang baru dibuat, tetapi biasanya kita akan mahu lulus sendiri. Kami harus menyokong juga menghantar hujah -hujah tersuai bersama -sama dengan kebergantungan.
Penyuntik menjadi lebih rumit jika kita mahu menyimpan kod kita selepas minifikasi. Seperti yang kita tahu minifiers menggantikan nama -nama fungsi, pembolehubah dan juga argumen kaedah. Dan kerana logik kita bergantung pada nama -nama ini kita perlu memikirkan penyelesaian. Satu penyelesaian yang mungkin sekali lagi datang dari AngularJS:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
bukannya hanya displayusers kita lulus nama dependensi sebenar.
Contoh kami dalam tindakan:
Lihat pena bxdar oleh Krasimir Tsonev (@krasimir) pada codepen.
Ember adalah salah satu rangka kerja yang paling popular pada masa kini. Ia mempunyai banyak ciri berguna. Terdapat satu yang sangat menarik - sifat yang dikira. Ringkasnya, sifat yang dikira adalah fungsi yang bertindak sebagai sifat. Mari kita lihat contoh mudah yang diambil dari dokumentasi Ember:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
Terdapat kelas yang mempunyai NameName dan LastName Properties. FullName harta yang dikira mengembalikan rentetan yang disatukan yang mengandungi nama penuh orang itu. Perkara yang pelik adalah bahagian di mana kita menggunakan kaedah .property terhadap fungsi yang digunakan untuk FullName. Saya secara peribadi tidak melihatnya di tempat lain. Dan, sekali lagi, melihat kod rangka kerja yang cepat mendedahkan sihir:
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>
Perpustakaan tweak prototaip objek fungsi global dengan menambahkan harta baru. Ia adalah pendekatan yang bagus untuk menjalankan beberapa logik semasa definisi kelas.
Ember menggunakan getters dan setters untuk beroperasi dengan data objek. Itu memudahkan pelaksanaan sifat -sifat yang dikira kerana kita mempunyai satu lagi lapisan sebelum mencapai pembolehubah sebenar. Walau bagaimanapun, ia akan menjadi lebih menarik jika kita dapat menggunakan sifat yang dikira dengan objek JavaScript biasa. Seperti contohnya:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
Nama digunakan sebagai harta biasa tetapi dalam amalan adalah fungsi yang mendapat atau menetapkan nama pertama dan lastname.
Terdapat ciri pembina JavaScript yang dapat membantu kita merealisasikan idea itu. Lihat coretan berikut:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
Kaedah Object.Defineproperty boleh menerima skop, nama harta, getter, dan setter. Apa yang perlu kita lakukan ialah menulis badan kedua -dua kaedah. Dan itu sahaja. Kami akan dapat menjalankan kod di atas dan kami akan mendapat hasil yang diharapkan:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
Object.Defineproperty adalah apa yang kita perlukan, tetapi kita tidak mahu memaksa pemaju untuk menulisnya setiap kali. Kita mungkin perlu menyediakan polyfill, menjalankan logik tambahan, atau sesuatu seperti itu. Dalam kes yang ideal, kami ingin menyediakan antara muka yang serupa dengan Ember. Hanya satu fungsi adalah sebahagian daripada definisi kelas. Dalam bahagian ini, kami akan menulis fungsi utiliti yang dipanggil mengira yang akan memproses objek kami dan entah bagaimana akan menukar fungsi nama ke harta dengan nama yang sama.
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
Kami mahu menggunakan kaedah nama sebagai setter, dan pada masa yang sama sebagai getter. Ini serupa dengan sifat -sifat yang dikira oleh Ember.
Sekarang mari kita tambahkan logik kita sendiri ke dalam prototaip objek fungsi:
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>
Sebaik sahaja kita menambah baris di atas, kita akan dapat menambah. Komput () hingga akhir setiap definisi fungsi:
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>
Akibatnya, harta nama tidak mengandungi fungsi lagi, tetapi objek yang telah mengira harta yang sama dengan harta yang benar dan func yang diisi dengan fungsi lama. Keajaiban sebenar berlaku dalam pelaksanaan pembantu mengira. Ia melalui semua sifat objek dan menggunakan objek.defineproperty di mana kita telah mengira sifat:
<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>
Perhatikan bahawa kami memadamkan nama harta asal. Dalam beberapa objek penyemak imbas.Defineproperty hanya berfungsi pada sifat yang belum ditakrifkan.
di sini adalah versi akhir objek pengguna yang menggunakan.Fungsi yang mengembalikan nama penuh digunakan untuk menukar nama firstName dan lastName. Itulah idea di sebalik pemeriksaan hujah -hujah yang diluluskan dan memproses yang pertama. Sekiranya ada, kita memisahkannya dan menggunakan nilai -nilai kepada sifat -sifat biasa.
<span>var dataMockup = ['John', 'Steve', 'David']; </span><span>var body = document.querySelector('body'); </span><span>var ajaxWrapper = { </span> <span>get: function(path<span>, cb</span>) { </span> <span>console.log(path + ' requested'); </span> <span>cb(dataMockup); </span> <span>} </span><span>}</span>
Kami sudah menyebut penggunaan yang dikehendaki, tetapi mari kita lihat sekali lagi:
codepen berikut menunjukkan kerja kami dalam amalan:
<span>var displayUsers = function(domEl<span>, ajax</span>) { </span> ajax<span>.get('/api/users', function(users) { </span> <span>var html = ''; </span> <span>for(var i=0; i < users.length; i++) { </span> html <span>+= '<p>' + users[i] + '</p>'; </span> <span>} </span> domEl<span>.innerHTML = html; </span> <span>}); </span><span>}</span>
Lihat pena ahpqo oleh Krasimir Tsonev (@Krasimir) di Codepen.
Anda mungkin pernah mendengar tentang Rangka Kerja Facebook. Ia dibina di sekitar idea bahawa semuanya adalah komponen. Apa yang menarik ialah definisi komponen. Mari kita lihat contoh berikut:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
Perkara pertama yang kita mulakan adalah bahawa ini adalah JavaScript, tetapi ia adalah yang tidak sah. Terdapat fungsi render, dan ia mungkin akan membuang kesilapan. Walau bagaimanapun, silap mata ialah kod ini dimasukkan ke dalam
Pendekatan yang diambil Facebook adalah untuk mencampur kod JavaScript dengan markup HTML. Oleh itu, katakanlah bahawa kita mempunyai templat berikut:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
dan komponen yang menggunakannya:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
Ideanya ialah kami menunjukkan ID templat dan menentukan data yang perlu digunakan. Sekeping pelaksanaan terakhir kami adalah enjin sebenar yang menggabungkan kedua -dua elemen tersebut. Mari kita panggil enjin dan mulakannya seperti itu:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
Kami mendapat kandungan tag
Sekarang, mari tulis fungsi parse kami. Tugas pertama kami adalah untuk membezakan HTML dari ekspresi. Dengan ungkapan, kami bermaksud rentetan yang diletakkan di antara . Kami akan menggunakan regex untuk mencari mereka dan gelung semasa yang mudah untuk melalui semua perlawanan:
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>
Hasil dari kod di atas adalah seperti berikut:
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>
Hanya ada satu ungkapan dan kandungannya adalah tajuk. Pendekatan intuitif pertama yang boleh kita ambil ialah menggunakan fungsi pengganti JavaScript dan menggantikan dengan data dari objek Comp yang diluluskan. Walau bagaimanapun, ini akan berfungsi hanya dengan sifat mudah. Bagaimana jika kita mempunyai objek bersarang atau bahkan jika kita mahu menggunakan fungsi. Seperti contohnya:
<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>
Daripada membuat parser kompleks dan hampir mencipta bahasa baru kita boleh menggunakan JavaScript tulen. Satu -satunya perkara yang perlu kita lakukan ialah menggunakan sintaks fungsi baru.
<span>var dataMockup = ['John', 'Steve', 'David']; </span><span>var body = document.querySelector('body'); </span><span>var ajaxWrapper = { </span> <span>get: function(path<span>, cb</span>) { </span> <span>console.log(path + ' requested'); </span> <span>cb(dataMockup); </span> <span>} </span><span>}</span>
kita dapat membina badan fungsi yang kemudian dilaksanakan. Jadi, kita tahu kedudukan ekspresi kita dan apa yang sebenarnya berdiri di belakang mereka. Jika kita menggunakan array sementara dan kursor kita sementara kitaran akan kelihatan seperti itu:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
output dalam konsol menunjukkan bahawa kita berada di landasan yang betul:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
Arahan kod harus diubah menjadi rentetan yang akan menjadi badan fungsi. Contohnya:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>Ia agak mudah untuk mencapai hasil ini. Kami boleh menulis gelung yang melalui semua elemen array kod dan cek jika item itu adalah rentetan atau objek. Walau bagaimanapun, ini sekali lagi merangkumi sebahagian daripada kes. Bagaimana jika kita mempunyai templat berikut:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>kita tidak boleh menggabungkan ungkapan dan mengharapkan warna yang disenaraikan. Oleh itu, bukannya memasuki rentetan untuk rentetan, kami akan mengumpulnya dalam array. Berikut adalah versi terkini fungsi parse:
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>Setelah array kod diisi, kami mula membina badan fungsi. Setiap baris templat akan disimpan dalam r. Jika garis adalah rentetan, kami membersihkannya sedikit dengan melepaskan petikan dan mengeluarkan baris dan tab baru. Ia ditambah kepada array melalui kaedah push. Jika kita mempunyai coretan kod maka kita periksa sama ada ia bukan pengendali JavaScript yang sah. Jika ya maka kita tidak menambahkannya ke array tetapi hanya menjatuhkannya sebagai garis baru. Konsol.log pada output akhir:
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>Bagus, bukan? JavaScript yang berfungsi dengan betul, yang dilaksanakan dalam konteks komponen kami akan menghasilkan markup HTML yang dikehendaki.
perkara terakhir yang tersisa adalah berjalan sebenar fungsi kami yang hampir dibuat:
<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>Kami membungkus kod kami dengan pernyataan untuk menjalankannya dalam konteks komponen. Tanpa itu kita perlu menggunakan ini.Title dan this.colors dan bukannya tajuk dan warna.
Berikut adalah codepen yang menunjukkan hasil akhir:
Lihat pena gahej oleh Krasimir Tsonev (@krasimir) pada codepen.
Ringkasan
kod dari artikel ini tersedia untuk dimuat turun dari GitHub
Soalan Lazim (Soalan Lazim) Mengenai Keajaiban JavaScript
Kaedah sihir dalam JavaScript boleh digunakan dengan menentukannya dalam objek atau kelas anda. Sebagai contoh, anda boleh menentukan kaedah ToString () dalam objek anda untuk menyesuaikan bagaimana objek anda akan diwakili sebagai rentetan. Berikut adalah contoh mudah:
biarkan person = {
firstName: "John",
lastName: "doe",
toString: function () {
kembali ini.firstname " "this.lastName;
}
};
console.log (person.toString ()); // "John Doe"
Bagaimanakah JavaScript mengendalikan kaedah sihir berbanding dengan bahasa pengaturcaraan lain? "Kaedah Magic". Walau bagaimanapun, ia mempunyai kaedah tertentu yang berkelakuan sama, seperti ToString () dan ValueOf (). Kaedah ini secara automatik dipanggil dalam situasi tertentu, seperti kaedah sihir dalam bahasa lain. Sertakan pemahaman bila dan mengapa menggunakannya, menggunakannya dengan berhati -hati untuk mengelakkan kerumitan, dan sentiasa menguji kod anda dengan teliti untuk memastikan ia berkelakuan seperti yang diharapkan.
Bolehkah kaedah sihir digunakan dengan kerangka JavaScript seperti React atau Vue? Walau bagaimanapun, cara mereka digunakan mungkin berbeza -beza bergantung kepada rangka kerja. Selalu terbaik untuk merujuk kepada dokumentasi rangka kerja khusus untuk panduan.
Atas ialah kandungan terperinci Mendedahkan keajaiban javascript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!