Önceki yazımda üzerine inşa edeceğimiz temelleri atmıştım; şimdi "gerçekten" başlamanın zamanı.
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <!--1--> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> <!--2--> </dependency> <dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator</artifactId> <!--3--> <version>0.52</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>vue</artifactId> <!--4--> <version>3.4.34</version> </dependency> </dependencies>
fun vue(todos: List<Todo>) = router { //1 GET("/vue") { ok().render("vue", mapOf("title" to "Vue.js", "todos" to todos)) //2-3 } }
Todo
nesneleri listesi geçirin
API geliştirmeye alışkınsanız, body()
fonksiyonuna aşinasınızdır; bu fonksiyon, yükü doğrudan, muhtemelen JSON formatında döndürür. render()
akışı görünüm teknolojisine, bu durumda Thymeleaf'e iletir. İki parametre kabul eder:
/templates
ve önek .html
; bu durumda, Thymeleaf /templates/vue.html
bir görünüm bekler
<script th:src="@{/webjars/axios/dist/axios.js}" src="//cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> <!--1--> <script th:src="@{/webjars/vue/dist/vue.global.js}" src="//cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script> <!--2--> <script th:src="@{/vue.js}" src="../static/vue.js"></script> <!--3--> <script th:inline="javascript"> /*<![CDATA[*/ window.vueData = { <!--4--> title: /*[[${ title }]]*/ 'A Title', todos: /*[[${ todos }]]*/ [{ 'id': 1, 'label': 'Take out the trash', 'completed': false }] }; /*]]>*/ </script>
Geçtiğimiz haftaki makalede açıklandığı gibi, Thymeleaf'in avantajlarından biri hem statik dosya işleme hem de sunucu tarafı işleme izin vermesidir. Sihrin işe yaraması için, bir istemci tarafı yolu, yani src
ve bir sunucu tarafı yolu, yani th:src
belirtiyorum.
Todo
öğelerini görüntülemelidirTodo
tamamlandı onay kutusuna tıklandığında, completed
niteliği ayarlanmalı/ayarlanmamalıdırTodo
silinirTodo
listesine aşağıdaki değerlere sahip bir Todo
eklenmelidir:id
: Sunucu tarafında hesaplanan, diğer tüm ID'lerin maksimum değeri artı 1label
: label
için Etiket alanının değericompleted
: false
olarak ayarlandı İlk adım framework'ü başlatmaktır. Yukarıda özel vue.js
dosyamız için referansı zaten ayarladık.
document.addEventListener('DOMContentLoaded', () => { //1 // The next JavaScript code snippets will be inside the block }
Bir sonraki adım Vue'nun sayfanın bir kısmını yönetmesine izin vermektir. HTML tarafında, Vue'nun hangi üst düzey kısmı yöneteceğine karar vermeliyiz. İsteğe bağlı bir <div>
seçebilir ve gerekirse daha sonra değiştirebiliriz.
<div id="app"> </div>
JavaScript tarafında, önceki HTML <div>
seçicisini CSS seçicisine geçirerek bir uygulama oluşturuyoruz.
Vue.createApp({}).mount('#app');
Bir sonraki adım bir Vue şablonu oluşturmaktır. Bir Vue şablonu, Vue tarafından yönetilen normal bir HTML <template>
udur. Vue'yi Javascript'te tanımlayabilirsiniz, ancak bunu HTML sayfasında yapmayı tercih ediyorum.
<template id="todos-app"> <!--1--> <h1>{{ title }}</h1> <!--2--> </template>
title
özelliğini kullanın; kurulumu yapılması gerekiyor
const TodosApp = { props: ['title'], //1 template: document.getElementById('todos-app').innerHTML, }
title
özelliğini bildirin
Vue.createApp({ components: { TodosApp }, //1 render() { //2 return Vue.h(TodosApp, { //3 title: window.vueData.title, //4 }) } }).mount('#app');
render()
fonksiyonunu bekliyorh()
nesneden ve onun özelliklerinden sanal bir düğüm oluştururtitle
özelliğini sunucu tarafında oluşturulan değerle başlatın
Öncelikle, Todo
görüntüleyen tablo için yeni bir iç içe geçmiş Vue şablonu ekledim. Yazıyı uzatmamak için, ayrıntılı olarak açıklamaktan kaçınacağım. İlginizi çekerse, bir göz atın.
const TodoLine = { props: ['todo'], template: document.getElementById('todo-line').innerHTML }
<template id="todo-line"> <tr> <td>{{ todo.id }}</td> <!--1--> <td>{{ todo.label }}</td> <!--2--> <td> <label> <input type="checkbox" :checked="todo.completed" /> </label> </td> </tr> </template>
Todo
kimliğini gösterTodo
etiketini görüntülecompleted
niteliği true
kutuyu işaretleyin
Vue, @
sözdizimi aracılığıyla olay işleme olanağı sağlar.
<input type="checkbox" :checked="todo.completed" @click="check" />
Kullanıcı satıra tıkladığında Vue şablonun check()
fonksiyonunu çağırır. Bu fonksiyonu bir setup()
parametresinde tanımlarız:
const TodoLine = { props: ['todo'], template: document.getElementById('todo-line').innerHTML, setup(props) { //1 const check = function (event) { //2 const { todo } = props axios.patch( //3 `/api/todo/${todo.id}`, //4 { checked: event.target.checked } //5 ) } return { check } //6 } }
props
dizisini kabul edin, böylece daha sonra erişebilirizevent
geçirir
<button class="btn btn-warning" @click="cleanup">Cleanup</button>
TodosApp
nesnesine aynı isimli bir fonksiyon ekliyoruz:
const TodosApp = { props: ['title', 'todos'], components: { TodoLine }, template: document.getElementById('todos-app').innerHTML, setup() { const cleanup = function() { //1 axios.delete('/api/todo:cleanup').then(response => { //1 state.value.todos = response.data //2-3 }) } return { cleanup } //1 } }
state
modeli depoladığımız yerdir
Vue'nun semantiğinde, Vue modeli reaktif olmasını istediğimiz verilerin etrafında bir sarmalayıcıdır. Reaktif, görünüm ve model arasında iki yönlü bağlama anlamına gelir. Mevcut bir değeri ref()
metoduna geçirerek reaktif hale getirebiliriz:
Composition API'sinde reaktif durumu bildirmenin önerilen yolu
ref()
fonksiyonunu kullanmaktır.
ref()
argümanı alır ve onu .value özelliğine sahip bir ref nesnesi içinde sarılı olarak döndürür.
Bir bileşenin şablonundaki referanslara erişmek için, bunları bileşenin
setup()
fonksiyonundan bildirin ve döndürün.--
const state = ref({ title: window.vueData.title, //1-2 todos: window.vueData.todos, //1 }) createApp({ components: { TodosApp }, setup() { return { ...state.value } //3-4 }, render() { return h(TodosApp, { todos: state.value.todos, //5 title: state.value.title, //5 }) } }).mount('#app');
title
ayarlama şeklimizi değiştiriyoruz. İki yönlü bir bağlama olmadığı için bu gerekli değil - başlığı istemci tarafında güncellemiyoruz, ancak tüm değerler arasında işlemeyi tutarlı tutmayı tercih ediyorumstate
yapılandırın
Bu noktada reaktif bir istemci tarafı modelimiz var.
<tbody> <tr is="vue:todo-line" v-for="todo in todos" :key="todo.id" :todo="todo"></tr> <!--1-2--> </tbody>
Todo
nesnelerinin listesi üzerinde döngüis
niteliği, tarayıcının HTML'yi ayrıştırma biçimiyle başa çıkmak için çok önemlidir. Daha fazla ayrıntı için bakın Artık yeni bir özellik uygulayabiliriz: istemciden yeni bir Todo
ekleyin. Ekle düğmesine tıkladığımızda, Etiket alan değerini okuruz, verileri API'ye göndeririz ve modeli yanıtla yenileriz.
const TodosApp = { props: ['title', 'todos'], components: { TodoLine }, template: document.getElementById('todos-app').innerHTML, setup() { const label = ref('') //1 const create = function() { //2 axios.post('/api/todo', { label: label.value }).then(response => { state.value.todos.push(response.data) //3 }).then(() => { label.value = '' //4 }) } const cleanup = function() { axios.delete('/api/todo:cleanup').then(response => { state.value.todos = response.data //5 }) } return { label, create, cleanup } } }
create()
fonksiyonu uygunTodo
listesine ekleyin
HTML tarafında bir buton ekliyoruz ve create()
fonksiyonuna bağlıyoruz. Aynı şekilde Label alanını da ekliyoruz ve onu modele bağlıyoruz.
<form> <div class="form-group row"> <label for="new-todo-label" class="col-auto col-form-label">New task</label> <div class="col-10"> <input type="text" id="new-todo-label" placeholder="Label" class="form-control" v-model="label" /> </div> <div class="col-auto"> <button type="button" class="btn btn-success" @click="create">Add</button> </div> </div> </form>
Vue, create()
fonksiyonunu HTML düğmesine bağlar. Bunu eş zamanlı olarak çağırır ve çağrı tarafından döndürülen yeni öğeyle reaktif Todo
listesini yeniler. Aynısını, işaretli Todo
nesnelerini kaldırmak için Cleanup düğmesi için de yaparız.
Bu gönderide, Vue ile bir SSR uygulamasını zenginleştirmeye yönelik ilk adımlarımı attım. Oldukça basitti. Karşılaştığım en büyük sorun, Vue'nin satır şablonunu değiştirmesiydi: Belgeleri kapsamlı bir şekilde okumadım ve is
niteliğini kaçırdım.
Daha ileri gidelim: