Porting aplikasi web Anda dari JavaScript murni ke Vue.js

Vue.js adalah kerangka kerja pengembangan aplikasi web. Ini memiliki sistem reaktivitas yang memungkinkan pengembang untuk mensimulasikan keadaan aplikasi dan mengelolanya. Akibatnya, ketika data berubah, secara otomatis mencerminkan antarmuka pengguna, sementara pengembang tidak perlu mengakses DOM. Jika Anda membuat aplikasi menggunakan JavaScript murni atau jQuery, ini berarti Anda harus secara eksplisit mengakses elemen DOM dan memperbaruinya untuk mencerminkan perubahan dalam keadaan aplikasi di antarmuka, misalnya, menampilkan beberapa data di halaman web.


Dalam kasus proyek besar, mengelola sinkronisasi keadaan dan antarmuka aplikasi secara manual bukanlah pekerjaan yang mudah. Penulis materi, terjemahan yang kami sajikan untuk perhatian Anda hari ini, ingin berbagi beberapa hasil penelitiannya yang bertujuan membandingkan dua versi aplikasi web progresif menggunakan Hoodie , yang merupakan daftar belanja . Versi dasar dari aplikasi ini ditulis dalam JS murni (dalam artikel ini Anda dapat menemukan detailnya). Di sini terjemahan aplikasi ke Vue.js akan diperlihatkan dengan pemeriksaan kelulusan dari fitur-fitur dasar dari kerangka kerja ini dan dengan analisis tentang apa yang terjadi pada akhirnya.


Aplikasi siap

Jika Anda ingin mengerjakan materi ini, Anda dapat mengunduh kode sumber aplikasi dalam JS murni dan mengikuti pembuatnya, memprosesnya menggunakan Vue.

Menambahkan produk ke daftar


▍JavaScript


Aplikasi ini memungkinkan pengguna untuk menambahkan produk ke daftar belanja mereka. Ini dilakukan dalam file index.html di folder publik . Markup terkandung dalam baris 92-124 dari file ini. Itu dia.

 <div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="text" id="new-item-name">     <label class="mdl-textfield__label" for="new-item-name">Item Name</label> </div> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-cost">     <label class="mdl-textfield__label" for="new-item-cost">Item Cost</label> </div> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-quantity">     <label class="mdl-textfield__label" for="new-item-quantity">Quantity</label> </div> </div> <div class="mdl-grid center-items"> <button id="add-item" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">     Add Item </button> </div> </div> 

Kode untuk memproses dan menyimpan data ada di file public/js/src/index.js . Fungsi saveItems() pada baris 28 bertanggung jawab untuk mengumpulkan nilai-nilai dari kontrol yang digunakan untuk memasukkan data dan untuk menyimpan data itu. Fungsi ini terikat pada acara click tombol add-item . Berikut ini kode yang dimaksud.

 function saveNewitem() { let name = document.getElementById("new-item-name").value; let cost = document.getElementById("new-item-cost").value; let quantity = document.getElementById("new-item-quantity").value; let subTotal = cost * quantity; if (name && cost && quantity) {   hoodie.store.withIdPrefix("item").add({     name: name,     cost: cost,     quantity: quantity,     subTotal: subTotal   });   document.getElementById("new-item-name").value = "";   document.getElementById("new-item-cost").value = "";   document.getElementById("new-item-quantity").value = ""; } else {   let snackbarContainer = document.querySelector("#toast");   snackbarContainer.MaterialSnackbar.showSnackbar({     message: "All fields are required"   }); } } document.getElementById("add-item").addEventListener("click", saveNewitem); 

UeVue


Sebelum mulai mengerjakan ulang proyek ini menggunakan Vue, Anda perlu menghubungkan kerangka kerja ke halaman. Dalam kasus kami, dalam file index.html , ini dilakukan sebagai berikut:

 <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script> 

Selain itu, elemen <div> telah ditambahkan dengan app pengenal, yang akan mencakup semua elemen halaman yang terletak di dalam tag body . Ini karena ketika instance Vue diinisialisasi, kerangka kerja perlu diinformasikan tentang bagian halaman mana yang harus dikelola. Dalam hal ini, kami memberi tahu kerangka kerja bahwa itu harus berurusan dengan semua yang ada di blok ini.

Sekarang mari kita mulai menerjemahkan proyek ke Vue. Pertama, kami memodifikasi markup untuk menggunakan beberapa arahan Vue. Arahan Vue adalah atribut khusus yang diawali dengan v- . Beginilah tampilan markup yang diperbarui.

 <form v-on:submit.prevent="onSubmit"> <div class="mdl-grid center-items">   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="text" id="new-item-name" v-model="name">     <label class="mdl-textfield__label" for="new-item-name">Item Name</label>   </div>   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-cost" v-model.number="cost">     <label class="mdl-textfield__label" for="new-item-cost">Item Cost</label>   </div>   <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">     <input class="mdl-textfield__input" type="number" id="new-item-quantity" v-model.number="quantity">     <label class="mdl-textfield__label" for="new-item-quantity">Quantity</label>   </div> </div> <div class="mdl-grid center-items">   <button id="add-item" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">     Add Item   </button> </div> </form> 

Arahan v-on digunakan di sini digunakan untuk mendengarkan acara DOM. Dalam cuplikan kode di atas, ini digunakan dalam elemen formulir untuk mendengarkan acara pengiriman. Selain itu, ia menggunakan pengubah .prevent , yang memberitahu arahan v-on untuk memanggil event.preventDefault() pada acara yang dipanggil. Kami menggunakan direktif v-model untuk elemen yang digunakan untuk entri data. Diperlukan, sebagaimana diterapkan untuk membentuk elemen, untuk membuat pengikatan data dua arah. Ini memungkinkan sistem untuk secara otomatis memilih cara yang benar untuk memperbarui item berdasarkan jenisnya. Kami menggunakan .number modifier untuk elemen cost dan quantity .

Ini secara otomatis mengubah tipe nilai dari bidang input ke angka. Ini dilakukan karena walaupun tipe diatur ke type=number , nilainya akan selalu dikembalikan sebagai string. Pengubah yang digunakan di sini mengotomatiskan pelaksanaan pemeriksaan tambahan yang sebelumnya harus dilakukan secara independen.

Selanjutnya, buat file baru, index-vue.js , di mana kami menempatkan kode yang setara dengan yang ada di index.js , tetapi menggunakan kemampuan Vue. Kode untuk file ini ditunjukkan di bawah ini. Ini menciptakan instance Vue dengan properti yang diperlukan untuk memproses event form dan mengumpulkan data.

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "" }, methods: {   onSubmit: function(event) {     if (this.name && this.cost && this.quantity) {       hoodie.store.withIdPrefix("item").add({         name: this.name,         cost: this.cost,         quantity: this.quantity,         subTotal: this.cost * this.quantity       });       this.name = "";       this.cost = "";       this.quantity = "";     } else {       const snackbarContainer = document.querySelector("#toast");       snackbarContainer.MaterialSnackbar.showSnackbar({         message: "All fields are required"       });     }   } } }); 

Sebuah instance Vue dibuat dalam cuplikan kode ini, dan sebuah objek diteruskan ke sana, memberi tahu Vue cara mengkonfigurasi aplikasi. Properti el memberitahu kerangka kerja pengidentifikasi elemen DOM, yang isinya akan dikontrol oleh Vue, dengan mempertimbangkannya sebagai "wilayah". Dalam elemen ini Vue akan mempertimbangkan arahan spesifik kerangka kerja (dan segala sesuatu yang terkait dengan Vue), dan, dalam proses inisialisasi kerangka kerja, Vue akan mengonfigurasi bindings dan event handler untuk aplikasi.

Properti data berisi status aplikasi. Semua properti di objek yang tersedia di sini akan, ketika menginisialisasi Vue, ditambahkan ke sistem respons kerangka kerja. Ini adalah tindakan dari sistem ini yang mengarah pada pembaruan antarmuka pengguna ketika mengubah nilai yang terkait dengan DOM. Misalnya, properti name terikat ke kontrol name menggunakan arahan v-model="name" . Arahan ini mengatur data dua arah yang mengikat antara properti dan kontrol sedemikian rupa sehingga ketika sesuatu ditambahkan ke bidang input (atau sesuatu dihapus dari itu), properti name diperbarui. Akibatnya, isi bidang input mencerminkan kondisi properti name ini.

Demikian pula, pengikatan bekerja dengan kontrol lain.

Properti methods berisi fungsi. Dalam kode di atas, fungsi onSubmit() , yang dilampirkan pada acara form submit() .

Menampilkan data yang disimpan pada halaman


▍JavaScript


Fungsi onSubmit menyimpan data dalam hoodie. Setelah itu, kita perlu menampilkan, dalam bentuk tabel, item yang ditambahkan ke repositori. Dalam kasus aplikasi yang ditulis dalam JS biasa, markup yang sesuai terlihat seperti ini:

 <div class="mdl-grid center-items"> <table id="item-table" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">   <thead>     <tr>       <th class="mdl-data-table__cell--non-numeric">Item Name</th>       <th class="mdl-data-table__cell--non-numeric">Cost</th>       <th class="mdl-data-table__cell--non-numeric">Quantity</th>       <th class="mdl-data-table__cell">Sub-total</th>       <th class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon">           <i class="material-icons">delete</font></i>         </button>       </th>     </tr>   </thead>   <tbody>   </tbody> </table> </div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">   <input class="mdl-textfield__input" type="number" id="total-cost" readonly value="0">   <label class="mdl-textfield__label" for="cost">Total Item Cost</label> </div> </div> <script id="item-row" type="text/template"> <tr id='{{row-id}}'>        <td class="mdl-data-table__cell--non-numeric">{{name}}</td>   <td class="mdl-data-table__cell--non-numeric">{{cost}}</td>   <td class="mdl-data-table__cell--non-numeric">{{quantity}}</td>   <td class="mdl-data-table__cell">{{subTotal}}</td>   <td class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored"         onclick="pageEvents.deleteItem('{{item-id}}')">         <i class="material-icons">remove</font></i>         </button>   </td> </tr> </script> 

Tabel akan berisi data yang ditambahkan secara dinamis, jadi di sini kita perlu beberapa cara untuk mengganti placeholder dengan data nyata dan melampirkan apa yang terjadi pada DOM. Dalam kasus kami, masalah ini diselesaikan menggunakan template mikro.

Kode berikut menunjukkan elemen-elemen dalam antarmuka pengguna saat ditambahkan.

 function addItemToPage(item) { if (document.getElementById(item._id)) return; let template = document.querySelector("#item-row").innerHTML; template = template.replace("{{name}}", item.name); template = template.replace("{{cost}}", item.cost); template = template.replace("{{quantity}}", item.quantity); template = template.replace("{{subTotal}}", item.subTotal); template = template.replace("{{row-id}}", item._id); template = template.replace("{{item-id}}", item._id); document.getElementById("item-table").tBodies[0].innerHTML += template; let totalCost = Number.parseFloat(   document.getElementById("total-cost").value ); document.getElementById("total-cost").value = totalCost + item.subTotal; } hoodie.store.withIdPrefix("item").on("add", addItemToPage); 

Dalam fragmen kode ini, templat diperoleh dari DOM, placeholder diganti dengan data nyata, dan hasilnya dilampirkan ke DOM. Kemudian indikator total-cost dihitung, jumlah total untuk semua elemen daftar, yang juga ditampilkan di antarmuka.

UeVue


Saat beralih ke Vue, templat yang digunakan oleh skrip telah dihapus, dan elemen tabel dirancang ulang sehingga mereka menggunakan direktif Vue v-for , yang memungkinkan Anda untuk mengulang-ulang properti yang berisi data elemen. Beginilah tampilan markup yang sesuai sekarang.

 <div class="mdl-grid center-items"> <table id="item-table" class="mdl-data-table mdl-js-data-table mdl-shadow--2dp">   <thead>     <tr>       <th class="mdl-data-table__cell--non-numeric">Item Name</th>       <th class="mdl-data-table__cell--non-numeric">Cost</th>       <th class="mdl-data-table__cell--non-numeric">Quantity</th>       <th class="mdl-data-table__cell">Sub-total</th>       <th class="mdl-data-table__cell--non-numeric">         <button class="mdl-button mdl-js-button mdl-button--icon">           <i class="material-icons">delete</font></i>         </button>       </th>     </tr>   </thead>   <tbody>     <tr v-for="item in items" :key="item._id">       <td class="mdl-data-table__cell--non-numeric">{{ item.name}}</td>       <td class="mdl-data-table__cell--non-numeric">{{ item.cost}}</td>       <td class="mdl-data-table__cell--non-numeric">{{ item.quantity}}</td>       <td class="mdl-data-table__cell">{{ item.subTotal}}</td>       <td class="mdl-data-table__cell--non-numeric">         <button @click="deleteRow(item._id)" class="mdl-button mdl-js-button mdl-button--icon mdl-button--colored">           <i class="material-icons">remove</font></i>         </button>       </td>     </tr>   </tbody> </table> </div> <div class="mdl-grid center-items"> <div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">   <!-- <input class="mdl-textfield__input" type="number" id="total-cost" readonly value="0">   <label class="mdl-textfield__label" for="cost">Total Item Cost</label> -->   <h4>Total Cost: {{ total }}</h4> </div> </div> 

Faktanya, tidak begitu banyak perubahan yang dilakukan pada markup. Di sini isi dari template-mikro yang digunakan sebelumnya disalin dan arahan dan mekanisme interpolasi dari teks Vue digunakan. Arahan v-for digunakan untuk membuat daftar item yang datanya diambil dari properti items . Data ditampilkan dalam kolom menggunakan kapabilitas konstruksi Vue {{ item.name }} . Mekanisme ini mirip dengan placeholder yang digunakan dalam mikro-templat. Jumlah total juga ditampilkan pada halaman menggunakan teknologi interpolasi teks.

Sekarang kita akan menyelesaikan kode JavaScript dalam file index-vue.js dan mendapatkan yang berikut.

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "",   items: [] }, computed: {   //     total: function() {     // `this`    vm     return this.items.reduce(       (accumulator, currentValue) => accumulator + currentValue.subTotal,       0     );   } }, methods: {   ..... } }); hoodie.store.withIdPrefix("item").on("add", item => vm.items.push(item)); 

Varian dari mekanisme yang dijelaskan, disiapkan oleh Vue, ternyata jauh lebih pendek dan lebih sederhana daripada yang dibuat menggunakan JS biasa. Dalam kode ini, properti data items ditambahkan, yang digunakan dalam v-for directive di atas. Ketika sebuah item ditambahkan, Hoodie memanggil fungsi yang melakukan operasi vm.items.push(item) untuk memperbarui status aplikasi, dan ini, berkat sistem reaktivitas Vue, secara otomatis memperbarui antarmuka pengguna. Untuk menghitung jumlah total, tidak perlu merujuk ke elemen DOM. Di sini kami menggunakan properti yang dihitung yang memproses dataset items menggunakan fungsi .reduce() . Sekarang, berkat sistem reaktivitas Vue, antarmuka pengguna diperbarui ketika nilai-nilai ini berubah. Hal yang baik adalah bahwa semua ini memungkinkan programmer untuk tidak khawatir bekerja dengan elemen DOM dalam kode. Akibatnya, dengan bantuan kode yang lebih kecil, kami memecahkan masalah yang sama, yang membutuhkan lebih banyak kode dalam kasus JS reguler (mungkin, jika bukan JS biasa dalam situasi ini perpustakaan jQuery akan digunakan, kucing juga akan keluar dengan ukuran yang lebih besar, dari yang Anda dapatkan saat menggunakan Vue).

Menyimpan Item sebagai Daftar


▍JavaScript


Setelah menambahkan elemen, Anda harus menyimpannya untuk digunakan nanti, sehingga nanti Anda bisa menambahkan daftar elemen lainnya ke sistem. Aplikasi ini memiliki tombol Save List , yang bertanggung jawab untuk mengumpulkan data, untuk menyimpannya sebagai sekelompok elemen menggunakan alat Hoodie, dan bagi pengguna untuk dapat menambahkan set elemen baru ke sistem.

Saat menggunakan JavaScript biasa, fungsi terkait terikat dengan onClick tombol onClick . Ini markupnya.

 //index.html <div class="mdl-grid center-items"> <button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored" onclick="pageEvents.saveList()">   Save List </button> </div> 

Berikut adalah kode fungsinya.

 //index.js function saveList() { let cost = 0; hoodie.store   .withIdPrefix("item")   .findAll()   .then(function(items) {     for (var item of items) {       cost += item.subTotal;     }     //      hoodie.store.withIdPrefix("list").add({       cost: cost,       items: items     });     //      hoodie.store       .withIdPrefix("item")       .remove(items)       .then(function() {         //          document.getElementById("item-table").tBodies[0].innerHTML = "";         //          var snackbarContainer = document.querySelector("#toast");         snackbarContainer.MaterialSnackbar.showSnackbar({           message: "List saved succesfully"         });       })       .catch(function(error) {         //             var snackbarContainer = document.querySelector("#toast");         snackbarContainer.MaterialSnackbar.showSnackbar({           message: error.message         });       });   }); } window.pageEvents = { deleteItem: deleteItem, saveList: saveList .... }; 

UeVue


Beralih ke Vue tidak akan membutuhkan banyak perubahan. Kita masih perlu untuk mengikat pawang ke acara yang dipicu ketika tombol diklik, di samping itu, kita perlu menambahkan metode, yang merupakan pawang acara ini, ke properti methods objek Vue ketika diinisialisasi.

Beginilah tampilan markup sekarang.

 <div class="mdl-grid center-items"> <button @click="saveList" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored">   Save List </button> </div> 

@click="saveList" adalah singkatan untuk v-on:click="saveList" . Mekanisme ini digunakan untuk mendengarkan acara DOM. Fungsi saveList sama yang digunakan dalam versi aplikasi yang ditulis dalam JS murni ditambahkan ke properti methods objek Vue.

Bilah navigasi


▍JavaScript


Sekarang elemen dapat disimpan sebagai daftar, kami ingin dapat melihat daftar yang disimpan sebelumnya dengan data tentang nilai total barang yang terkandung di dalamnya. Informasi ini akan ditampilkan di halaman lain, akan terlihat seperti yang ditunjukkan di bawah ini.


Data pada daftar produk yang dibuat sebelumnya

Markup untuk halaman ini ada di file public/history.html , kode JS yang sesuai ada di file public/js/src/history.js . Halaman dan index.html memiliki kesamaan. Ini adalah bilah navigasi yang terletak di bagian atas jendela. Panel ini berisi tautan ke berbagai halaman, tautan Login dan Register yang memohon formulir dialog untuk memasuki sistem dan mendaftar di dalamnya. Ada juga tombol Signout untuk keluar.
Dalam versi aplikasi yang dibuat menggunakan JS biasa, Anda harus menduplikasi markup yang sama di kedua halaman. Ini adalah tampilan kode HTML pada bilah navigasi.

 <header class="mdl-layout__header">   <div class="mdl-layout__header-row">   <!-- Title -->   <span class="mdl-layout-title">Shopping List</span>   <!-- Add spacer, to align navigation to the right -->   <div class="mdl-layout-spacer"></div>   <!-- Navigation. We hide it in small screens. -->   <nav class="mdl-navigation mdl-layout--large-screen-only">       <a class="mdl-navigation__link" href="index.html">Home</a>       <a class="mdl-navigation__link" href="history.html">History</a>       <a onclick="pageEvents.showLogin()" style="cursor: pointer" class="mdl-navigation__link login">Login</a>       <a onclick="pageEvents.showRegister()" style="cursor: pointer" class="mdl-navigation__link register">Register</a>       <a onclick="pageEvents.signout()" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>   </nav>   </div> </header> <div class="mdl-layout__drawer">   <span class="mdl-layout-title">Shopping List</span>   <nav class="mdl-navigation">   <a class="mdl-navigation__link" href="index.html">Home</a>   <a class="mdl-navigation__link" href="history.html">History</a>   <a onclick="pageEvents.showLogin()" style="cursor: pointer" class="mdl-navigation__link login">Login</a>   <a onclick="pageEvents.showRegister()" style="cursor: pointer" class="mdl-navigation__link register">Register</a>   <a onclick="pageEvents.signout()" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>   </nav> </div> 

Setelah menganalisis kode ini, Anda akan melihat bahwa ketika Anda mengklik tautan Login , Register , dan Logout , fungsinya yang sesuai akan dipanggil. Penangan acara untuk elemen yang dijelaskan dalam markup ini didefinisikan dalam file index.js .

 import * as shared from "shared.js"; .... shared.updateDOMLoginStatus(); window.pageEvents = { showLogin: shared.showLoginDialog, showRegister: shared.showRegisterDialog, signout: shared.signOut }; 

Fungsi yang bertanggung jawab untuk bekerja dengan bilah navigasi dinyatakan dalam file shared.js .

 //   let loginDialog = document.querySelector("#login-dialog"); dialogPolyfill.registerDialog(loginDialog); let registerDialog = document.querySelector("#register-dialog"); dialogPolyfill.registerDialog(registerDialog); let showLoginDialog = function() { loginDialog.showModal(); }; let showRegisterDialog = function() { registerDialog.showModal(); }; let showAnonymous = function() { document.getElementsByClassName("login")[0].style.display = "inline"; document.getElementsByClassName("login")[1].style.display = "inline"; document.getElementsByClassName("register")[0].style.display = "inline"; document.getElementsByClassName("register")[1].style.display = "inline"; document.getElementsByClassName("logout")[0].style.display = "none"; document.getElementsByClassName("logout")[1].style.display = "none"; }; let showLoggedIn = function() { document.getElementsByClassName("login")[0].style.display = "none"; document.getElementsByClassName("login")[1].style.display = "none"; document.getElementsByClassName("register")[0].style.display = "none"; document.getElementsByClassName("register")[1].style.display = "none"; document.getElementsByClassName("logout")[0].style.display = "inline"; document.getElementsByClassName("logout")[1].style.display = "inline"; }; let updateDOMLoginStatus = () => { hoodie.account.get("session").then(function(session) {   if (!session) {     //          showAnonymous();   } else if (session.invalid) {     //   ,          showAnonymous();   } else {     //         showLoggedIn();   } }); }; let signOut = function() { hoodie.account   .signOut()   .then(function() {     showAnonymous();     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "You logged out"     });     location.href = location.origin;   })   .catch(function() {     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "Could not logout"     });   }); }; export { signOut, showRegisterDialog, showLoginDialog, updateDOMLoginStatus }; 

Kode ini mengekspor fungsi yang digunakan di index.js . Fungsi showLoginDialog() dan showRegisterDialog() masing-masing menampilkan kotak dialog modal, untuk masuk dan mendaftar. Fungsi signout() memungkinkan pengguna untuk keluar dan memanggil fungsi showAnonymous() , yang menyembunyikan tautan Logout dan hanya menampilkan tautan Register dan Login . Fungsi updateDOMLoginStatus() memeriksa apakah pengguna diautentikasi dan menampilkan tautan yang sesuai. Fungsi ini dipanggil saat halaman dimuat.

Untuk memiliki bilah navigasi yang sama pada dua halaman yang berbeda, kami harus menduplikasi markup, mengakses elemen DOM dan menggunakan fitur CSS untuk menunjukkan dan menyembunyikan tautan pada panel. Mari kita lihat bilah navigasi alternatif yang dibuat oleh Vue.

UeVue


Banyak aplikasi web memiliki snippet yang sama dengan yang digunakan pada halaman berbeda. Misalnya, bilah navigasi. Entitas tersebut harus ditempatkan dalam wadah atau disajikan sebagai komponen yang cocok untuk digunakan kembali. Vue menyediakan pengembang dengan mesin komponen yang dapat digunakan untuk memecahkan masalah seperti yang sedang kami pertimbangkan. Komponen Vue mandiri dan dapat digunakan kembali.

Mentransfer proyek untuk menggunakan komponen Vue, kami membuat file baru, shared-vue.js . Vue, . .

 Vue.component("navigation", { props: ["isLoggedIn", "toggleLoggedIn"], template: `<div>             <header class="mdl-layout__header">       <div class="mdl-layout__header-row">         <!-- Title -->         <span class="mdl-layout-title">Shopping List</span>         <!-- Add spacer, to align navigation to the right -->         <div class="mdl-layout-spacer"></div>         <!-- Navigation. We hide it in small screens. -->         <nav class="mdl-navigation mdl-layout--large-screen-only">           <a class="mdl-navigation__link" href="index.html">Home</a>           <a class="mdl-navigation__link" href="history.html">History</a>           <a v-show="!isLoggedIn" @click="showLogin" style="cursor: pointer" class="mdl-navigation__link login">Login</a>           <a v-show="!isLoggedIn" @click="showRegister" style="cursor: pointer" class="mdl-navigation__link register">Register</a>           <a v-show="isLoggedIn" @click="logout" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>         </nav>       </div>     </header>     <div class="mdl-layout__drawer">       <span class="mdl-layout-title">Shopping List</span>       <nav class="mdl-navigation">         <a class="mdl-navigation__link" href="index.html">Home</a>         <a class="mdl-navigation__link" href="history.html">History</a>         <a v-show="!isLoggedIn" @click="showLogin" style="cursor: pointer" class="mdl-navigation__link login">Login</a>         <a v-show="!isLoggedIn" @click="showRegister" style="cursor: pointer" class="mdl-navigation__link register">Register</a>         <a v-show="isLoggedIn" @click="logout" style="cursor: pointer" class="mdl-navigation__link logout">Logout</a>       </nav>     </div>           </div>`, methods: {   showLogin: function() {     const loginDialog = document.querySelector("#login-dialog");     dialogPolyfill.registerDialog(loginDialog);     loginDialog.showModal();   },   showRegister: function() {     const registerDialog = document.querySelector("#register-dialog");     dialogPolyfill.registerDialog(registerDialog);     registerDialog.showModal();   },   logout: function() {     hoodie.account       .signOut()       .then(() => {         this.toggleLoggedIn();       })       .catch(error => {         alert("Could not logout");       });   } } }); 

Vue, navigation , , , Vue. — props . props — . , , , props . isLoggedIn , .

, template , , . , , JS, , Vue — v-show @click . v-show . Logout , isLoggedIn true , falseLogin Register . , Vue v-if v-else . . @clickv-on:click . showLogin , showRegister logout .

methods . logout , , this.toggleLoggedIn() , props . , props , , isLoggedin , . , Vue DOM.
index.html . , 59-84. .

 <navigation v-bind:is-logged-in="isLoggedIn" v-bind:toggle-logged-in="toggleLoggedIn"></navigation> 

JS- isLoggedIn toggleLoggedIn , , props , , kebab-case. v-bind . isLoggedIn . : v-bind , .

 <navigation :is-logged-in="isLoggedIn" :toggle-logged-in="toggleLoggedIn"></navigation> 

isLoggedIn , toggleLoggedIn — , Vue index-vue.js . .

 const vm = new Vue({ el: "#app", data: {   name: "",   cost: "",   quantity: "",   items: [],   isLoggedIn: false }, computed: {   .....//   }, methods: {   toggleLoggedIn: function() {     this.isLoggedIn = !this.isLoggedIn;   },   ......//   } }); .....//   hoodie.account.get("session").then(function(session) { if (!session) {   //       vm.isLoggedIn = false; } else if (session.invalid) {   vm.isLoggedIn = false; } else {   //       vm.isLoggedIn = true; } }); 

Vue , , , , Vue. , Vue DOM , .


▍JavaScript


Login Register , . , , , . 171-244 index.html 100-158 history.html .

 <dialog id="login-dialog" class="mdl-dialog"> <h4 class="mdl-dialog__title">Login</h4> <div class="mdl-dialog__content">   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="text" id="login-username">       <label class="mdl-textfield__label" for="login-username">Username</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="password" id="login-password">       <label class="mdl-textfield__label" for="login-password">Password</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <span id="login-error"></span>     </div>   </div> </div> <div class="mdl-dialog__actions">   <button onclick="pageEvents.closeLogin()" type="button" class="mdl-button close">Cancel</button>   <button onclick="pageEvents.login()" type="button" class="mdl-button">Login</button> </div> </dialog> <dialog id="register-dialog" class="mdl-dialog"> <h4 class="mdl-dialog__title">Login</h4> <div class="mdl-dialog__content">   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="text" id="register-username">       <label class="mdl-textfield__label" for="register-username">Username</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <input class="mdl-textfield__input" type="password" id="register-password">       <label class="mdl-textfield__label" for="register-password">Password</label>     </div>   </div>   <div class="mdl-grid center-items">     <!-- Simple Textfield -->     <div class="mdl-textfield mdl-js-textfield">       <span id="register-error"></span>     </div>   </div> </div> <div class="mdl-dialog__actions">   <button onclick="pageEvents.closeRegister()" type="button" class="mdl-button close">Cancel</button>   <button onclick="pageEvents.register()" type="button" class="mdl-button">Register</button> </div> </dialog> 

, , shared.js index.js .

 //shared.js //   let loginDialog = document.querySelector("#login-dialog"); dialogPolyfill.registerDialog(loginDialog); let registerDialog = document.querySelector("#register-dialog"); dialogPolyfill.registerDialog(registerDialog); let closeLoginDialog = function() { loginDialog.close(); }; let closeRegisterDialog = function() { registerDialog.close(); }; let showAnonymous = function() { ... }; let showLoggedIn = function() { .... }; let signOut = function() { .... }; let updateDOMLoginStatus = () => { .... }; let login = function() { let username = document.querySelector("#login-username").value; let password = document.querySelector("#login-password").value; hoodie.account   .signIn({     username: username,     password: password   })   .then(function() {     showLoggedIn();     closeLoginDialog();     let snackbarContainer = document.querySelector("#toast");     snackbarContainer.MaterialSnackbar.showSnackbar({       message: "You logged in"     });   })   .catch(function(error) {     console.log(error);     document.querySelector("#login-error").innerHTML = error.message;   }); }; let register = function() { let username = document.querySelector("#register-username").value; let password = document.querySelector("#register-password").value; let options = { username: username, password: password }; hoodie.account   .signUp(options)   .then(function(account) {     return hoodie.account.signIn(options);   })   .then(account => {     showLoggedIn();     closeRegisterDialog();     return account;   })   .catch(function(error) {     console.log(error);     document.querySelector("#register-error").innerHTML = error.message;   }); }; export { register, login, closeRegisterDialog, closeLoginDialog, ... }; 

index.js.

 //index.js window.pageEvents = { closeLogin: shared.closeLoginDialog, showLogin: shared.showLoginDialog, closeRegister: shared.closeRegisterDialog, showRegister: shared.showRegisterDialog, login: shared.login, register: shared.register, signout: shared.signOut }; 

▍Vue


Vue . , .

 Vue.component("login-dialog", { data: function() {   return {     username: "",     password: ""   }; }, props: ["toggleLoggedIn"], template: `<dialog id="login-dialog" class="mdl-dialog">     <h4 class="mdl-dialog__title">Login</h4>     <div class="mdl-dialog__content">       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <input v-model="username" class="mdl-textfield__input" type="text" id="login-username">           <label class="mdl-textfield__label" for="login-username">Username</label>         </div>       </div>       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <input v-model="password" class="mdl-textfield__input" type="password" id="login-password">           <label class="mdl-textfield__label" for="login-password">Password</label>         </div>       </div>       <div class="mdl-grid center-items">         <!-- Simple Textfield -->         <div class="mdl-textfield mdl-js-textfield">           <span id="login-error"></span>         </div>       </div>     </div>     <div class="mdl-dialog__actions">       <button @click="closeLogin" type="button" class="mdl-button close">Cancel</button>       <button @click="login" type="button" class="mdl-button">Login</button>     </div>   </dialog>`, methods: {   closeLogin: function() {     const loginDialog = document.querySelector("#login-dialog");     dialogPolyfill.registerDialog(loginDialog);     loginDialog.close();   },   login: function(event) {     hoodie.account       .signIn({         username: this.username,         password: this.password       })       .then(() => {         this.toggleLoggedIn();         this.closeLogin();       })       .catch(error => {         console.log(error);         document.querySelector("#login-error").innerHTML = "Error loggin in";       });   } } }); 

data , props , template methods , Vue.component() .

, , Vue .

 //index.html <login-dialog v-bind:toggle-logged-in="toggleLoggedIn"></login-dialog> 

.

, , Vue. , , . , - Push API .

Ringkasan


-, JS, Vue.js. HTML, CSS JavaScript (jQuery), Vue . ES6 , .

Vue , , . , , , Vue. , , Vue .

, JS. — , Vue.

Pembaca yang budiman! - ?

Source: https://habr.com/ru/post/id413311/


All Articles