У меня есть демонстрационное приложение, которое отображает некоторые погодные данные для некоторых городов. Я использую Vue hash router для 3 маршрутов:
/
(домашняя страница)
/weather/:id
(для подробного прогноза по конкретному месту)
/search/:term
(для поиска местоположений)
Все работает нормально, кроме маршрута /search/:term
, который необходимо обновить при изменении условия поиска, а также при переходе на предыдущую страницу поиска с помощью кнопки «Назад» браузера.
Страница поиска выглядит так (url: http://localhost/#/search/lon
):
Компонент страницы поиска:
<template>
<div :key="'search_page_'+$route.params.term" class="page page-search">
<h2 class="page-header">Search Results</h2>
<div class="search-box">
<input type="text" placeholder="search.." v-model="text" />
<button type="button" @click="handleOnClick">Search!</button>
</div>
<Loader v-if="loading" text="Loading.." />
<template v-else-if="data && data.length">
<Weather v-for="place in data" :key="'weather_for_'+place.woeid" :woeid="String(place.woeid)" :city="place.title" />
</template>
<p v-else><b>No results found!</b></p>
</div>
</template>
<script>
// @ is an alias to /src
import Loader from '@/components/Loader.vue'
import Weather from '@/components/Weather.vue'
import store from '@/modules/Store'
const API_URL = '/weather.php?keyword=';
export default {
name: 'search',
components: {
Loader, Weather
},
data: function() {
return {
loading: true,
text: this.$route.params.term ? decodeURIComponent(this.$route.params.term) : '',
data: null
};
},
methods: {
handleOnClick: function() {
this.$router.push({ name: 'search', params: { term: encodeURIComponent(this.text) } });
},
loadData: function( withText ) {
let searchData = store.get('search_'+this.$route.params.term);
if ( searchData ) {
if ( withText ) this.text = decodeURIComponent(this.$route.params.term);
this.data = searchData;
this.loading = false;
} else {
fetch(API_URL+this.$route.params.term)
.then(response => response.json())
.then(jsonResponse => {
store.set('search_'+this.$route.params.term, searchData = jsonResponse);
if ( withText ) this.text = decodeURIComponent(this.$route.params.term);
this.data = searchData;
this.loading = false;
})
.catch(error => console.log(error));
}
}
},
watch: {
'$route': function(to, from) {
if ( from.params.term !== to.params.term )
{
this.loadData(true);
}
}
},
mounted: function() {
this.loadData();
}/*,
updated: function() {
this.loadData();
}*/
}
</script>
Конфигурация маршрутизатора:
import Vue from 'vue'
import Router from 'vue-router'
import HomePage from './views/HomePage.vue'
import SearchPage from './views/SearchPage.vue'
import WeatherPage from './views/WeatherPage.vue'
Vue.use(Router)
export default new Router({
mode: 'hash',
base: '/',
routes: [
{
path: '/',
name: 'home',
component: HomePage
},
{
path: '/search/:term',
name: 'search',
component: SearchPage
},
{
path: '/weather/:woeid',
name: 'weather',
component: WeatherPage
}
]
})
Я заставил это работать (хотя страница поиска немного мигает при обновлении поискового запроса на той же странице и не так реагирует, как я ожидал), но Мне интересно, является ли это лучшим подходом, который я могу использовать или там лучше?
Например, я использую ловушки жизненного цикла для извлечения данных из API, а также использую наблюдатели на маршруте, чтобы иметь возможность реагировать на изменения поискового запроса на той же странице. Также добавлено свойство :key
на весь компонент. Но у меня сложилось впечатление, что это можно сделать проще / лучше. возможно, мне не хватает sth и / или, может быть, я делаю что-то дважды (например, я не уверен, что при первом входе на страницу поиска вызывается loadData
дважды, так как я loadData
на mounted
ловлю и на $route
изменить).
UPDATE
частично ответить 2nd
часть вопроса: loadData
метод не вызывается дважды при первом входе на страницу поиска. Либо ловушка жизненного цикла mounted
вызывается при первом входе на страницу, либо наблюдатель $route
запускается при обновлении страницы поиска изнутри самой страницы (включая кнопку возврата браузера), но не оба .