paint-brush
Зголемување на клиентот со Vue.jsод страна на@nfrankel
Нова историја

Зголемување на клиентот со Vue.js

од страна на Nicolas Fränkel17m2024/09/26
Read on Terminal Reader

Премногу долго; Да чита

Во овој пост, ги направив моите први чекори во зголемувањето на апликацијата SSR со Vue. Беше прилично директно. Најголемиот проблем на кој наидов беше Vue да го замени шаблонот за линија: не ја прочитав опширно документацијата и го пропуштив атрибутот е.
featured image - Зголемување на клиентот со Vue.js
Nicolas Fränkel HackerNoon profile picture
0-item


Во мојот претходен пост , поставив основа за да се изградам; сега е време да се започне „вистински“.


Слушнав многу Vue.js. Дополнително, еден пријател кој премина од програмер во менаџер ми кажа добри работи за Vue, што дополнително го разбуди мојот интерес. Решив да го погледнам: тоа ќе биде првата „лесна“ JavaScript рамка што ќе ја проучувам - од гледна точка на почетник, каков што сум јас.

Поставување на работата

Ги објаснив WebJars и Thymeleaf во последниот пост. Еве го поставувањето, серверот и клиентот.

Од страна на серверот

Еве како ги интегрирам и двете во ПОМ:


 <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>
  1. Самата пролетна чизма; Се одлучив за редовниот, нереактивен пристап
  2. Интеграција на Spring Boot Thymeleaf
  3. Локатор WebJars, за да се избегне специфицирање на верзијата Vue на страната на клиентот
  4. Vue, конечно!


Ги користам 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 } }
  1. Пренесете статична листа на Todo објекти
  2. Видете подолу
  3. Пренесете го моделот на Thymeleaf


Ако сте навикнати да развивате API, запознаени сте со функцијата body() ; директно го враќа товарот, веројатно во JSON формат. render() го пренесува протокот на технологијата за преглед, во овој случај, Thymeleaf. Прифаќа два параметри:


  1. Името на погледот. Стандардно, патеката е /templates , а префиксот е .html ; во овој случај, Thymeleaf очекува преглед на /templates/vue.html
  2. Модел на мапа на парови клуч-вредност

Од страната на клиентот

Еве го кодот од страната на 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>
  1. Axios помага да се прават барања за HTTP
  2. Самиот Vue
  3. Нашиот код од клиентската страна
  4. Поставете ги податоците


Како што беше објаснето во минатонеделната статија, една од придобивките на Thymeleaf е тоа што овозможува и статичко прикажување на датотеки и прикажување од страна на серверот. За да може магијата да функционира, јас одредувам патека од клиентот, т.е. src и патека од страна на серверот, т.е. th:src .


Кодот Vue

Сега, ајде да се нурнеме во кодот Vue.

Сакаме да имплементираме неколку карактеристики:


  1. По вчитувањето на страницата, страницата треба да ги прикаже сите ставки Todo
  2. При кликнување на полето за избор Todo завршено, треба да го постави/непостави completed атрибут
  3. Кога ќе кликнете на копчето Cleanup , се брише сите завршени Todo
  4. Кога ќе кликнете на копчето Додај , треба да додадете Todo на листата на Todo со следните вредности:
    • id : пресметан ID од страна на серверот како максимум од сите други ID плус 1
    • label : вредност на полето Label за label
    • completed : поставено на false

Нашите први чекори во Vue

Првиот чекор е да се подигне рамката. Веќе ја поставивме референцата за нашата приспособена датотека vue.js погоре.


 document.addEventListener('DOMContentLoaded', () => { //1 // The next JavaScript code snippets will be inside the block }
  1. Извршете го блокот кога DOM ќе заврши со вчитување


Следниот чекор е да му дозволите на Vue да управува со дел од страницата. На страната на HTML, ние мора да одлучиме со кој дел од највисоко ниво управува Vue. Можеме да избереме произволно <div> и да го промениме подоцна ако е потребно.


 <div id="app"> </div>


На страната JavaScript, создаваме апликација , поминувајќи го CSS избирачот на претходниот HTML <div> .


 Vue.createApp({}).mount('#app');


Во овој момент, го стартуваме Vue кога страницата се вчитува, но ништо видливо не се случува.


Следниот чекор е да креирате шаблон Vue. Шаблон Vue е обичен HTML <template> управуван од Vue. Можете да го дефинирате Vue во Javascript, но јас претпочитам да го направам тоа на страницата HTML.


Да почнеме со root шаблон што може да го прикаже насловот.


 <template id="todos-app"> <!--1--> <h1>{{ title }}</h1> <!--2--> </template>
  1. Поставете го ID за лесно врзување
  2. Користете го имотот title ; останува да се постави


На страната JavaScript, мора да го креираме управувачкиот код.


 const TodosApp = { props: ['title'], //1 template: document.getElementById('todos-app').innerHTML, }
  1. Декларирајте го својството title , она што се користи во шаблонот HTML


Конечно, мора да го предадеме овој објект кога ја креираме апликацијата:


 Vue.createApp({ components: { TodosApp }, //1 render() { //2 return Vue.h(TodosApp, { //3 title: window.vueData.title, //4 }) } }).mount('#app');
  1. Конфигурирајте ја компонентата
  2. Vue ја очекува функцијата render()
  3. h() за хиперскрипт создава виртуелен јазол од објектот и неговите својства
  4. Иницијализирајте го имотот 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>
  1. Прикажи Todo id
  2. Прикажете ја етикетата Todo
  3. Проверете го полето дали неговиот 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 } }
  1. Прифатете ја низата со props , за да можеме подоцна да пристапиме до неа
  2. Vue го поминува event што го активирал повикот
  3. Axios е JavaScript lib што ги поедноставува HTTP повиците
  4. Од страната на серверот мора да се обезбеди API; тоа е надвор од опсегот на овој пост, но слободно проверете го изворниот код.
  5. JSON носивост
  6. Ги враќаме сите дефинирани функции за да ги направиме достапни од HTML

Модел од страна на клиентот

Во претходниот дел, направив две грешки:


  • Не управував со ниту еден локален модел
  • Не го користев методот на повик на одговорот на HTTP


Тоа ќе го направиме со имплементирање на следната функција, а тоа е чистење на завршените задачи.


Сега знаеме како да се справиме со настаните преку 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 } }
  1. Како погоре
  2. Axios нуди автоматска JSON конверзија на повикот HTTP
  3. 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');
  1. Добијте го множеството податоци во HTML страницата, преку Thymeleaf, како што е објаснето погоре
  2. Го менуваме начинот на кој го поставуваме title . Не е неопходно бидејќи нема двонасочно врзување - не го ажурираме насловот од клиентската страна, но претпочитам да го одржувам управувањето кохерентно за сите вредности
  3. Вратете ги судиите, според очекувањата на Vue
  4. Види, мајко, јас го користам операторот за ширење JavaScript
  5. Конфигурирајте го објектот припишан од state


Во овој момент, имаме реактивен модел од страна на клиентот.


На страната на HTML, ги користиме соодветните атрибути на Vue:


 <tbody> <tr is="vue:todo-line" v-for="todo in todos" :key="todo.id" :todo="todo"></tr> <!--1-2--> </tbody>
  1. Превртете ја листата на Todo објекти
  2. Атрибутот 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 } } }
  1. Направете реактивна обвивка околу насловот чиј опсег е ограничен на функцијата
  2. Функцијата create() правилна
  3. Додадете го новиот JSON објект вратен од повикот на API на списокот Todo
  4. Ресетирајте ја вредноста на полето
  5. Заменете ја целата листа при бришење; механизмот е ист


На страната 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 со новата ставка вратена од повикот. Истото го правиме и за копчето Cleanup , за да ги отстраниме означените Todo објекти.


Забележете дека намерно не имплементирав код за справување со грешки за да избегнам да го направам кодот покомплексен отколку што е потребно. Ќе застанам овде бидејќи добивме доволно сознанија за прво искуство.

Заклучок

Во овој пост, ги направив моите први чекори во зголемувањето на апликацијата SSR со Vue. Беше прилично директно. Најголемиот проблем на кој наидов беше Vue да го замени шаблонот за линија: не ја прочитав опширно документацијата и го пропуштив атрибутот is .


Сепак, морав да напишам неколку линии JavaScript, иако користев Axios за да ми помогне со HTTP повиците и не управував со грешките.


Во следниот пост, ќе ги имплементирам истите карактеристики со Alpine.js.


Целосниот изворен код за оваа објава може да се најде на GitHub:

Оди понатаму:



L O A D I N G
. . . comments & more!

About Author

Nicolas Fränkel HackerNoon profile picture
Nicolas Fränkel@nfrankel
Developer Advocate for Apache APISIX *** Learner *** Author of http://leanpub.com/integrationtest

ВИСЕТЕ ТАГОВИ

ОВОЈ СТАТИЈА БЕШЕ ПРЕТСТАВЕН ВО...