Создание современного приложения с помощью Django и Vue – часть вторая

Теперь, когда мы закончили с бэкендом, пришло время создать фронтенд нашего приложения. В этом уроке мы будем использовать Vue.js для создания фронтенд-приложения. Опять же, давайте начнем с краткого обзора. Если вы никогда раньше не использовали этот фреймворк, пожалуйста, сначала изучите учебник Vue.js For Beginners.

Вы можете скачать исходный код этого учебника здесь:

Скачать исходный код

Краткий обзор Vue.js

Vue.js – это front-end JavaScript фреймворк, который предоставляет нам простую систему, основанную на компонентах, что позволяет нам создавать сложные пользовательские интерфейсы. Компонентная система означает, что корневой компонент (App.vue) может импортировать другие компоненты (файлы с расширением .vue), а эти другие компоненты могут импортировать больше компонентов, что позволяет нам создавать очень сложные системы.

Типичный файл Vue содержит три секции, секция <template> включает HTML-коды, секция <script> включает JavaScript-коды, а секция <style> включает CSS-коды.

В разделе <script> мы можем объявить новые привязки внутри функции data(). Затем эти привязки могут быть отображены в разделе <template> с помощью синтаксиса двойных фигурных скобок ({{ binding }}). Привязки, объявленные внутри метода data(), будут автоматически обернуты в систему реактивности Vue. Это означает, что при изменении значения привязки соответствующий компонент будет автоматически отображаться, без необходимости обновлять страницу.

Раздел <script> также может содержать методы, отличные от data(), такие как computed, props, methods и так далее. А <template> также позволяет нам связывать данные с помощью таких директив, как v-bind, v-on и v-model. Если вы не знаете, что это такое, пожалуйста, сначала изучите этот учебник: Vue.js для начинающих.

Создайте новый проект Vue.js

В учебнике “Vue.js для начинающих” мы установили и создали приложение Vue с помощью инструмента командной строки Vue. В этот раз мы поступим по-другому. Мы будем использовать инструмент для сборки фронтенда под названием Vite (произносится как “veet”, французское слово, означающее “быстрый”), который был создан тем же человеком, который создал Vue.js.

Зайдите в папку frontend и выполните следующую команду:

npm init vue@latest
Войти в полноэкранный режим Выйти из полноэкранного режима

Вам будет предложено несколько вариантов, для нашего проекта нам нужно добавить только Vue Router:

✔ Project name: … <your-project-name>
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit testing? … No / Yes
✔ Add Cypress for both Unit and End-to-End testing? … No / Yes
✔ Add ESLint for code quality? … No / Yes
✔ Add Prettier for code formating? … No / Yes

Scaffolding project in ./<your-project-name>...
Done.
Войти в полноэкранный режим Выйти из полноэкранного режима

Если вам удобнее работать с языком сильных типов, вы можете установить TypeScript. Если вам нужна автокоррекция кода, вы можете установить ESlint и Prettier.

В результате этого процесса в вашем проекте будет создан файл package.json, в котором хранятся необходимые пакеты и их версии. Вам необходимо установить эти пакеты в свой проект.

cd <your-project-name>
npm install
npm run dev
Вход в полноэкранный режим Выход из полноэкранного режима

Еще один момент, прежде чем мы начнем создавать фронтенд-приложение. В нашем проекте мы используем CSS-фреймворк под названием TailwindCSS. Чтобы установить его, выполните следующую команду:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Войти в полноэкранный режим Выйти из полноэкранного режима

В результате будут созданы два файла, tailwind.config.js и postcss.config.js. Это не учебник по CSS или Tailwind, я предполагаю, что вы уже знаете, как их использовать, и что такое PostCSS. Если нет, пожалуйста, прочитайте их документацию. Tailwind: (https://tailwindcss.com/docs/editor-setup). PostCSS: (https://github.com/postcss/postcss/tree/main/docs).

Перейдите в tailwind.config.js, и добавьте путь ко всем файлам вашего шаблона:

module.exports = {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Вход в полноэкранный режим Выйти из полноэкранного режима

Создайте файл ./src/index.css и добавьте директивы @tailwind для каждого из слоев Tailwind.

@tailwind base;
@tailwind components;
@tailwind utilities;
Вход в полноэкранный режим Выйдите из полноэкранного режима

Импортируйте вновь созданный файл ./src/index.css в файл ./src/main.js.

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './main.css'

const app = createApp(App)

app.use(router)

app.mount('#app')
Вход в полноэкранный режим Выйдите из полноэкранного режима

Теперь вы должны иметь возможность использовать Tailwind внутри файлов .vue. Давайте проверим это.

<template>
  <header>
    ...
    <div class="wrapper">
      <HelloWorld msg="You did it!" />
      <h1 class="text-3xl font-bold underline">Hello world!</h1>
      ...
    </div>
  </header>
  ...
</template>
Войдите в полноэкранный режим Выход из полноэкранного режима

Мы добавили заголовок <h1> после <HelloWorld>, и этот заголовок использует классы Tailwind.

Маршрутизатор Vue

Также обратите внимание, что на этот раз каталог нашего проекта немного отличается.

Внутри каталога src находятся папки router и views. Каталог router содержит файл index.js. Здесь мы можем определить наши маршрутизаторы. Каждый маршрутизатор будет указывать на компонент представления, который находится в каталоге views, а представление может расширяться на другие компоненты в каталоге components.

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/',
      name: 'home',
      component: HomeView
    },
    {
      path: '/about',
      name: 'about',
      // route level code-splitting
      // this generates a separate chunk (About.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import('../views/AboutView.vue')
    }
  ]
})

export default router
Вход в полноэкранный режим Выход из полноэкранного режима

Чтобы вызвать определенный маршрутизатор, загляните в файл App.vue. Вместо тега <a> мы используем тег <RouterLink>, который импортируется из пакета vue-router.

<script setup>
import { RouterLink, RouterView } from "vue-router";
...
</script>

<template>
  <header>
    ...
    <div class="wrapper">
      ...
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
      </nav>
    </div>
  </header>

  <RouterView />
</template>
Вход в полноэкранный режим Выход из полноэкранного режима

Во время рендеринга страницы тег <RouterView /> будет заменен соответствующим представлением.

Если вы не хотите импортировать эти компоненты, просто используйте вместо них <router-link to=""> и <router-view>. Лично я предпочитаю этот способ, потому что всегда забываю их импортировать.

Создание маршрутов

Для нашего блог-приложения нам нужно создать как минимум 6 страниц. Нам нужна главная страница, которая отображает список последних страниц, страница категорий/тегов, которая отображает все категории/теги, страница категорий/тегов, которая отображает список постов, принадлежащих данной категории/тегу, и, наконец, страница поста, которая отображает содержание поста, а также комментарии.

Итак, вот какие маршрутизаторы я создал.

import { createRouter, createWebHistory } from "vue-router";
import HomeView from "@/views/main/Home.vue";
import PostView from "@/views/main/Post.vue";
import CategoryView from "@/views/main/Category.vue";
import TagView from "@/views/main/Tag.vue";
import AllCategoriesView from "@/views/main/AllCategories.vue";
import AllTagsView from "@/views/main/AllTags.vue";

const routes = [
  {
    path: "/",
    name: "Home",
    component: HomeView,
  },
  {
    path: "/category",
    name: "Category",
    component: CategoryView,
  },
  {
    path: "/tag",
    name: "Tag",
    component: TagView,
  },
  {
    path: "/post",
    name: "Post",
    component: PostView,
  },
  {
    path: "/categories",
    name: "Categories",
    component: AllCategoriesView,
  },
  {
    path: "/tags",
    name: "Tags",
    component: AllTagsView,
  },
];

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

export default router;

Вход в полноэкранный режим Выход из полноэкранного режима

Обратите внимание, что в этой статье мы создаем только интерфейс фронтенда, мы пока не занимаемся передачей данных, поэтому не беспокойтесь о том, как найти нужный пост/категорию/тег прямо сейчас.

Представления и компоненты

Это внешний пользовательский интерфейс, который я создал для этого проекта, вы можете использовать мой код напрямую или, если он вам не нравится, вы можете следовать этому руководству по Vue.js (Vue.js для начинающих) и создать свой собственный.

  • Изображения


  <template>
    <div class="container mx-auto max-w-3xl px-4 sm:px-6 xl:max-w-5xl xl:px-0">
      <div class="flex flex-col justify-between h-screen">
        <header class="flex flex-row items-center justify-between py-10">
          <div class="nav-logo text-2xl font-bold">
            <router-link to="/">Django Vue Starter Blog</router-link>
          </div>
          <div class="nav-links hidden sm:block">
            <router-link
              to="/"
              class="mx-2 font-sans font-medium hover:underline hover:text-teal-700"
              >Home</router-link
            >
            <router-link
              to="/categories"
              class="mx-2 font-sans font-medium hover:underline hover:text-teal-700"
              >Category</router-link
            >
            <router-link
              to="/tags"
              class="mx-2 font-sans font-medium hover:underline hover:text-teal-700"
              >Tag</router-link
            >
          </div>
        </header>

        <router-view />

        <footer class="flex flex-col place-items-center mt-5 py-5 border-t-2">
          <div class="mb-3 flex space-x-4">
            <i
              class="fa-brands fa-linkedin text-3xl text-gray-700 hover:text-teal-700"
            ></i>
            ...
          </div>
          <div class="mb-3 flex space-x-1 text-sm text-gray-700">
            <div>
              <a
                href="<https://www.ericsdevblog.com>"
                class="hover:underline hover:text-teal-700"
                >Eric Hu</a
              >
            </div>
            <div></div>
            <div>© 2022</div>
            <div></div>
            <a href="/" class="hover:underline hover:text-teal-700"
              >Vue.js Starter Blog</a
            >
          </div>
        </footer>
      </div>
    </div>
  </template>

  <script>
  export default {
    ...
  };
  </script>

Вход в полноэкранный режим Выход из полноэкранного режима
  <template>
    <div class="home">
      <h1 class="text-5xl font-extrabold mb-2">Recent Posts</h1>
      <p class="text-gray-500 text-lg mb-5">
        A blog created with Django, Vue.js and TailwindCSS
      </p>

      <post-list></post-list>
    </div>
  </template>

  <script>
  // @ is an alias to /src
  import PostList from "@/components/PostList.vue";

  export default {
    components: { PostList },
    name: "HomeView",
  };
  </script>

Войти в полноэкранный режим Выход из полноэкранного режима
  <template>
    <div class="flex flex-col place-content-center place-items-center">
      <div class="py-8 border-b-2">
        <h1 class="text-5xl font-extrabold">All Categories</h1>
      </div>
      <div class="flex flex-wrap py-8">
        <router-link
          class="my-2 mr-5 text-sm font-medium uppercase text-teal-500 hover:underline hover:text-teal-700"
          to="/category"
          >Category Name</router-link
        >
        <router-link
          class="my-2 mr-5 text-sm font-medium uppercase text-teal-500 hover:underline hover:text-teal-700"
          to="/category"
          >Category Name</router-link
        >
        ...
      </div>
    </div>
  </template>

  <script>
  export default {
    name: "CategoriesView",
  };
  </script>

Войти в полноэкранный режим Выход из полноэкранного режима
  <template>
    <div>
      <h1 class="text-5xl font-extrabold mb-2">Category Name</h1>
      <p class="text-gray-500 text-lg mb-5">
        A blog created with Django, Vue.js and TailwindCSS
      </p>

      <post-list></post-list>

    </div>
  </template>

  <script>
  // @ is an alias to /src
  import PostList from "@/components/PostList.vue";

  export default {
    components: { PostList },
    name: "CategoryView",
  };
  </script>

Войти в полноэкранный режим Выход из полноэкранного режима
  <template>
    <div class="home">
      <div class="flex flex-col place-items-center border-b-2">
        <!-- Featured Image and title -->
        <img src="..." class="w-full my-5" />
        <h1 class="text-center text-5xl font-extrabold mb-5">
          Post Title
        </h1>
        <p class="text-gray-500 text-lg mb-2">
          March 3, 2022 - By Eric Hu
        </p>
      </div>

      <!-- Tags -->
      <div class="flex flex-wrap my-4">
        <div class="mr-5 text-sm font-medium">Tags:</div>
        <router-link
          class="mr-5 text-sm font-medium uppercase text-teal-500 hover:underline hover:text-teal-700"
          to="/tag"
          >Tag Name</router-link
        >
        ...
      </div>

      <!-- Main content -->
      <div class="py-5 font-serif space-y-4">
        Lorem Lipsum ...
      </div>

      <!-- Like, Comment and Share -->
      ...

      <!-- Comment Section -->
      ...
    </div>
  </template>

  <script></script>

Войти в полноэкранный режим Выход из полноэкранного режима
  <template>
    <div class="post-list">
      <ul v-if="publishedPosts" class="divide-y divide-gray-200">
        <li class="py-12">
          <article>
            <div
              class="space-y-2 xl:grid xl:grid-cols-4 xl:items-baseline xl:space-y-0"
            >
              <dl>
                <dt class="sr-only">Published on</dt>
                <dd
                  class="text-base font-medium leading-6 text-gray-500 dark:text-gray-400"
                >
                  <time>March 3, 2022</time>
                </dd>
              </dl>
              <div class="space-y-5 xl:col-span-3">
                <div class="space-y-6">
                  <div>
                    <h2 class="text-2xl font-bold leading-8 tracking-tight">
                      <router-link
                        class="text-gray-900"
                        to="/post"
                        >This is a post title</router-link
                      >
                    </h2>
                    <router-link
                      class="text-sm font-medium uppercase text-teal-500 hover:underline hover:text-teal-700"
                      to="/category"
                      >Category</router-link
                    >
                  </div>
                  <div class="prose max-w-none text-gray-500">
                    Lorem Lipsum ...
                  </div>
                </div>
                <div class="text-base font-medium leading-6">
                  <router-link
                    class="text-teal-500 hover:underline hover:text-teal-700"
                    to="/post"
                    >Read more →</router-link
                  >
                </div>
              </div>
            </div>
          </article>
        </li>
        ...
      </ul>
    </div>
  </template>

  <script>
  export default {
    name: "PostListComponent",
  };
  </script>

Войти в полноэкранный режим Выход из полноэкранного режима

Оцените статью
Procodings.ru
Добавить комментарий