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 siapJika 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"> <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 sebelumnyaMarkup 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"> <span class="mdl-layout-title">Shopping List</span> <div class="mdl-layout-spacer"></div> <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"> <span class="mdl-layout-title">Shopping List</span> <div class="mdl-layout-spacer"></div> <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
,
false
—
Login
Register
. , Vue
v-if
v-else
.
.
@click
—
v-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"> <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"> <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"> <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"> <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"> <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"> <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"> <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"> <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"> <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! - ?
