问题描述
我在基于Vue全家桶的单页项目中使用了IView, 页面类似于一个监控页面,当点击不同的图标的时候需要在一个模态框内(Modal)内展示不同的内容,所以我考虑将监控一面作为一个路由,这里命名为路由 A,并且在 A 路由下添加一个子路由,这里命名为路由 B,且 B 为一个命名路由,本想 A 组件在 mounted 之后直接跳转到子组件,利用命名路由动态控制页面的模态框展示,但是第一次控制模态框展示成功了,第二次却无效!!!
项目中的各种依赖信息
- 下面是 package.json 配置类容
{
"name": "test4",
"version": "1.0.0",
"description": "webpack test",
"main": "webpack.config.js",
"scripts": {
"dev": "webpack-dev-server --config config.js --content-base dist/ --port 8080 --color --hot --inline ",
"build": "webpack --config config.js --progress --display-modules --display-reasons --colors",
"auto-build": "webpack --config config.js --progress --colors --watch"
},
"keywords": [
"webpack",
"test"
],
"author": "yangxiuchu",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-es2016": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"compression-webpack-plugin": "^1.0.1",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.1",
"file": "^0.2.2",
"file-loader": "^1.1.5",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^2.30.1",
"style-loader": "^0.19.0",
"url": "^0.11.0",
"url-loader": "^0.6.2",
"vee-validate": "^2.1.3",
"vue-loader": "^13.5.0",
"vue-router": "^3.0.1",
"vue-template-compiler": "^2.5.5",
"webpack": "^3.8.0",
"webpack-dev-server": "^2.9.2"
},
"dependencies": {
"axios": "^0.17.1",
"bootstrap": "^3.3.7",
"echarts": "^4.1.0",
"iview": "^3.1.5",
"jquery": "^3.2.1",
"moment": "^2.22.2",
"toastr": "^2.1.2",
"underscore": "^1.9.1",
"vue": "^2.5.5",
"vue-axios": "^2.0.2",
"vuex": "^3.0.1",
"ztree": "^3.5.24"
}
}
相关代码
相关代码如下:
- A 组件相关代码
<style scoped>
...
</style>
<template>
...
<!--
此处使用命名路由,当前跳转到子路由的时候,此视图会根据 currentView 的名字渲染,
未了强制刷新 <router-view> 组件,在每次修改 currentView 的时候都修改 key 的值
未当前时间戳,即 this.key = new Date().getTime(); 具体见 detail 方法。
-->
<button @click="detail('dynamoDetail')">clike me</button>
<router-view :name="currentView" :key="key"></router-view>
</Layout>
</template>
<script>
export default {
data() {
return {
currentView : '',
key : ''
}
},
watch : {
},
created() {
},
mounted() {
// 加载完成之后直接跳转到子路由,使命名路由生效
this.$router.push({name : 'dynamic-power-systme-detail'});
},
beforeDestroy() {
},
methods: {
detail(target) {
// 更改 key, 已强制刷新 <router-view>。
this.key = new Date().getTime();
if(target !== this.currentView) {
this.currentView = target;
}
console.log('key is updated...');
}
}
}
</script>
- 相应路由定义部分
...
{
path : 'dynamic-oil-electric-system-index',
name : 'dynamic-oil-electric-system-index',
component : (resolve) => require(['./monitor/dynamicSystem/oilElectricSystem/index.vue'], resolve),
children : [
{
path : 'detail',
name : 'dynamic-oil-electric-system-detail',
components : {
'pressureGaugeDetail' : (resolve) => require(['./monitor/dynamicSystem/oilElectricSystem/pressureGaugeDetail.vue'], resolve)
}
}
]
}
...
- B 组件定义如下
<style scoped>
...
</style>
<template>
<Layout>
<Modal
:value="show"
@on-visible-change="change"
title="foo"
:styles="{width: '50%', verticalAlign: 'center', marginTop: '5%'}">
<div class="tz-table-wrapper">
<Table :columns="cols" :data="rows"></Table>
</div>
<span slot="footer">
{{new Date().getTime()}}
</span>
</Modal>
</Layout>
</template>
<script>
export default {
data() {
return {
show : true,
cols : [
{title : '编号', key : 'id'},
{title : '名称', key : 'name'},
{title : '内容', key : 'content'}
],
rows : []
}
},
created() {
console.log('dynamoDetail Component created...');
},
updated() {
console.log('dynamoDetail Component updated...');
},
mounted() {
console.log('dynamoDetail Component mounted...');
},
destroyed() {
console.log('dynamoDetail Component destoryed...');
},
methods: {
ok() {
},
cancel() {
},
change(state) {
this.show = state;
}
}
}
</script>
此组件是 A 组件的子组件,且定义为命名路由
实际情况说明
在 A 组件页面中, 点击按钮,则 B 命名路由匹配到的组件会弹出一个模态框,而实际情况也是如此,但是我关闭模态框之后,再次在 A 组件页面中点击按钮却无法弹出该模态框,打印了生命周期,输出如下:
// 第一次点击按钮之后
key is updated...
dynamoDetail Component created...
dynamoDetail Component mounted...
// 关闭模态框之后
dynamoDetail Component updated...
// 再次点击按钮之后, 这里生命周期和我了解 Vue 组件生命周期顺序不同,不知道为什么!!!???
// 这都是其次的,最重要的是这个模态框的组件不是钩子函数都触发了吗? 为什么显示不出呢?
// 而且页面上也没有实际创建 dom 元素!!!???
key is updated...
dynamoDetail Component created...
dynamoDetail Component destoryed...
dynamoDetail Component mounted...
// 再次点击和上一步是一样的结果
解决办法
- 修改组件 B 代码如下:
<style scoped>
...
</style>
<template>
<!--
套一层组件,也尝试过直接用普通的 HTML 标签,如 div, span, 都能避免上述出现的问题
而且点击按钮打印的效果是一模一样的。
-->
<Layout>
<Modal
:value="show"
@on-visible-change="change"
title="foo"
:styles="{width: '50%', verticalAlign: 'center', marginTop: '5%'}">
<div class="tz-table-wrapper">
<Table :columns="cols" :data="rows"></Table>
</div>
<span slot="footer">
{{new Date().getTime()}}
</span>
</Modal>
</Layout>
</template>
<script>
export default {
data() {
return {
show : true,
cols : [
{title : '编号', key : 'id'},
{title : '名称', key : 'name'},
{title : '内容', key : 'content'}
],
rows : []
}
},
created() {
console.log('dynamoDetail Component created...');
},
updated() {
console.log('dynamoDetail Component updated...');
},
mounted() {
console.log('dynamoDetail Component mounted...');
},
destroyed() {
console.log('dynamoDetail Component destoryed...');
},
methods: {
ok() {
},
cancel() {
},
change(state) {
this.show = state;
}
}
}
</script>
疑问
1、Vue 组件正常的生命周期是 brforeCreaded -> created -> mounted -> [beforeUpdated -> updated] -> beforeDestoryed -> destoryed, 而上述问题中为什么会出现 created -> destoryed -> updated 的顺序,而且在解决方案中调用的顺序也是如此?
2、为什么会出现上述的问题,而用上述的解决方案就能够解决呢? 是 IView Modal 组件自身的问题吗?
这是因为你加了key的原因,vue检测到key不一样就会销毁子组件,重新加载,销毁的过程中就触发了destory