Իմ նախորդ գրառման մեջ ես հիմք դրեցի կառուցելու համար. հիմա ժամանակն է սկսել «իրականում»:
Ես շատ Vue.js եմ լսել: Բացի այդ, մի ընկեր, ով ծրագրավորողից վերածվեց մենեջերի, ինձ լավ բաներ ասաց Vue-ի մասին, որն էլ ավելի գրգռեց իմ հետաքրքրությունը: Ես որոշեցի նայել դրան. դա կլինի առաջին «թեթև» JavaScript շրջանակը, որը ես կուսումնասիրեմ՝ նորեկի տեսանկյունից, որը ես եմ:
Ես բացատրեցի WebJars-ը և Thymeleaf-ը վերջին գրառման մեջ: Ահա կարգավորումը, սերվերի և հաճախորդի կողմից:
Ահա թե ինչպես եմ ես ինտեգրում երկուսն էլ POM-ում.
<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>
Ես օգտագործում եմ Kotlin Router-ը և Bean DSL-ները Spring Boot-ի կողմում.
fun vue(todos: List<Todo>) = router { //1 GET("/vue") { ok().render("vue", mapOf("title" to "Vue.js", "todos" to todos)) //2-3 } }
Todo
օբյեկտների ստատիկ ցուցակը
Եթե դուք սովոր եք API-ների մշակմանը, ապա ծանոթ եք body()
ֆունկցիային; այն ուղղակիորեն վերադարձնում է ծանրաբեռնվածությունը, հավանաբար JSON ձևաչափով: render()
փոխանցում է հոսքը դեպի դիտման տեխնոլոգիա, այս դեպքում՝ Thymeleaf: Այն ընդունում է երկու պարամետր.
/templates
է, իսկ նախածանցը՝ .html
; այս դեպքում Thymeleaf-ն ակնկալում է դիտում /templates/vue.html
կայքումԱհա կոդը HTML կողմում.
<script th:src="@{/webjars/axios/dist/axios.js}" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> <!--1--> <script th:src="@{/webjars/vue/dist/vue.global.js}" src="https://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>
Ինչպես բացատրվեց անցյալ շաբաթվա հոդվածում, Thymeleaf-ի առավելություններից մեկն այն է, որ այն թույլ է տալիս ինչպես ստատիկ ֆայլերի մատուցում, այնպես էլ սերվերի կողմից: Որպեսզի կախարդանքն աշխատի, ես նշում եմ հաճախորդի կողմի ուղին, այսինքն ՝ src
, և սերվերի կողմից, այսինքն ՝ th:src
:
Հիմա եկեք սուզվենք Vue կոդը:
Մենք ցանկանում ենք իրականացնել մի քանի առանձնահատկություններ.
Todo
տարրերըTodo
ավարտված վանդակի վրա սեղմելիս այն պետք է սահմանի/չսահմանի completed
հատկանիշըTodo
Todo
Todo
ցանկին ավելացնի հետևյալ արժեքներով.id
. սերվերի կողմից հաշվարկված ID-ն որպես բոլոր մյուս ID-ների առավելագույն գումարած 1label
. Label դաշտի արժեքը label
համարcompleted
. սահմանվել է false
Առաջին քայլը շրջանակը բեռնաթափելն է: Մենք արդեն ստեղծել ենք վերևում մեր հատուկ vue.js
ֆայլի հղումը:
document.addEventListener('DOMContentLoaded', () => { //1 // The next JavaScript code snippets will be inside the block }
Հաջորդ քայլը Vue-ին թույլ տալն է կառավարել էջի մի մասը: HTML-ի կողմից մենք պետք է որոշենք, թե վերին մակարդակի որ մասը կառավարում է Vue-ը: Մենք կարող ենք ընտրել կամայական <div>
և անհրաժեշտության դեպքում փոխել այն ավելի ուշ:
<div id="app"> </div>
JavaScript-ի կողմից մենք ստեղծում ենք հավելված ՝ անցնելով նախորդ <div>
HTML-ի CSS ընտրիչը:
Vue.createApp({}).mount('#app');
Այս պահին մենք գործարկում ենք Vue-ն, երբ էջը բեռնվում է, բայց տեսանելի ոչինչ տեղի չի ունենում:
Հաջորդ քայլը Vue կաղապարի ստեղծումն է: Vue ձևանմուշը սովորական HTML <template>
կաղապար> է, որը կառավարվում է Vue-ի կողմից: Դուք կարող եք սահմանել Vue-ը Javascript-ով, բայց ես նախընտրում եմ դա անել HTML էջում:
Սկսենք արմատային կաղապարից, որը կարող է ցուցադրել վերնագիրը:
<template id="todos-app"> <!--1--> <h1>{{ title }}</h1> <!--2--> </template>
title
հատկությունը; մնում է կարգավորել
JavaScript-ի կողմից մենք պետք է ստեղծենք կառավարման կոդը:
const TodosApp = { props: ['title'], //1 template: document.getElementById('todos-app').innerHTML, }
title
հատկությունը, որն օգտագործվում է HTML ձևանմուշում
Ի վերջո, մենք պետք է փոխանցենք այս օբյեկտը, երբ ստեղծենք հավելվածը.
Vue.createApp({ components: { TodosApp }, //1 render() { //2 return Vue.h(TodosApp, { //3 title: window.vueData.title, //4 }) } }).mount('#app');
render()
ֆունկցիանh()
հիպերսկրիպտի համար ստեղծում է վիրտուալ հանգույց օբյեկտից և նրա հատկություններիցtitle
հատկությունը սերվերի կողմից ստեղծված արժեքով
Այս պահին Vue-ն ցուցադրում է վերնագիրը:
Այս պահին մենք կարող ենք իրականացնել գործողությունը, երբ օգտագործողը սեղմում է վանդակը. այն պետք է թարմացվի սերվերի կողմից:
Նախ, ես ավելացրի նոր տեղադրված Vue ձևանմուշ աղյուսակի համար, որը ցուցադրում է Todo
ը: Գրառումը երկարացնելուց խուսափելու համար կխուսափեմ մանրամասն նկարագրելուց։ Եթե դուք հետաքրքրված եք, դիտեք սկզբնաղբյուրը :
Ահա մեկնարկային տողի կաղապարի կոդը, համապատասխանաբար JavaScript-ը և HTML-ը.
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
ID-նTodo
պիտակըcompleted
հատկանիշը true
է
Vue-ն թույլ է տալիս իրադարձությունների մշակումը @
շարահյուսության միջոցով:
<input type="checkbox" :checked="todo.completed" @click="check" />
Vue-ն կանչում է կաղապարի check()
ֆունկցիան, երբ օգտատերը սեղմում է գծի վրա: Մենք սահմանում ենք այս ֆունկցիան setup()
պարամետրով.
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
զանգվածը, որպեսզի հետագայում կարողանանք մուտք գործել այնevent
, որն առաջացրել է զանգըՆախորդ բաժնում ես երկու սխալ թույլ տվեցի.
Մենք դա կանենք՝ կիրառելով հաջորդ գործառույթը, որն է՝ ավարտված առաջադրանքների մաքրում։
Մենք այժմ գիտենք, թե ինչպես վարվել իրադարձությունների հետ Vue-ի միջոցով.
<button class="btn btn-warning" @click="cleanup">Cleanup</button>
TodosApp
օբյեկտի վրա մենք ավելացնում ենք նույնանուն ֆունկցիա.
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
այն է, որտեղ մենք պահում ենք մոդելը
Vue-ի իմաստաբանության մեջ Vue մոդելը տվյալների շուրջ փաթաթված է, որը մենք ցանկանում ենք ռեակտիվ լինել: Ռեակտիվ նշանակում է երկկողմանի կապ՝ տեսարանի և մոդելի միջև: Մենք կարող ենք ռեակտիվ դարձնել գոյություն ունեցող արժեքը՝ այն փոխանցելով ref()
մեթոդին՝
Composition API-ում ռեակտիվ վիճակ հայտարարելու առաջարկվող եղանակը
ref()
ֆունկցիայի օգտագործումն է:
ref()
վերցնում է արգումենտը և վերադարձնում այն ref օբյեկտի մեջ փաթաթված .value հատկությամբ:
Բաղադրիչի ձևանմուշում refs մուտք գործելու համար հայտարարեք և վերադարձրեք դրանք բաղադրիչի
setup()
ֆունկցիայից:
Եկեք դա անենք.
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
սահմանման ձևը: Դա անհրաժեշտ չէ, քանի որ չկա երկկողմանի կապ. մենք չենք թարմացնում վերնագիրը հաճախորդի կողմից, բայց ես նախընտրում եմ պահպանել կառավարումը բոլոր արժեքների միջև:state
Այս պահին մենք ունենք հաճախորդի կողմից ռեակտիվ մոդել:
HTML-ի կողմից մենք օգտագործում ենք համապատասխան Vue ատրիբուտները.
<tbody> <tr is="vue:todo-line" v-for="todo in todos" :key="todo.id" :todo="todo"></tr> <!--1-2--> </tbody>
Todo
օբյեկտների ցանկըis
հատկանիշը շատ կարևոր է զննարկիչի կողմից HTML-ը վերլուծելու համար: Լրացուցիչ մանրամասների համար տես Vue-ի փաստաթղթերըԵս վերը նկարագրեցի համապատասխան ձևանմուշը:
Այժմ մենք կարող ենք ներդնել նոր հնարավորություն՝ ավելացնել նոր Todo
հաճախորդից: Ավելացնել կոճակը սեղմելիս մենք կարդում ենք Label դաշտի արժեքը, տվյալները ուղարկում ենք API և թարմացնում ենք մոդելը պատասխանով:
Ահա թարմացված կոդը.
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()
ֆունկցիան ճիշտ էTodo
ի ցանկին
HTML-ի կողմից մենք կոճակ ենք ավելացնում և կապում ենք create()
ֆունկցիային: Նմանապես, մենք ավելացնում ենք Label դաշտը և կապում այն մոդելի հետ:
<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()
ֆունկցիան HTML կոճակին։ Այն կանչում է այն ասինխրոն կերպով և թարմացնում է ռեակտիվ Todo
ցուցակը զանգով վերադարձված նոր նյութով: Մենք նույնն ենք անում Մաքրում կոճակի համար՝ ստուգված Todo
օբյեկտները հեռացնելու համար:
Նկատի ունեցեք, որ ես միտումնավոր չեմ կիրառել սխալների հետ կապված որևէ կոդ, որպեսզի խուսափեմ կոդը ավելի բարդ դարձնելուց, քան անհրաժեշտ է: Ես կդադարեմ այստեղ, քանի որ մենք բավականաչափ պատկերացումներ ձեռք բերեցինք առաջին փորձի համար:
Այս գրառման մեջ ես իմ առաջին քայլերն արեցի Vue-ի միջոցով SSR հավելվածն ավելացնելու համար: Դա բավականին պարզ էր: Ամենամեծ խնդիրը, որին ես հանդիպեցի, դա այն is
, որ Vue-ն փոխարիներ տողի ձևանմուշը.
Այնուամենայնիվ, ես ստիպված էի գրել JavaScript-ի բավականին տողեր, թեև ես օգտագործում էի Axios-ը HTTP զանգերի հարցում ինձ օգնելու համար և չէի կառավարում սխալները:
Հաջորդ գրառման մեջ ես նույն հնարավորությունները կներդնեմ Alpine.js-ի հետ:
Այս գրառման ամբողջական սկզբնական կոդը կարելի է գտնել GitHub-ում.
Անցեք հետագա.