Создание компонента оглавления

Первое что мы сделаем в нашем проекте - это компопнент оглавления с поиском главы, тот что вы видите сейчас слева от данного текста. Но сначала удалим всё ненужное из сгенерированного на предыдущем шаге шаблона.

А ненужное - это компонент HelloWorld и все ссылки на него. Смело удаляйте файл HelloWorld.vue из каталога src/components/, а файл App.vue приведите к следующему виду:

<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">Актуальная версия
            </v-btn>
        </v-toolbar>

        <v-content>
        </v-content>
    </v-app>
</template>

<script>
    export default {
        name: 'App',
        components: {
        },
        data () {
            return {
            }
        }
    }
</script>
        

Vuetify неплохо документирован и имеет множество примеров, одним из них мы и воспользуемся при создании компонента оглавления. За основу возьмём один из примеров со страницы https://next.vuetifyjs.com/ru/components/treeview и приведём его к следующему виду:

<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>
        

Компонент готов, но если вы запустите приложение на исполнение, то никаких изменений не увидите, ведь мы не добавили его в само приложение. Этим сейчас и займёмся. Откройте файл App.vue и в блок <v-content> </v-content> добавьте наш компонент <TOC/>. Уже запустили просмотр? Ну и как? Ничего нового? А всё потому, что мы не импортировали его в приложение, срочно исправляем это досадное недоразумение добавлением в блок <script></script> строки import TOC from './components/TOC' и чуть ниже в components: {}, строку TOC. В итоге App.vue должен выглядеть следующим образом:

<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">Актуальная версия
            </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>
        

Запустили? Круто же? =) Идём дальше.

Нам надо чтобы оглавление было во всю ширину экрана только на смартфонах, на компьютере это выглядит как минимум странно, изменим разметку в файле App.vue, создадим одну колонку шириной 4 для оглавления и одну шириной 8 для текста. Про двенадцатиточечную систему сеток Vutify можно прочитать тут: https://vuetifyjs.com/ru/framework/grid. Приведём блок <v-content></v-content> к следующему виду:

<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>
    

В блок data() добавьте строку text: "" так как выше, в строке <v-flex sm8 v-html="text"></v-flex> мы директивой v-html="text" указали Vue, что оон должен в качестве содержимого блока брать значение свойства text, и если мы его не добавим в объект нашего приложения, то Vue будет ругаться нехорошими словами.

Готово! Почти идеально... Почему почти? Попробуйте уменьшить размер окна браузера и на определённом этапе буквы вылезут за пределы блока меню... Непорядок! К счастью, исправить сиё недоразумение несложно, просто добавьте в наш компонент (TOC.vue) блок стилей:

<style>
    .v-treeview-node__content, .v-treeview-node__label {
        flex-shrink: 1;
    }
    .v-treeview-node__root {
        height: auto;
    }
</style>
        

Отлично! Теперь всё выглядит как надо и можно переходить к следующему шагу.