Исходный код: https://github.com/ITmind/django-vue-template

Вторым по популярности реактивным фрамеворком является Vue. Синтаксис Composition API в версии Vue 3 очень напоминает синтаксис Svelte. Перепишем наш шаблон для Svelte на Vue, что бы посмотреть на отличия.

Копируем шаблон Svelte, удаляем папку svelte_app и создаем папку vue_app. В папке vue_app создаем приложение Vue на базе штатного шаблона из Vite. В папке /vue_app/src/components/ файл Notes.vue.

Код в Notes.vue почти идентичен коду из Svelte.vue. Область шаблона:

<template>
    <h3>Заметки</h3>
    <table>
        <thead>
        <tr>
            <th>Дата</th>
            <th>Название</th>
            <th colspan="2">
                <button class="btnadd" @click="add">Добавить</button>
            </th>
        </tr>
        </thead>
        <tbody>

        <tr v-for="note in notes" @click="event => onSelectRow(note)">

            <td v-if="note.edit"><input class="editable" type="date" v-model="note.date"></td>
            <td v-else>{{ note.date }}</td>
            <td v-if="note.edit"><input class="editable" v-model="note.title"></td>
            <td v-else>{{ note.title }}</td>
            <td>
                <button @:click="event => onEditClick(event, note)">Edit</button>
            </td>
            <td><a href="notes/{note.slug}/">Details</a></td>
        </tr>

        </tbody>
    </table>
    
    <input v-if="currentNote.edit" class="note editable" v-model="currentNote.note">
    <div v-else class="note noteditable">{{ currentNote.note }}</div>
</template>

Основное отличие от Svelte в том, что здесь условия и циклы не отдельные теги, а атрибуты обычных тегов. На мой взгляд это ухудшает чтение шаблона.

Область кода (script) практически повторят код из Svelte. В Vue переменные просто так не становятся “реактивными”, их нужно объявить особым образом . Для массива используем reactive() который создает прокси объекта с переопределенными методами get и set. Для текущей записи используем ref(). И перепишем функцию чтения данных, т.к. reactive() является не переопределяемым. (т.е. нужно менять объект по первоначальной ссылке)

import { ref, reactive, onMounted } from 'vue'


const notes = reactive([...Array(3).keys()].map(() => {
    return {date: '', title: '1'}
}));
let currentNote = ref({note: ''});

onMounted(readTable)

async function readTable() {
    let response = await fetch("/notes");
    const temp = await response.json()
    notes.length = 0
    for(let el of temp){
        notes.push(el)
    }
    notes.map((value) => value['edit'] = false);

}

reactive() делает все элементы массив тоже reactive и для сравнивать элемент массив с currentNote нам нужно следующим образом:

if (currentNote.value !== note) {
    ...
}

Value у ref() это то же reactive (прокси) и два прокси можно сравнить между собой.

И еще один момент связанный с отладкой. По умолчанию Vite делает build в режиме production и код js минифицирован. Это когнитивно усложняет отладку, поэтому в vite.config.js включим sourcemap:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  // параметр base определят директорию прямой ссылки на статические файлы (используется при разыменовывании относительных ссылок в скриптах)
  base: "/static/spa",
  //для отладки
  mode: "development",
  build: {
    //Для отладки
    sourcemap: true,
    //сюда будем выкладывать артефакты
    outDir: "../static/spa",
    //сюда картинки и прочее midia
    assetsDir: './assets',

    rollupOptions: {
      output: {
        //название главного файла javascript
        entryFileNames: '[name].js',
        //Название остальных файлов. Если не прописать, то к имени будет дописывать случайный id
        assetFileNames: '[name].[ext]',
      },
    },
  }
})

После этого в в панели разработчика браузера появится дополнительная “папка” с нормальным кодом в котором мы можем ставить точки останова (Если не появилась, то установите расширение vue js devtool)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *