【发布时间】:2019-10-01 05:59:03
【问题描述】:
我有一个页面,其中包含证券列表(子组件)的 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 中的“Key”属性都会发生变化(如上面的 Vue 调试窗口所示),这可能是原因吗?有没有办法为 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>
安全.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>
路由器.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'
}
]
}
]
})
更新:
只是为了更新这个已经有一段时间了,我终于找到了问题所在,这就是@matpie 在其他地方指出的,我发现我的 App.vue 是有 :key 的罪魁祸首添加到应用程序的最根目录:<router-view :key="$route.fullPath" /> 这是我从某个地方使用的模板,但从来不必查看它“正在工作”,删除密钥后,一切正常,标记 matpie 答案已接受。
【问题讨论】:
-
你能提供 jsfiddle 或等效的吗?
-
使用 vuex 存储当前选择的安全性,而不是使用路由器加载子组件不是更容易吗?然后,只要 vuex 存储属性发生更改,您就可以获取子数据。
-
这将如何解决在更改安全性时重新加载 ClientPortfolio 的问题?我可以 vuex 来存储证券等,但父组件仍然需要重新加载一次。另外,我在每个投资组合中都有成千上万的证券,我不认为 vuex 旨在存储如此数量的数据。
-
如果能分享更多代码就好了。您是否尝试过用
包装您的组件 -
您没有碰巧在顶级
上定义了一个 :key 吗?如果是这样,那可能就是问题
标签: vue.js vuejs2 vue-component vue-router