На заре Интернета ряд статических HTML-файлов был связан вместе, чтобы сформировать веб-сайт. Щелчок по ссылкам страниц вызовет запросы к серверу, который ответит новым HTML-файлом.
Однако развитие JavaScript и появление AJAX сделали возможным отправку и получение данных с сервера без полной перезагрузки страницы. Эти технологии добавили динамизма веб-сайтам, открыв дверь для значительного прогресса в том, как веб-сайты работают сегодня. Например, с помощью JavaScript можно обрабатывать взаимодействие с пользователем и обновлять веб-сайты с помощью асинхронных запросов.
Эти типы веб-сайтов стали известны как одностраничные приложения (SPA). На фоне этого несколько библиотек и фреймворков JavaScript получили известность, особенно Vue.js.
В этой статье вы узнаете, как создать одностраничное приложение с использованием Vue.js и PHP-фреймворка Yii 2.0 ; CRUD API для библиотечного приложения, которое будет обрабатывать один основной ресурс: книги.
Предпосылки
В этом руководстве вам поможет базовое понимание Yii 2.0 и PHP. Тем не менее, я буду давать пояснения и ссылки на официальную документацию на протяжении всего руководства. Если вам неясна какая-либо концепция, вы можете просмотреть связанный материал, прежде чем продолжить обучение.
Вам также потребуется базовое понимание Vue.js и ES6 , чтобы помочь в создании SPA, а также следующее, установленное в вашей системе:
- PHP 7.4 с включенным расширением PDO .
- Композитор установлен глобально.
- Локальный сервер базы данных. Хотя в этом руководстве будет использоваться SQLite , вы можете выбрать предпочитаемую службу базы данных.
- Менеджер пакетов JavaScript, такой как NPM или Yarn (который я буду использовать).
Создайте серверную часть
Создайте проект Yii 2.0
Для начала создайте новое приложение с именем vue_library_app и переключитесь в каталог проекта, используя следующие команды.
composer create-project --prefer-dist yiisoft/yii2-app-basic vue_library_app
cd vue_library_app
Затем запустите приложение с помощью следующей команды.
php yii serve
По умолчанию приложение будет обслуживаться по адресу http://localhost:8080/ . Откройте URL-адрес в своем браузере, где вы должны увидеть страницу приветствия, как показано ниже.
Вернитесь к терминалу и нажмите Ctrl + C , чтобы выйти из приложения.
Настройка базы данных
Создайте новый каталог в корне приложения с именем db и в нем файл с именем app.db. Затем обновите config/db.php , чтобы он соответствовал следующему коду.
<?php
return [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:' . dirname(__DIR__) . '/db/app.db',
'charset' => 'utf8',
];
Создать перенос книги
Затем создайте миграцию для таблицы базы данных. Приложение будет иметь одну сущность с именем Book
, которая будет представлять книгу, доступную в библиотеке. Для этой статьи таблица book будет содержать название книги, автора, IBAN и год выпуска.
Чтобы создать миграцию, используйте приведенную yii migrate/create
ниже команду, указав имя создаваемой миграции ( create_book_table
). При запросе подтверждения введите «да», чтобы миграция была создана.
php yii migrate/create create_book_table
По умолчанию файлы миграции находятся в каталоге миграции . Их имена файлов начинаются с буквы m и даты и времени создания в формате UTC, например, migrations/m<ГГММДД_ЧЧММСС>_create_book_table.php .
Отредактируйте safeUp
функцию migrations/m<ГГММДД_ЧЧММСС>_create_book_table.php , чтобы она соответствовала следующему коду.
public function safeUp()
{
$this->createTable('book', [
'id' => $this->primaryKey(),
'title' => $this->string(),
'author' => $this->string(),
'iban' => $this->string(),
'release_year' => $this->smallInteger(),
'cover_image' => $this->string()
]);
}
Заполнить базу данных
Чтобы вставить некоторые поддельные данные в таблицу, создайте начальную миграцию, выполнив следующую команду и ответив «да» на запрос.
php yii migrate/create seed_book_table
Откройте файл миграции, migrations/m<ГГММДД_ЧЧММСС>_seed_book_table.php и замените safeUp
функцию следующими двумя функциями.
public function safeUp()
{
$this->insertFakeBooks();
}
private function insertFakeBooks()
{
$faker = \Faker\Factory::create();
for ($i = 0; $i < 50; $i++) {
$this->insert(
'book',
[
'title' => $faker->sentence(),
'author' => $faker->name,
'iban' => $faker->iban(),
'release_year' => (int)$faker->year,
'cover_image' => $faker->imageUrl()
]
);
}
}
Затем запустите все миграции, используя следующую команду, введя «yes» и нажав Enter при появлении запроса:
php yii migrate
Вы можете убедиться, что база данных была создана и заполнена с помощью инструмента командной строки SQLite3 , выполнив следующую команду.
sqlite3 -table db/app.db "select * from book limit 10;"
Первые 10 книг в базе данных будут напечатаны в командной строке в красиво отформатированной таблице.
Если -table
он недоступен, попробуйте использовать -line
или -column
вместо него.
Создать модель книги
Вместо написания необработанных SQL-запросов для взаимодействия с базой данных мы будем использовать ActiveRecord для нашей модели. Это даст нам объектно-ориентированные средства доступа и хранения данных в базе данных.
Создайте ActiveRecord для объекта Book, выполнив приведенную ниже команду.
php yii gii/model --tableName=book --modelClass=Book
Введите «да» и нажмите Enter , когда будет предложено.
Класс модели создается в каталоге моделей и называется Book.php . Имея готовую модель, мы теперь можем создать контроллер для обработки вызовов RESTful API.
Создайте контроллер книги
Для начала создайте контроллер для объекта Book. Yii 2.0 предоставляет класс ActiveController , который обеспечивает общие действия RESTful , позволяя нам создавать конечные точки для обработки действий CRUD без необходимости самостоятельно писать шаблонный код.
Для этого выполните команду ниже.
php yii gii/controller \
--controllerClass=app\\controllers\\BookController \
--baseClass=yii\\rest\\ActiveController
Введите «да» и нажмите Enter , когда будет предложено.
Аргумент controllerClass
указывает имя создаваемого контроллера. Ожидается, что вы предоставите класс Fully-Qualified Namespaced (FQN).
Используемый \\
при указании пространства имен экранирует \
символ.
Класс контроллера хранится в каталоге контроллера и называется BookController.php . Откройте controllers/BookController.php и отредактируйте содержимое, чтобы оно соответствовало следующему.
<?php
namespace app\controllers;
use yii\data\ActiveDataProvider;
use yii\rest\ActiveController;
class BookController extends ActiveController
{
public $modelClass = 'app\models\Book';
public function actions(): array
{
$actions = parent::actions();
$actions['index'] = [
'class' => 'yii\rest\IndexAction',
'modelClass' => $this->modelClass,
'prepareDataProvider' => fn() => new ActiveDataProvider(
[
'query' => $this->modelClass::find(),
'pagination' => false,
]
),
];
return $actions;
}
}
В actions
методе мы переопределяем поставщика данных, используемого для index
действия, и отключаем разбиение на страницы, чтобы все книги возвращались одним запросом.
Далее в конфигурации приложения в config/web.php модифицируем urlManager
компонент. Там $config
объявляется массив, который содержит components
массив. В components
массиве раскомментируйте urlManager
компонент и обновите его, чтобы он соответствовал следующему коду.
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'book'],
],
],
Этот код добавляет правило URL для контроллеров книг, чтобы можно было получить доступ к связанным данным и управлять ими с помощью красивых URL-адресов и значимых HTTP-команд .
Массив components
также содержит request
массив, содержащий конфигурацию компонента приложения запроса . Чтобы API мог анализировать ввод JSON, добавьте в request
массив следующее.
'parsers' => [
'application/json' => 'yii\web\JsonParser',
],
На данном этапе мы создали приложение, которое может обрабатывать следующие запросы:
- GET (/books): список всех книг страница за страницей;
- POST (/books): создать новую книгу;
- GET (/books/<id>): вернуть информацию о книге с идентификатором
<id>
; - PATCH и PUT (/books/<id>): обновить книгу с помощью id
<id>
; - УДАЛИТЬ (/books/<id>): удалить книгу с id
<id>
;
Настроить интеграцию с Vue.js
Чтобы наш API правильно работал с интерфейсом, нам нужно внести некоторые дополнительные изменения. Идея состоит в том, чтобы страница индекса обслуживалась приложением Yii 2.0 с приложением Vue, связанным и указанным в <script>
теге.
После загрузки JavaScript приложение Vue нацеливается на указанную <div>
и загружает страницу, а затем обрабатывает взаимодействие с пользователем, не обновляя страницу, выполняя сетевые запросы к API, повторно отображая DOM по мере необходимости.
Первое, что нужно сделать, это зарегистрировать связанное приложение. Для этого откройте assets/AppAsset.php и отредактируйте $js
массив, чтобы он соответствовал следующему коду.
public $js = [
'app.js'
];
Это делает наше связанное приложение Vue доступным в представлениях Yii 2.0.
Затем отредактируйте urlManager
компонент $config
массива в config/web.php , чтобы он соответствовал следующему коду.
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'book'],
'<url:(.*)>' => 'site/index',
],
],
Здесь мы добавляем правило маршрутизации для индексной страницы, чтобы загружать индексную страницу по умолчанию, предоставляемую Yii 2.0. Это правило гарантирует, что индексная страница будет возвращена для любого другого запроса к API Yii 2.0. Это предотвращает возврат API-интерфейсом ошибки 404 при обновлении нашего приложения. Вместо этого загружается индексная страница, а маршрутизатор Vue загружает соответствующий компонент.
Наконец, обновите содержимое views/layouts/main.php , чтобы оно соответствовало следующему коду.
<?php
/* @var $this \yii\\web\View */
/* @var $content string */
use app\assets\AppAsset;
use app\widgets\Alert;
use yii\bootstrap4\Html;
AppAsset::register($this);
?>
<?php
$this->beginPage() ?>
<!DOCTYPE html>
<html lang="<?= Yii::$app->language ?>" class="h-100">
<head>
<meta charset="<?= Yii::$app->charset ?>">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<?php
$this->registerCsrfMetaTags() ?>
<title>Vue Library App</title>
<?php
$this->head() ?>
</head>
<body>
<?php
$this->beginBody() ?>
<div id="app">
</div>
<?php
$this->endBody() ?>
</body>
</html>
<?php
$this->endPage() ?>
Здесь мы удаляем содержимое тела макета. Это означает, что представления Yii 2.0 не будут отображаться, поскольку мы больше не предоставляем их. Мы также объявляем DIV с идентификатором app
. В этот DIV будет монтироваться приложение Vue при загрузке страницы.
Имея это на месте, мы готовы построить интерфейс!
Создайте интерфейс
Настройте зависимости проекта
Прежде чем мы начнем создавать приложение Vue, давайте настроим зависимости для проекта. Создайте новый файл с именем package.json и добавьте в него следующее.
{
"dependencies": {
"ant-design-vue": "^2.2.7",
"axios": "^0.21.4",
"core-js": "^3.6.5",
"vue": "^3.0.0",
"vue-router": "^4.0.6"
},
"devDependencies": {
"@vue/compiler-sfc": "^3.2.11",
"laravel-mix": "^6.0.31",
"vue-loader": "^16.2.0"
}
}
В дополнение к базовой зависимости Vue мы добавляем vue-router для маршрутизации на стороне клиента и Axios для сетевых запросов к API. Ant Design Vue будет использоваться для создания пользовательского интерфейса приложения.
Мы также добавляем некоторые зависимости, доступные только в среде разработки. Laravel Mix будет использоваться для компиляции нашего приложения Vue в один файл JavaScript, который можно импортировать на индексную страницу, обслуживаемую приложением Yii 2.0. vue — loader и компилятор используются для обработки файлов .vue , которые мы будем создавать.
Установите зависимости, выполнив следующую команду.
yarn install
Далее нам нужно настроить Laravel Mix и предоставить некоторую необходимую информацию, которая поможет связать приложение Vue. В корне проекта создайте новый файл с именем webpack.mix.js и добавьте в него следующий код.
const mix = require('laravel-mix');
mix.js('app/app.js', 'web/app.js')
.setPublicPath('web')
.vue();
Точкой входа для приложения Vue является индексный файл app.js , который находится в каталоге приложения . Мы создадим этот файл позже, но сейчас мы просто хотим, чтобы Laravel Mix знал, где он находится.
Мы также указываем выходной путь (и имя) для связанного файла JavaScript. Он будет называться app.js и храниться в веб- каталоге. Затем мы устанавливаем общедоступный путь к веб- каталогу.
Создайте Vue-приложение
В корне проекта создайте новый каталог с именем app. Этот каталог будет содержать весь код, относящийся к интерфейсу. В каталоге приложения создайте два файла: app.js и App.vue .
Добавьте следующее в app/app.js.
import {createApp} from 'vue';
import App from './App.vue';
const app = createApp(App);
app.mount('#app');
Затем добавьте следующий код в App.vue.
<template>
<h1>Welcome to your Yii Powered Vue3 App!!!!</h1>
</template>
Чтобы связать приложение с нашими новыми изменениями, выполните следующую команду.
yarn mix
Когда Webpack завершит компиляцию и отобразит подтверждающее сообщение, запустите приложение с помощью следующей команды.
php yii serve
Затем перейдите на индексную страницу ( по умолчанию http://localhost:8080/ ), где вы должны увидеть приветственное сообщение, похожее на скриншот ниже.
На данный момент ничего захватывающего (за исключением того, что мы только что получили Vue и Yii 2.0, чтобы хорошо играть!). В следующих разделах мы создадим функции CRUD приложения.
Создание помощника API
В каталоге приложения создайте новый файл с именем api.js и добавьте в него следующий код.
import axios from 'axios';
const axiosClient = axios.create({
baseURL: 'http://localhost:8080',
responseType: 'json',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
export default {
helpGet: url => axiosClient.get(url).then(res => res.data),
helpPost: (url, data) => axiosClient.post(url, data).then(res => res.data),
helpPatch: (url, data) => axiosClient.patch(url, data).then(res => res.data),
helpDelete: (url) => axiosClient.delete(url)
}
Здесь мы создаем экземпляр Axios с baseUrl
набором URL-адреса нашего приложения Yii 2.0. Затем мы экспортируем четыре функции, чтобы помочь с четырьмя методами запросов, которые мы собираемся использовать (GET, POST, PATCH и DELETE). Помимо helpDelete()
метода, обещание , возвращаемое каждым вспомогательным методом, может быть разрешено для получения данных, возвращаемых API.
Создайте компонент BooksList
Компонент BooksList
отобразит все книги в библиотеке. Для начала создайте новый каталог с именем components в каталоге приложения и в этом каталоге новый файл с именем BooksList.vue.
Добавьте следующий код во вновь созданный файл app/components/BooksList.vue .
<template>
<a-button
type='primary'
style='margin-bottom: 8px'
@click='showAddBookForm'
>
Add Book
</a-button>
<a-table
:dataSource='books'
:columns='columns'
rowKey='id'
bordered
>
<template #action='{ record }'>
<div>
<a-button
type='primary'
@click='showBook(record.id)'
style='margin-right: 5px'
ghost
>
View
</a-button>
<a-button
@click='showEditBookForm(record.id)'
style='margin-right: 5px'
>
Edit
</a-button>
<a-popconfirm
title='Delete book? This action cannot be undone'
@confirm='deleteBook(record.id)'
okText='Delete'
okType='danger'
>
<template #icon>
<WarningOutlined style='color: red'/>
</template>
<a-button danger>
Delete
</a-button>
</a-popconfirm>
</div>
</template>
</a-table>
</template>
<script>
import api from '../api';
import {
PlusOutlined,
EyeOutlined,
EditOutlined,
DeleteOutlined,
WarningOutlined
} from '@ant-design/icons-vue';
export default {
components: {
PlusOutlined,
EditOutlined,
EyeOutlined,
DeleteOutlined,
WarningOutlined
},
data() {
return {
books: [],
columns: [
{
title: 'Name',
dataIndex: 'title',
key: 'title',
ellipsis: true
},
{
title: 'Author',
dataIndex: 'author',
key: 'author',
},
{
title: 'Release Year',
dataIndex: 'release_year',
key: 'release_year',
},
{
title: 'Action',
key: 'action',
slots: {customRender: 'action'},
},
]
};
},
methods: {
async deleteBook(bookId) {
await api.helpDelete(`books/${bookId}`);
this.books = this.books.filter(({id}) => id !== bookId);
},
showBook(bookId) {
this.$router.push({name: 'book-item', params: {bookId}});
},
showAddBookForm() {
this.$router.push('/book/add');
},
showEditBookForm(bookId) {
this.$router.push({name: 'book-form', params: {bookId}});
}
},
async mounted() {
this.books = await api.helpGet('books');
}
};
</script>
В этом компоненте наш шаблон состоит из кнопки для добавления новой книги и таблицы, показывающей существующие книги. В таблице есть три столбца, в которых указаны название, автор и год выпуска каждой книги. Также есть столбец действий с тремя вариантами просмотра, редактирования и удаления книг.
Компонент также прослушивает событие жизненного цикла монтирования , где он отправляет запрос API, чтобы получить все книги и установить их в компонент данных книг.
Создайте компонент BookForm
Далее мы создадим форму для добавления новой книги. В каталоге app/components создайте новый файл с именем BookForm.vue и добавьте в него следующий код.
<template>
<a-card
hoverable
style='width: 100%'
:loading='loading'
>
<a-form
:model='book'
:label-col='labelCol'
:wrapper-col='wrapperCol'
:rules='rules'
>
<a-form-item
label='Book title'
v-bind='validationErrors.title'
>
<a-input
v-model:value='book.title'
/>
</a-form-item>
<a-form-item
label='Author'
v-bind='validationErrors.author'
>
<a-input
v-model:value='book.author'
/>
</a-form-item>
<a-form-item
label='IBAN'
v-bind='validationErrors.iban'
>
<a-input
v-model:value='book.iban'
/>
</a-form-item>
<a-form-item
label='Release Year'
v-bind='validationErrors.release_year'
>
<a-input
v-model:value='book.release_year'
/>
</a-form-item>
<a-form-item
label='Cover Image URL'
v-bind='validationErrors.cover_image'
>
<a-input
v-model:value='book.cover_image'
/>
</a-form-item>
<a-form-item
:wrapper-col='{ span: 14, offset: 4 }'
>
<a-button
size='large'
type='primary'
@click='handleSubmit'
>
{{ isEdit ? 'Update' : 'Create' }}
</a-button>
<a-button
size='large'
style='margin-left: 10px'
@click='resetFields'
v-if='!isEdit'
>
Reset
</a-button>
<a-button
size='large'
style='margin-left: 10px'
@click='showAllBooks'
danger
>
Cancel
</a-button>
</a-form-item>
</a-form>
</a-card>
</template>
<script>
import api from '../api';
import {Form} from 'ant-design-vue';
import {reactive} from 'vue';
import {useRouter} from 'vue-router'
const {useForm} = Form;
export default {
setup(props) {
let book = reactive({
title: '',
author: '',
iban: '',
release_year: '',
cover_image: '',
});
const rules = reactive({
title: [
{
required: true,
message: 'Please provide book title',
trigger: 'blur'
},
],
author: [
{
required: true,
message: 'Please provide book author',
trigger: 'blur'
},
],
iban: [
{
required: true,
message: 'Please provide book IBAN',
trigger: 'blur'
},
],
release_year: [
{
required: true,
message: 'Please provide book release year',
trigger: 'blur'
},
{
length: 4,
message: 'Length should be 4',
trigger: 'blur'
},
],
cover_image: [
{
required: true,
message: 'Please provide url for book cover image',
trigger: 'blur'
},
],
});
const {
resetFields,
validate,
validateInfos: validationErrors
} = useForm(book, rules);
const router = useRouter();
const handleSubmit = () => {
validate()
.then(
async () => {
const {bookId} = props;
const updatedBook = !!bookId ?
await api.helpPatch(`books/${bookId}`, book) :
await api.helpPost('books', book);
Object.assign(book, updatedBook);
router.push({name: 'book-item', params: {bookId: book.id}});
}
)
.catch(() => {
});
}
return {
resetFields,
validationErrors,
book,
handleSubmit,
rules
};
},
props: ['bookId'],
data() {
return {
isEdit: !!this.bookId,
loading: !!this.bookId,
labelCol: {span: 4},
wrapperCol: {span: 14},
}
},
methods: {
async loadBook() {
Object.assign(this.book, await api.helpGet(`books/${this.bookId}`));
this.loading = false;
},
showAllBooks() {
this.$router.push({name: 'books'});
},
},
async mounted() {
if (this.isEdit) {
await this.loadBook();
}
}
};
</script>
Шаблон для этого компонента представляет собой форму с полями для названия, автора, IBAN, года выпуска и URL-адреса обложки добавляемой книги. Кроме того, в форму добавлены кнопка отправки, кнопка сброса и кнопка отмены.
Поскольку эта форма будет использоваться либо для создания новой книги, либо для редактирования существующей книги, мы проверяем, передается ли идентификатор книги в качестве реквизита в смонтированном событии жизненного цикла. Если указан идентификатор, выполняется запрос API для получения книги и заполнения полей формы.
При handleSubmit()
отправке вызывается функция, которая проверяет форму перед отправкой соответствующего запроса POST или PATCH для создания или обновления книги соответственно. В случае успеха приложение перенаправляется к представлению, отображающему сведения о книге.
Создайте компонент BookItem
В каталоге app/components создайте новый файл с именем BookItem.vue и добавьте в него следующий код.
<template>
<a-spin
tip='Loading Book'
v-if='book === null'
>
</a-spin>
<a-card
hoverable
style='width: 60%'
v-else
>
<template #cover>
<img
alt='example'
:src='book.cover_image'
/>
</template>
<template
class='ant-card-actions'
#actions
>
<a-button
@click='showAllBooks'
type='primary'
style='margin-right: 5px'
ghost
>
Home
</a-button>
<a-button
@click='showEditBookForm'
style='margin-right: 5px'
>
Edit
</a-button>
<a-popconfirm
title='Delete book? This action cannot be undone'
@confirm='deleteBook'
okText='Delete'
okType='danger'
>
<template #icon>
<WarningOutlined style='color: red'/>
</template>
<a-button danger>
Delete
</a-button>
</a-popconfirm>
</template>
<a-card-meta
:title='book.title'
:description='`Book by ${book.author}`'
>
<template #avatar>
<a-avatar
src='<https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png>'
/>
</template>
</a-card-meta>
<a-row style='margin-top: 50px'>
<a-col :span='6'>
<a-statistic
title='Release Year'
groupSeparator=''
:value='book.release_year'
style='margin-right: 50px'
/>
</a-col>
<a-col :span='18'>
<a-statistic
title='IBAN'
:value='book.iban'
groupSeparator=''
/>
</a-col>
</a-row>
</a-card>
</template>
<script>
import api from '../api';
import {
EditOutlined,
ArrowLeftOutlined,
WarningOutlined,
DeleteOutlined
} from '@ant-design/icons-vue';
export default {
props: ['bookId'],
data() {
return {
book: null
}
},
components: {
EditOutlined,
ArrowLeftOutlined,
WarningOutlined,
DeleteOutlined
},
methods: {
async loadBook() {
this.book = await api.helpGet(`books/${this.bookId}`);
},
showAllBooks() {
this.$router.push({name: 'books'});
},
showEditBookForm() {
this.$router.push({name: 'book-form', params: {bookId: this.bookId}});
},
async deleteBook() {
await api.helpDelete(`books/${this.bookId}`);
this.showAllBooks();
}
},
async mounted() {
await this.loadBook();
}
};
</script>
В этом компоненте мы отображаем сведения о книге и добавляем параметры для отображения всех книг, редактирования книги и удаления книги. Когда компонент смонтирован, книга извлекается из API с использованием идентификатора книги, переданного в качестве реквизита.
Создать маршрутизатор
В каталоге приложения создайте новый файл с именем router.js и добавьте в него следующий код.
import {createRouter, createWebHistory} from 'vue-router';
import BooksList from './components/BooksList';
import BookItem from './components/BookItem';
import BookForm from './components/BookForm';
const router = createRouter({
history: createWebHistory(),
routes: [
{
name: 'books',
path: '/',
component: BooksList,
},
{
name: 'book-form',
path: '/book/edit/:bookId?',
component: BookForm,
props: true,
alias: '/book/add'
},
{
name: 'book-item',
path: '/book/:bookId(\\d+)',
component: BookItem,
props: true
},
],
});
export default router;
Обновите компонент приложения
Обновите app/App.vue , чтобы он соответствовал следующему коду.
<template>
<div class='container'>
<a-typography-title>Vue Library App</a-typography-title>
<router-view></router-view>
</div>
</template>
<script>
import BooksList from './components/BooksList.vue';
import BookItem from './components/BookItem';
export default {
components: {
BooksList,
BookItem
}
}
</script>
<style scoped>
.container {
padding: 2%;
}
</style>
Используя компонент представления маршрутизатора, мы отобразим компонент, назначенный совпадающему маршруту.
Обновить app.js
Наконец, обновите app/app.js , чтобы он соответствовал следующему коду.
import { createApp } from 'vue';
import router from './router';
import App from './App.vue';
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
const app = createApp(App);
app.use(Antd);
app.use(router);
app.mount('#app');
Создайте файлы внешнего интерфейса
Затем свяжите приложение со всеми новыми изменениями, используя следующую команду.
yarn mix
Протестируйте приложение
Теперь протестируйте приложение, запустив его с помощью следующей команды:
php yii serve
Посмотреть список книг
Откройте http://localhost:8080/
, где вы увидите список всех доступных книг в базе данных.
Создать книгу
Чтобы создать новую книгу, нажмите кнопку « Добавить книгу» . Вы будете перенаправлены на страницу, похожую на показанную ниже:
Заполните форму соответствующим образом и нажмите кнопку « Создать » .
Обновить книгу
В списке, отображаемом на главной странице, нажмите кнопку « Изменить » , чтобы обновить сведения о любой книге в списке. Обновите одно или несколько доступных полей и нажмите кнопку « Обновить » .
Удалить книгу
Чтобы удалить книгу, нажмите кнопку « Удалить » в столбце «Действие» для книги и нажмите « Удалить » во всплывающем окне, чтобы подтвердить, что вы хотите удалить книгу.
Вывод
В этой статье вы узнали, как интегрировать приложение Vue в проект Yii 2.0. Чтобы помочь с этим, вы использовали Laravel Mix для объединения приложения Vue в один файл js, который регистрируется и внедряется на страницу индекса. Вы также использовали правило перехвата всех URL-адресов, чтобы гарантировать, что из бэкэнда Yii 2.0 возвращается только индексная страница, что дает приложению Vue полный контроль над маршрутизацией.