Немного предыстории ...
Давным-давно я написал простой плагин JS, который автоматически удаляет источники изображения со страницы и предварительно загружает каждый из них перед последующим отображением содержимого страницы.т.е. показывать счетчик или индикатор выполнения, а затем показывать основное содержимое.
Однако сейчас я собираюсь добавить именно эту функциональность в мои проекты Vue с намерением разрешить каждому view
предварительно загружать каждое из изображений.в их относительных DOM.
Я пытался определить наиболее подходящую структуру для этого плагина и, наконец, нашел, как мне кажется, наиболее подходящее решение.
Моя структура и планируемая реализация
Каждый из моих проектов Vue имеет следующую иерархию компонентов:
App.vue -> {route}.vue -> {relevant components}.vue
Исходя из этого, я придумал следующую структуру:
App.vue
- Хранить локальный логический
loaded
, который определит, отображать ли содержимое (router-view
) или spinner
- Сохранить локальный массив
images
чтобы сохранить все изображения для предварительной загрузки - Определить метод
preload
, который будет проходить по циклу и предварительно загружать все изображения - Прослушать изменения
loaded
, например, когда loaded
is false
вызывает метод preload
- Прослушивание изменений в
images
- это позволит нам объединить наши очищенные изображения DOM с нашим пользовательским списком изображений, излучаемых из {route}.vue
компонентов
{route} .vue - через mixin
- Зарегистрировать
images
проп, который будет определен на маршруте и будет выдавать эти значения в App.vue
. - Зарегистрируйте
loaded
реквизит, который будет изменен на false до изменения маршрута
Мой код
Я началвнедряя это в мой код следующим образом (лишено только показывать релевантную информацию):
App.vue
<template>
<div id="app" :class="{ loading: !loaded }">
<!-- Main content loading indicator -->
<spinner v-if="!loaded"></spinner>
<!-- Main content wrapper -->
<div id="main-wrapper">
<!-- Include the main site header -->
<main-header></main-header>
<!-- Include the content of the current page -->
<router-view :loaded.sync="loaded" :images.sync="images"></router-view>
<!-- Include the main site footer -->
<main-footer></main-footer>
</div>
</div>
</template>
<script>
import Header from 'core-js/components/core/Header';
import Footer from 'core-js/components/core/Footer';
export default {
components: {
'main-header': Header,
'main-footer': Footer
},
data() {
return {
images: [],
loaded: false
}
},
mounted() {
// Trigger the preload once all components are mounted
this.$nextTick(this.preload);
},
watch:{
images(value) {
// Whenever images is updated, we should merge with the
// DOM scraped images
console.log(value);
},
loaded(value) {
// Whenever loaded is updated, we should hide and content
// and show the spinner (if it is false)
console.log(value);
}
},
methods: {
/**
* Preload all images for the active route.
*
* @return void
*/
preload() {
// Scrape the DOM and build array of images
// Then merge this array with `this.images`
// For testing purposes...
setTimeout(() => { this.loaded = true; }, 2000);
}
}
}
</script>
PreloadRoute.js (mixin)
export default {
props: {
loaded: {
type: Boolean,
required: false
},
images: {
type: Array,
required: false
}
},
beforeRouteEnter(to, from, next) {
console.log('The route is about to change');
}
};
Мой вопрос
Как видно из приведенного выше кода, это очень большой прогресс, так как я столкнулся с проблемой, которую я не совсем уверен, как
В миксине PreloadRoute.js
мне нужно сообщить App.vue
, что loaded
теперь ложно.Однако мне нужно сделать это до того, как маршрут действительно изменится.Поскольку this
недоступно в beforeRouteEnter
, я не могу передать изменения.Я не могу использовать next
, потому что он мне особенно нужен для запуска до того, как маршрут действительно изменится.
Есть ли способ передать изменение реквизита в родительский компонент до того, как дочерний компонент фактически инициализирован?
Я думал о возможном использовании отдельного экземпляра Vue в качестве шины событий, например так:
window.bus = new Vue();
Я забочусь об этом, я считаю, что это можно сделать лучше ...
Дополнительно...
Причина, по которой я включил все вышеперечисленное содержимое, а не просто вопрос относительно beforeRouteEnter
, заключается в том, что я открыт для альтернативных структурных предложений.Другими словами, если у вас есть предложения относительно более простой / альтернативной структуры, которая позволит достичь того, что я ищу, тогда, пожалуйста, во что бы то ни стало, стреляйте ...