У меня есть страница, на которой ClientPortfolio (родительский компонент), содержащий список ценных бумаг (дочерний компонент), загружается в список v-data-table.
Проблема, с которой я столкнулся, заключается в том, что ClientPortfolio полностью перезагружается каждый раз, когда я щелкаю по безопасности в списке, в результате чего обновляется весь список, в результате чего прокрутка и выбранный класс сбрасываются, а также излишние потери производительности.
Я посмотрел документацию по Vue, и, кажется, ничто не указывает на то, как обновлять дочерний компонент только тогда, когда у него есть параметры, похоже, что родительский компонент обновляется при изменении маршрута каждый раз, когда выбирается защита, несмотря на то, что Vue будет знать , что изменяется только sub (вложенный маршрут), следовательно, необходимо только перезагрузить дочерний компонент
Ближайший ответ, который я получил, был объяснен на https://github.com/vuejs/vue-router/issues/230, который не объясняет в коде, как этого добиться.
routes.js:
routes: [
{
path: '/client/:clientno/portfolios/:portfolioNo',
component: ClientPortfolios,
children: [
{ path: 'security/:securityNo', component: Security }
]
},
]
Ссылка на маршрутизатор в ClientPortfolios.vue:
<router-link tag="tr" style="cursor:pointer"
:to="`/client/${$route.params.clientno}/portfolios/${selectedPortfolioSequenceNo}/security/${props.item.SecurityNo}-${props.item.SequenceNo}`"
:key="props.item.SecurityNo+props.item.SequenceNo">
</router-link>
Вид маршрутизатора (для компонента безопасности) в ClientPortfolios.vue:
<v-flex xs10 ml-2>
<v-layout>
<router-view :key="$route.fullPath"></router-view>
</v-layout>
</v-flex>
Любой совет о том, как предотвратить перезагрузку родителей, приветствуется.
РЕДАКТИРОВАТЬ: Пытаясь приблизиться к проблеме, я замечаю, что атрибут «Ключ» в ClientPortfolios изменяется (как показано в окне отладки Vue выше) всякий раз, когда я меняю Security, может ли это быть причиной? Есть ли способ назначить ключ компоненту ClientPortfolios, хотя он не является дочерним? Или способ не обновлять свой ключ при переходе на разные ценные бумаги?
ОБНОВЛЕНИЕ: Полный код
ClientPortfolios.vue
<template>
<v-layout row fill-height>
<v-flex xs2>
<v-layout column class="ma-0 pa-0 elevation-1">
<v-flex>
<v-select v-model="selectedPortfolioSequenceNo" :items="clientPortfolios" box label="Portfolio"
item-text="SequenceNo" item-value="SequenceNo" v-on:change="changePortfolio">
</v-select>
</v-flex>
<v-data-table disable-initial-sort :items="securities" item-key="Id" hide-headers hide-actions
style="overflow-y: auto;display:block;height: calc(100vh - 135px);">
<template slot="items" slot-scope="props">
<router-link tag="tr" style="cursor:pointer"
:to="{ name: 'Security', params: { securityNo: props.item.SecurityNo+'-'+props.item.SequenceNo } }"
>
</router-link>
</template>
<template v-slot:no-data>
<v-flex class="text-xs-center">
No securities found
</v-flex>
</template>
</v-data-table>
</v-layout>
</v-flex>
<v-flex xs10 ml-2>
<v-layout>
<keep-alive>
<router-view></router-view>
</keep-alive>
</v-layout>
</v-flex>
</v-layout>
</template>
<script>
import Security from '@/components/Security'
export default {
components: {
security: Security
},
data () {
return {
portfoliosLoading: false,
selectedPortfolioSequenceNo: this.$route.params.portfolioNo,
selectedPortfolio: null,
securityNo: this.$route.params.securityNo
}
},
computed: {
clientPortfolios () {
return this.$store.state.ClientPortfolios
},
securities () {
if (this.clientPortfolios == null || this.clientPortfolios.length < 1) {
return []
}
let self = this
this.selectedPortfolio = global.jQuery.grep(this.clientPortfolios, function (portfolio, i) {
return portfolio.SequenceNo === self.selectedPortfolioSequenceNo
})[0]
return this.selectedPortfolio.Securities
}
},
mounted () {
this.getClientPortfolios()
},
activated () {
},
methods: {
changePortfolio () {
this.$router.push({
path: '/client/' + this.$route.params.clientno + '/portfolios/' + this.selectedPortfolioSequenceNo
})
},
getClientPortfolios: function () {
this.portfoliosLoading = true
let self = this
this.$store.dispatch('getClientPortfolios', {
clientNo: this.$route.params.clientno
}).then(function (serverResponse) {
self.portfoliosLoading = false
})
}
}
}
</script>
Security.vue
<template>
<v-flex>
<v-layout class="screen-header">
<v-flex class="screen-title">Security Details </v-flex>
</v-layout>
<v-divider></v-divider>
<v-layout align-center justify-space-between row class="contents-placeholder" mb-3 pa-2>
<v-layout column>
<v-flex class="form-group" id="security-portfolio-selector">
<label class="screen-label">Sequence</label>
<span class="screen-value">{{security.SequenceNo}}</span>
</v-flex>
<v-flex class="form-group">
<label class="screen-label">Security</label>
<span class="screen-value">{{security.SecurityNo}}-{{security.SequenceNo}}</span>
</v-flex>
<v-flex class="form-group">
<label class="screen-label">Status</label>
<span class="screen-value-code" v-if="security.Status !== ''">{{security.Status}}</span>
</v-flex>
</v-layout>
</v-layout>
</v-flex>
</template>
<script>
export default {
props: ['securityNo'],
data () {
return {
clientNo: this.$route.params.clientno,
securityDetailsLoading: false
}
},
computed: {
security () {
return this.$store.state.SecurityDetails
}
},
created () {
if (this.securityNo.length > 1) {
this.getSecurityDetails()
}
},
methods: {
getSecurityDetails: function () {
let self = this
this.securityDetailsLoading = true
this.$store.dispatch('getSecurityDetails', {
securityNo: this.securityNo,
clientNo: this.clientNo
}).then(function (serverResponse) {
self.securityDetailsLoading = false
})
}
}
}
</script>
router.js
const router = new Router({
mode: 'history',
routes: [
{
path: '/',
component: Dashboard
},
{
path: '/client/:clientno/details',
component: Client,
props: true
},
{
path: '/client/:clientno/portfolios/:portfolioNo',
component: ClientPortfolios,
name: 'ClientPortfolios',
children: [
{ path: 'security/:securityNo',
component: Security,
name: 'Security'
}
]
}
]
})
UPDATE
Просто чтобы обновить это, как это было давно, мне наконец-то удалось выяснить, в чем проблема, о которой @matpie указал в другом месте, я обнаружил, что мой App.vue является виновником, где есть ключ: добавьте в самый корень приложения: <router-view :key="$route.fullPath" />
это был шаблон, который я использовал откуда-то, но мне никогда не приходилось смотреть, как он «работал», после удаления ключа все работает как надо, отмечая ответ Matpie принятым.