Первоначальная версия
This commit is contained in:
parent
a0fa2798d9
commit
9f4cda9e64
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
||||||
5
babel.config.js
Normal file
5
babel.config.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/app'
|
||||||
|
]
|
||||||
|
}
|
||||||
53
package.json
Normal file
53
package.json
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"name": "learn_vuejs",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build",
|
||||||
|
"lint": "vue-cli-service lint"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"core-js": "^2.6.5",
|
||||||
|
"vue": "^2.6.10",
|
||||||
|
"vue-axios": "^2.1.4",
|
||||||
|
"vuetify": "^1.5.5"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^3.8.0",
|
||||||
|
"@vue/cli-plugin-eslint": "^3.8.0",
|
||||||
|
"@vue/cli-service": "^3.8.0",
|
||||||
|
"babel-eslint": "^10.0.1",
|
||||||
|
"eslint": "^5.16.0",
|
||||||
|
"eslint-plugin-vue": "^5.0.0",
|
||||||
|
"stylus": "^0.54.5",
|
||||||
|
"stylus-loader": "^3.0.1",
|
||||||
|
"vue-cli-plugin-vuetify": "^0.5.0",
|
||||||
|
"vue-template-compiler": "^2.6.10",
|
||||||
|
"vuetify-loader": "^1.0.5"
|
||||||
|
},
|
||||||
|
"eslintConfig": {
|
||||||
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"plugin:vue/essential",
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"rules": {},
|
||||||
|
"parserOptions": {
|
||||||
|
"parser": "babel-eslint"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"postcss": {
|
||||||
|
"plugins": {
|
||||||
|
"autoprefixer": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"> 1%",
|
||||||
|
"last 2 versions"
|
||||||
|
]
|
||||||
|
}
|
||||||
9
public/data/id1.html
Normal file
9
public/data/id1.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<h1>Введение</h1>
|
||||||
|
<p>
|
||||||
|
Привет! Данный самоучитель появился в результате желания освоить Vue.js. Я решил что решать абстрактные задачи
|
||||||
|
и записывать свои мысли в блокнот менее интересно чем создать мини-сайт справочник, описывающий процесс его же
|
||||||
|
создания.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Надеюсь мои заметки окажутся полезными и вам.
|
||||||
|
</p>
|
||||||
37
public/data/id201.html
Normal file
37
public/data/id201.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<h1>Подготовка среды разработки</h1>
|
||||||
|
<h2>Программное обеспечение</h2>
|
||||||
|
<p>
|
||||||
|
Что вам потребуется для создания первого приложения на Vue.js? Самый минимум - это текстовый редактор и
|
||||||
|
наличие интернета, но мы пойдём другим путём, возьмём инструменты разработки для взрослых, а именно:
|
||||||
|
менеджер пакетов npm или yarn, систему контроля версий Git и редактор исходного кода (В моём случае это
|
||||||
|
Visual Stido Code, но вы можете использовать любой другой).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Нужен ли вам yarn - решайте сами, сравнений в интернете много, вот одно из них:
|
||||||
|
<a href="http://prgssr.ru/development/yarn-ili-npm-vse-chto-vam-nuzhno-znat.html" target="_blank">Yarn
|
||||||
|
или npm: все, что вам нужно знать о них</a>. Я в данном руководстве буду его использовать, но если вы
|
||||||
|
решили его не устанавливать, то перевести команды в формат npm не составит труда.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Ссылки</h3>
|
||||||
|
<p>
|
||||||
|
<ol>
|
||||||
|
<li>npm: <a target="_blank" href="https://www.npmjs.com/get-npm">https://www.npmjs.com/get-npm</a></li>
|
||||||
|
<li>yarn: <a target="_blank" href="https://www.yarnpkg.com/ru/docs/install#windows-stable">https://www.yarnpkg.com/ru/docs/install#windows-stable</a></li>
|
||||||
|
<li>Git: <a target="_blank" href="https://git-scm.com/downloads">https://git-scm.com/downloads</a></li>
|
||||||
|
<li>Visual Studio Code: <a target="_blank" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a></li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Установка vue-cli</h3>
|
||||||
|
<p>
|
||||||
|
Установив менеджер пакетов, перейдём к установке vue-cli с помощью которой в будущем будем создавать наши
|
||||||
|
великие и не очень проекты. Делается это командой <code>yarn global add @vue/cli</code> если вы решили
|
||||||
|
использовать yarn или <code>npm install @vue/cli -g</code> если выбор пал на npm. Также имеет смысл сразу
|
||||||
|
установить пакет vue/cli-upgrade для обновления vue-cli в будущем.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
На этом установка инструментария для дальнейшей работы завершена, переходим к настройке среды разработки
|
||||||
|
и созданию нового проекта.
|
||||||
|
</p>
|
||||||
17
public/data/id202.html
Normal file
17
public/data/id202.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<h1>Подготовка среды разработки</h1>
|
||||||
|
<h2>Расширения Visual Studio Code</h2>
|
||||||
|
<p>
|
||||||
|
Если вы выбрали другой редактор кода, смело можете пропустить данную часть.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Bookmarks.</b> Позволяет создавать закладки с описаниями, что очень помогает в процессе разработки.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>GitLens.</b> Очень упрощает работу с Git непосредственно из Visual Studio.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Vue 2 Snippets.</b> Сниппеты для Vue 2.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>vuetify-vscode.</b> Сниппеты для Vuetify.
|
||||||
|
</p>
|
||||||
26
public/data/id301.html
Normal file
26
public/data/id301.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<h1>Создание проекта</h1>
|
||||||
|
<p>
|
||||||
|
Создать проект можно двумя способами: из терминала или при помощи веб-интерфейса. Рассмотрим оба способа.
|
||||||
|
<ol>
|
||||||
|
<li>Из терминала, для этого следует выполнить команду <code>vue create _название_проекта_</code></li>
|
||||||
|
<li>В веб-интерфейсе, запустив его командой <code>vue ui</code></li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
При создании проекта выберите параметры по умолчанию с установкой babel и eslint.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Каркас приложения мы создали, можно посмотреть что получилось выполнив команду <code>yarn serve</code> или
|
||||||
|
<code>npm run serve</code>. Вдоволь налюбовавшись результатом, добавим к проекту библиотеку интерфейса
|
||||||
|
Vuetify, выполнив команду <code>vue add vuetify</code>. Установщик задаст вам единственный вопрос - какие
|
||||||
|
предустановки вы хотите выбрать (Choose a preset), нас устроит набо по умолчанию (default).
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
запустив <code>yarn serve</code> сейчас, вы увидите, что внешний вид нашего приложения несколько изменился,
|
||||||
|
в нём появились компоненты библиотеки Vuetify. Этот вариант мы и возьмём за основу нашего приложения.
|
||||||
|
</p>
|
||||||
|
<h2>Клонирование проекта</h2>
|
||||||
|
<p>
|
||||||
|
Текущую версию проекта можно также получить с Git, для этого создайте каталог проекта, перейдите в него
|
||||||
|
и клонируйте командой <code>git clone https://home.cainet.info:3000/cai/VueJS/</code>.
|
||||||
|
</p>
|
||||||
237
public/data/id302.html
Normal file
237
public/data/id302.html
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
<h1>Создание компонента оглавления</h1>
|
||||||
|
<p>
|
||||||
|
Первое что мы сделаем в нашем проекте - это компопнент оглавления с поиском главы, тот что вы видите сейчас слева
|
||||||
|
от данного текста. Но сначала удалим всё ненужное из сгенерированного на предыдущем шаге шаблона.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
А ненужное - это компонент HelloWorld и все ссылки на него. Смело удаляйте файл HelloWorld.vue из каталога
|
||||||
|
<code>src/components/</code>, а файл App.vue приведите к следующему виду:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<template>
|
||||||
|
<v-app>
|
||||||
|
<v-toolbar app>
|
||||||
|
<v-toolbar-title class="headline text-uppercase">
|
||||||
|
<span>Vue.js:</span>
|
||||||
|
<span class="font-weight-light">Самоучитель</span>
|
||||||
|
</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
flat
|
||||||
|
href="https://github.com/vuetifyjs/vuetify/releases/latest"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span class="mr-2">Актуальная версия</span>
|
||||||
|
</v-btn>
|
||||||
|
</v-toolbar>
|
||||||
|
|
||||||
|
<v-content>
|
||||||
|
</v-content>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Vuetify неплохо документирован и имеет множество примеров, одним из них мы и воспользуемся при создании компонента
|
||||||
|
оглавления. За основу возьмём один из примеров со страницы
|
||||||
|
<a href="https://next.vuetifyjs.com/ru/components/treeview" target="blank">https://next.vuetifyjs.com/ru/components/treeview</a> и
|
||||||
|
приведём его к следующему виду:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<template>
|
||||||
|
<v-card class="mx-auto">
|
||||||
|
<v-sheet class="pa-3 primary lighten-2">
|
||||||
|
<v-text-field
|
||||||
|
v-model="search"
|
||||||
|
label="Поиск по названию главы"
|
||||||
|
dark
|
||||||
|
flat
|
||||||
|
solo-inverted
|
||||||
|
hide-details
|
||||||
|
clearable
|
||||||
|
clear-icon="mdi-close-circle-outline"
|
||||||
|
>
|
||||||
|
</v-text-field>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="caseSensitive"
|
||||||
|
dark
|
||||||
|
hide-details
|
||||||
|
label="С учётом регистра"
|
||||||
|
>
|
||||||
|
</v-checkbox>
|
||||||
|
</v-sheet>
|
||||||
|
<v-card-text>
|
||||||
|
<v-treeview
|
||||||
|
:active.sync="active"
|
||||||
|
:filter="filter"
|
||||||
|
:items="items"
|
||||||
|
:open.sync="open"
|
||||||
|
:search="search"
|
||||||
|
activatable
|
||||||
|
active-class="primary--text"
|
||||||
|
open-on-click
|
||||||
|
>
|
||||||
|
<template v-slot:prepend="{ item }">
|
||||||
|
<v-icon
|
||||||
|
v-if="item.children"
|
||||||
|
v-text="`mdi-${item.id === 1 ? 'home-variant' : 'folder-network'}`"
|
||||||
|
>
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
active: [],
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Введение"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Подготовка среды разработки",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": 201,
|
||||||
|
"name": "Программное обеспечение"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
open: [1],
|
||||||
|
search: null,
|
||||||
|
caseSensitive: false
|
||||||
|
}),
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
filter () {
|
||||||
|
return this.caseSensitive
|
||||||
|
? (item, search, textKey) => item[textKey].indexOf(search) > -1
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Компонент готов, но если вы запустите приложение на исполнение, то никаких изменений не увидите, ведь мы не
|
||||||
|
добавили его в само приложение. Этим сейчас и займёмся. Откройте файл App.vue и в блок <code><v-content>
|
||||||
|
</v-content></code> добавьте наш компонент <code><TOC/></code>. Уже запустили просмотр? Ну и как?
|
||||||
|
Ничего нового? А всё потому, что мы не импортировали его в приложение, срочно исправляем это досадное
|
||||||
|
недоразумение добавлением в блок <code><script></script></code> строки
|
||||||
|
<code>import TOC from './components/TOC'</code> и чуть ниже в <code>components: {},</code> строку
|
||||||
|
<code>TOC</code>. В итоге App.vue должен выглядеть следующим образом:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<template>
|
||||||
|
<v-app>
|
||||||
|
<v-toolbar app>
|
||||||
|
<v-toolbar-title class="headline text-uppercase">
|
||||||
|
<span>Vue.js:</span>
|
||||||
|
<span class="font-weight-light">Самоучитель</span>
|
||||||
|
</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
flat
|
||||||
|
href="https://github.com/vuetifyjs/vuetify/releases/latest"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span class="mr-2">Актуальная версия</span>
|
||||||
|
</v-btn>
|
||||||
|
</v-toolbar>
|
||||||
|
|
||||||
|
<v-content>
|
||||||
|
<TOC/>
|
||||||
|
</v-content>
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TOC from './components/TOC'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
TOC
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Запустили? Круто же? =) Идём дальше.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Нам надо чтобы оглавление было во всю ширину экрана только на смартфонах, на компьютере это выглядит как минимум
|
||||||
|
странно, изменим разметку в файле App.vue, создадим одну колонку шириной 4 для оглавления и одну шириной 8 для
|
||||||
|
текста. Про двенадцатиточечную систему сеток Vutify можно прочитать тут:
|
||||||
|
<a href="https://vuetifyjs.com/ru/framework/grid" target="_blank">https://vuetifyjs.com/ru/framework/grid</a>.
|
||||||
|
Приведём блок <v-content></v-content> к следующему виду:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<v-content>
|
||||||
|
<v-container fluid fill-height grid-list-md>
|
||||||
|
<v-layout row wrap full-height>
|
||||||
|
<v-flex sm4>
|
||||||
|
<TOC/>
|
||||||
|
</v-flex>
|
||||||
|
<v-flex sm8 v-html="text"></v-flex>
|
||||||
|
</v-layout>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
В блок <code>data()</code> добавьте строку <code>text: ""</code> так как выше, в строке
|
||||||
|
<code><v-flex sm8 v-html="text"></v-flex></code> мы директивой <code>v-html="text"</code> указали Vue, что
|
||||||
|
оон должен в качестве содержимого блока брать значение свойства text, и если мы его не добавим в объект нашего
|
||||||
|
приложения, то Vue будет ругаться нехорошими словами.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Готово! Почти идеально... Почему почти? Попробуйте уменьшить размер окна браузера и на определённом этапе буквы
|
||||||
|
вылезут за пределы блока меню... Непорядок! К счастью, исправить сиё недоразумение несложно, просто добавьте в
|
||||||
|
наш компонент (TOC.vue) блок стилей:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<style>
|
||||||
|
.v-treeview-node__content, .v-treeview-node__label {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.v-treeview-node__root {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Отлично! Теперь всё выглядит как надо и можно переходить к следующему шагу.
|
||||||
|
</p>
|
||||||
126
public/data/id303.html
Normal file
126
public/data/id303.html
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<h1>Загрузка данных</h1>
|
||||||
|
<p>
|
||||||
|
В созданном нами компоненте есть один ощутимый недостаток - данные в нём зашиты намертво и чтобы добавить
|
||||||
|
новую главу, придётся перекомпилировать всё приложение, а так дела не делаются. Сейчас мы добавим возможность
|
||||||
|
хранения данных во внешних файлах и будем загружать их по мере надобности.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Для начала нам понадобится Axios (<a href="https://yarnpkg.com/ru/package/axios" target="_blank">
|
||||||
|
https://yarnpkg.com/ru/package/axios</a>), именно с его помощью мы будем загружать наши json и html файлы.
|
||||||
|
Установим его командой <code>yarn add axios vue-axios</code>, после чего добавим в main.js строки для его
|
||||||
|
подключения. Выглядеть он у вас должен следующим образом:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Axios from 'axios'
|
||||||
|
import VueAxios from 'vue-axios'
|
||||||
|
import './plugins/vuetify'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
Vue.use(VueAxios, Axios)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app')
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Вот теперь можно взяться за загрузку внешних данных. Для начала уберём из нашего компонента (TOC.vue) все данные
|
||||||
|
о разделах, для этого строку items в блоке data приведём к виду <code>items: []</code>, после чего перейдём к
|
||||||
|
App.vue и в секцию export добавим <code>mounted () {}</code>. Здесь мы в дальнейшем добавим код, исполняемый при
|
||||||
|
запуске нашего приложения. Блок <code><script></script></code> должен выглядеть следующим образом:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<script>
|
||||||
|
import TOC from './components/TOC'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
TOC
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Помимо этого нам надо немного изменить тег нашего оглавления, добавить в него <code>ref="TOC"</code>, после
|
||||||
|
чего выглядеть он должен следующим образом: <code><TOC ref="TOC"/></code>. Нужно нам это для того чтобы
|
||||||
|
мы могли обращаться к конкретному экземпляру созданного нами компонента.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Итак, добавим в секцию <code>mounted</code> код загрузки оглавления:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
mounted () {
|
||||||
|
this.axios.get("data/toc.json")
|
||||||
|
.then(response => {
|
||||||
|
this.$refs.TOC.items = response.data;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Готово! Всё работает, убедиться в этом можете открыв консоль браузера и обнаружив там ошибку "Request failed with
|
||||||
|
status code 404". Чтобы от неё избавиться, создайте в каталоге public/data файл toc.json и заполните его данными
|
||||||
|
о разделах. Готовый файл можно получить по ссылке <a href="../data/toc.json" target="_blank">/data/toc.json</a>
|
||||||
|
и сохранить его в <code>public/data/toc.json</code>. После этого оглавление будет загружаться из него.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Оглавление у нас есть, осталось реализовать загрузку статей. Для того чтобы сделать это, погрузимся немного в
|
||||||
|
принципы работы нашего компонента. Каждый раз при выборе элемента, у компонента изменяется свойство active и
|
||||||
|
нам надо отслеживать его изменение в App.vue. Для этого добавим в mounted файла App.vue следующий код:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
this.$watch(
|
||||||
|
"$refs.TOC.active",
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
if (newVal.length) {
|
||||||
|
this.axios.get("data/id" + newVal + ".html")
|
||||||
|
.then(response => {
|
||||||
|
this.text = response.data;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Остаётся только создать файлы с содержимым статей. Вы можете скачать их из git или по следующим ссылкам:
|
||||||
|
<ul>
|
||||||
|
<li><a href="../data/id1.html" target="_blank">/data/id1.html</a></li>
|
||||||
|
<li><a href="../data/id201.html" target="_blank">/data/id201.html</a></li>
|
||||||
|
<li><a href="../data/id202.html" target="_blank">/data/id202.html</a></li>
|
||||||
|
<li><a href="../data/id301.html" target="_blank">/data/id301.html</a></li>
|
||||||
|
<li><a href="../data/id302.html" target="_blank">/data/id302.html</a></li>
|
||||||
|
<li><a href="../data/id303.html" target="_blank">/data/id303.html</a></li>
|
||||||
|
</ul>
|
||||||
|
Разместите данные файлы в public/data/. Теперь приложение выполняет все свои основные задачи.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
А теперь попробуйте самостоятельно добавить при старте приложения загрузку и отображение информации о нём.
|
||||||
|
Файл с информацией можно взять на git или по следующей ссылке:
|
||||||
|
<a href="../data/start.html" target="_blank">/data/start.html</a>.
|
||||||
|
</p>
|
||||||
207
public/data/id304.html
Normal file
207
public/data/id304.html
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<h1>Добавление диалогов</h1>
|
||||||
|
<h2>Диалог с сообщением</h2>
|
||||||
|
<p>
|
||||||
|
Некоторые ссылки в нашем приложении пока ведут в никуда и единственная реакция на щелчок по ним - это сообщение
|
||||||
|
в консоли, что не особо информативно, исправим этот недочёт. Создадим новый компонент MessageDialog.vue и, не
|
||||||
|
изобретая велосипедов, возьмём готовое решение для модального диалога из документации к Vuetify:
|
||||||
|
<a href="https://vuetifyjs.com/ru/components/dialogs" target="_blank">https://vuetifyjs.com/ru/components/dialogs</a>,
|
||||||
|
немного его модифицировав:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<template>
|
||||||
|
<v-layout row justify-center>
|
||||||
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
persistent
|
||||||
|
max-width="290"
|
||||||
|
>
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="headline">{{ title }}</v-card-title>
|
||||||
|
<v-card-text>{{ text }}</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="green darken-1" flat @click="dialog = false">Ok</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</v-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dialog: false,
|
||||||
|
title: "",
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Подключите диалог, добавив в блок <code><script></script></code> файла App.vue строку
|
||||||
|
<code>import MessageDialog from './components/MessageDialog'</code> и ниже в <code>components: {}</code>
|
||||||
|
строку <code>MessageDialog</code>. Начало блока <code><sctipt></script></code> должно выглядеть следующим
|
||||||
|
образом:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<script>
|
||||||
|
import MessageDialog from './components/MessageDialog'
|
||||||
|
import TOC from './components/TOC'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
MessageDialog,
|
||||||
|
TOC
|
||||||
|
},
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
В конец блока <code><v-app></v-app></code> добавьте строку
|
||||||
|
<code><MessageDialog ref="MessageDialog" /></code>, после чего останется только в коде скрипта добавить
|
||||||
|
в секции .catch каждого обращения к Axios строки вызова нашего диалога с сообщением об ошибке:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
Теперь все ошибки при загрузке файлов будут показаны пользователю.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Диалог с индикатором загрузки</h2>
|
||||||
|
<p>
|
||||||
|
При медленном соединении наше приложение будет загружать данные молча, ни коим образом не оповещая пользователя о
|
||||||
|
том, что оно работает, это нехорошо, давайте выводить при загрузке индикатор. Создадим компонент LoadingDialog.vue
|
||||||
|
как всегда воспользовавшись шаблоном vuetify:
|
||||||
|
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
<template>
|
||||||
|
<div class="text-xs-center">
|
||||||
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
hide-overlay
|
||||||
|
persistent
|
||||||
|
width="300"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
color="primary"
|
||||||
|
dark
|
||||||
|
>
|
||||||
|
<v-card-text>
|
||||||
|
Загружаю данные, ожидайте...
|
||||||
|
<v-progress-linear
|
||||||
|
indeterminate
|
||||||
|
color="white"
|
||||||
|
class="mb-0"
|
||||||
|
>
|
||||||
|
</v-progress-linear>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dialog: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
dialog (val) {
|
||||||
|
if (!val) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Предлагаю вам самостоятельно подключить его в App.vue, добавив нужные строки в блоки шаблона и скрипта. В шаблоне
|
||||||
|
значение ref установите равным "LoadingDialog".
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Справились? Теперь добавим код для отображения и скрытия диалога при загрузке файла в секцию mounted:
|
||||||
|
<div class="grey lighten-2" style="overflow-x: auto; border-radius: 5px;">
|
||||||
|
<pre>
|
||||||
|
mounted () {
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
|
||||||
|
this.axios.get("data/start.html")
|
||||||
|
.then(response => {
|
||||||
|
this.text = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
|
||||||
|
this.axios.get("data/toc.json")
|
||||||
|
.then(response => {
|
||||||
|
this.$refs.TOC.items = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$watch(
|
||||||
|
"$refs.TOC.active",
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
if (newVal.length) {
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
this.axios.get("data/id" + newVal + ".html")
|
||||||
|
.then(response => {
|
||||||
|
this.text = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Всё, теперь во время загрузки данных мы будем видеть сообщение с бегунком.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
P.S. Текст данной части можно взять тут: <a href="../data/id304.html" target="_blank">/data/id304.html</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
P.P.S. Финальную версию можно скомпилировать командой <code>yarn build</code>.
|
||||||
|
</p>
|
||||||
7
public/data/start.html
Normal file
7
public/data/start.html
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<div class="text-xs-center">
|
||||||
|
<img src="../img/logo.png" alt="Логотип Vue.js">
|
||||||
|
<h1>Самоучитель Vue.js</h1>
|
||||||
|
<h2>© Александр Чебыкин, 2019</h2>
|
||||||
|
<h3>Опубликовано под лицензией <a href="https://opensource.org/licenses/MIT">MIT</a></h3>
|
||||||
|
Git: <a href="https://home.cainet.info:3000/cai/VueJS/" target="_blank">https://home.cainet.info:3000/cai/VueJS/</a>
|
||||||
|
</div>
|
||||||
52
public/data/toc.json
Normal file
52
public/data/toc.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Введение"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "Подготовка среды разработки",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": 201,
|
||||||
|
"name": "Программное обеспечение"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 202,
|
||||||
|
"name": "Расширения Visual Studio Code"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "Разработка",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": 301,
|
||||||
|
"name": "Шаг 1. Создание проекта"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 302,
|
||||||
|
"name": "Шаг 2. Создание компонента оглавления"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 303,
|
||||||
|
"name": "Шаг 3. Загрузка данных"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 304,
|
||||||
|
"name": "Шаг 4. Добавление диалогов"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 99,
|
||||||
|
"name": "Дополнительная информация",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": 9901,
|
||||||
|
"name": "Команды npm, yarn, vue-cli"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
public/img/img301.png
Normal file
BIN
public/img/img301.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
BIN
public/img/logo.png
Normal file
BIN
public/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
19
public/index.html
Normal file
19
public/index.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title>Самоучитель Vue.js</title>
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>
|
||||||
|
<strong>Извините, но самоучитель не работает без JavaScript. Включите его для продолжения.</strong>
|
||||||
|
</noscript>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
117
src/App.vue
Normal file
117
src/App.vue
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<template>
|
||||||
|
<v-app :dark="dark">
|
||||||
|
<v-toolbar app>
|
||||||
|
<v-toolbar-title class="headline text-uppercase">
|
||||||
|
<span>Vue.js:</span>
|
||||||
|
<span class="font-weight-light">Самоучитель</span>
|
||||||
|
</v-toolbar-title>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn
|
||||||
|
flat
|
||||||
|
href="https://home.cainet.info:3000/cai/VueJS/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span class="mr-2">Актуальная версия</span>
|
||||||
|
</v-btn>
|
||||||
|
</v-toolbar>
|
||||||
|
|
||||||
|
<v-content>
|
||||||
|
<v-container fluid fill-height grid-list-md>
|
||||||
|
<v-layout row wrap full-height>
|
||||||
|
<v-flex sm4>
|
||||||
|
<TOC ref="TOC" />
|
||||||
|
</v-flex>
|
||||||
|
<v-flex sm8 v-html="text"></v-flex>
|
||||||
|
</v-layout>
|
||||||
|
</v-container>
|
||||||
|
</v-content>
|
||||||
|
<LoadingDialog ref="LoadingDialog" />
|
||||||
|
<MessageDialog ref="MessageDialog" />
|
||||||
|
</v-app>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LoadingDialog from './components/LoadingDialog'
|
||||||
|
import MessageDialog from './components/MessageDialog'
|
||||||
|
import TOC from './components/TOC'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
|
||||||
|
components: {
|
||||||
|
LoadingDialog,
|
||||||
|
MessageDialog,
|
||||||
|
TOC
|
||||||
|
},
|
||||||
|
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dark: false,
|
||||||
|
docId: 0,
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
/*
|
||||||
|
fetch("data/toc.json")
|
||||||
|
.then(res => res.json()
|
||||||
|
.then(data => this.$refs.TOC.items = data))
|
||||||
|
.catch(err => alert(err));
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.axios.get("data/start.html")
|
||||||
|
.then(response => {
|
||||||
|
this.text = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
|
||||||
|
this.axios.get("data/toc.json")
|
||||||
|
.then(response => {
|
||||||
|
this.$refs.TOC.items = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$watch(
|
||||||
|
"$refs.TOC.active",
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
if (newVal.length) {
|
||||||
|
this.$refs.LoadingDialog.dialog = true;
|
||||||
|
this.axios.get("data/id" + newVal + ".html")
|
||||||
|
.then(response => {
|
||||||
|
this.text = response.data;
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.$refs.LoadingDialog.dialog = false;
|
||||||
|
console.log(error);
|
||||||
|
this.$refs.MessageDialog.title = "Ошибка";
|
||||||
|
this.$refs.MessageDialog.text = error;
|
||||||
|
this.$refs.MessageDialog.dialog = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
1
src/assets/logo.svg
Normal file
1
src/assets/logo.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>
|
||||||
|
After Width: | Height: | Size: 539 B |
41
src/components/LoadingDialog.vue
Normal file
41
src/components/LoadingDialog.vue
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div class="text-xs-center">
|
||||||
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
hide-overlay
|
||||||
|
persistent
|
||||||
|
width="300"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
color="primary"
|
||||||
|
dark
|
||||||
|
>
|
||||||
|
<v-card-text>
|
||||||
|
Загружаю данные, ожидайте...
|
||||||
|
<v-progress-linear
|
||||||
|
indeterminate
|
||||||
|
color="white"
|
||||||
|
class="mb-0"
|
||||||
|
>
|
||||||
|
</v-progress-linear>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dialog: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
dialog (val) {
|
||||||
|
if (!val) return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
30
src/components/MessageDialog.vue
Normal file
30
src/components/MessageDialog.vue
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<template>
|
||||||
|
<v-layout row justify-center>
|
||||||
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
persistent
|
||||||
|
max-width="290"
|
||||||
|
>
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="headline">{{ title }}</v-card-title>
|
||||||
|
<v-card-text>{{ text }}</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="green darken-1" flat @click="dialog = false">Ok</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</v-layout>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
dialog: false,
|
||||||
|
title: "",
|
||||||
|
text: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
92
src/components/TOC.vue
Normal file
92
src/components/TOC.vue
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<template>
|
||||||
|
<v-card class="mx-auto">
|
||||||
|
<v-sheet class="pa-3 primary lighten-2">
|
||||||
|
<v-text-field
|
||||||
|
v-model="search"
|
||||||
|
label="Поиск по названию главы"
|
||||||
|
dark
|
||||||
|
flat
|
||||||
|
solo-inverted
|
||||||
|
hide-details
|
||||||
|
clearable
|
||||||
|
clear-icon="mdi-close-circle-outline"
|
||||||
|
>
|
||||||
|
</v-text-field>
|
||||||
|
<v-checkbox
|
||||||
|
v-model="caseSensitive"
|
||||||
|
dark
|
||||||
|
hide-details
|
||||||
|
label="С учётом регистра"
|
||||||
|
>
|
||||||
|
</v-checkbox>
|
||||||
|
</v-sheet>
|
||||||
|
<v-card-text>
|
||||||
|
<v-treeview
|
||||||
|
:active.sync="active"
|
||||||
|
:filter="filter"
|
||||||
|
:items="items"
|
||||||
|
:open.sync="open"
|
||||||
|
:search="search"
|
||||||
|
activatable
|
||||||
|
active-class="primary--text"
|
||||||
|
open-on-click
|
||||||
|
>
|
||||||
|
<template v-slot:prepend="{ item }">
|
||||||
|
<v-icon
|
||||||
|
v-if="item.children"
|
||||||
|
v-text="`mdi-${item.id === 1 ? 'home-variant' : 'folder-network'}`"
|
||||||
|
>
|
||||||
|
</v-icon>
|
||||||
|
</template>
|
||||||
|
</v-treeview>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
active: [],
|
||||||
|
items: [],
|
||||||
|
open: [1],
|
||||||
|
search: null,
|
||||||
|
caseSensitive: false
|
||||||
|
}),
|
||||||
|
|
||||||
|
mounted () {
|
||||||
|
/*
|
||||||
|
fetch("data/toc.json")
|
||||||
|
.then(res => res.json()
|
||||||
|
.then(data => this.items = data))
|
||||||
|
.catch(err => alert(err));
|
||||||
|
*/
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
filter () {
|
||||||
|
return this.caseSensitive
|
||||||
|
? (item, search, textKey) => item[textKey].indexOf(search) > -1
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
active (val) {
|
||||||
|
//if (val.length) alert("-" + val + "-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* Стили для того чтобы текст не вылезал за границы блока */
|
||||||
|
.v-treeview-node__content, .v-treeview-node__label {
|
||||||
|
flex-shrink: 1;
|
||||||
|
}
|
||||||
|
.v-treeview-node__root {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
13
src/main.js
Normal file
13
src/main.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Axios from 'axios'
|
||||||
|
import VueAxios from 'vue-axios'
|
||||||
|
import './plugins/vuetify'
|
||||||
|
import App from './App.vue'
|
||||||
|
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
Vue.use(VueAxios, Axios)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app')
|
||||||
7
src/plugins/vuetify.js
Normal file
7
src/plugins/vuetify.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
import Vuetify from 'vuetify/lib'
|
||||||
|
import 'vuetify/src/stylus/app.styl'
|
||||||
|
|
||||||
|
Vue.use(Vuetify, {
|
||||||
|
iconfont: 'md',
|
||||||
|
})
|
||||||
Loading…
x
Reference in New Issue
Block a user