场景:移动端有 A、B、C 三个页面,A、B 页面路由设置了keepAlive属性,有下面两个场景:
1、A 页面 --> B 页面,B 页面刷新。
2、C 页面 --> B页面,B 页面不刷新。
一、分为以下两个情况讨论:
情况一、B 页面的代码未做组件封装,B 页面的核心代码如下:
<template><div class="demo" ref="pageWrapRef"><div v-for="item in arr" :key="item.id">{{ item.name }}</div></div>
</template><script>
export default {name: 'demo',data() {return {name: 'zhangsan',id: '1',arr: [],pageSourceName: ''};},mounted() {for (let i = 0; i < 100; i++) {this.arr.push({id: i,name: `张三${i}`});}},beforeRouteEnter(to, from, next) {next((vm) => {vm.pageSourceName = from.name;});},activated() {if (this.pageSourceName == 'A') {// 处理刷新数据的逻辑this.resetParams();this.initData();} else {// 滚动到指定位置const scrollTop = sessionStorage.getItem('scrollTop');if (scrollTop) {this.$refs.pageWrapRef.scrollTop = scrollTop;}}},beforeRouteLeave(to, from, next) {if (to.name == 'A') {sessionStorage.removeItem('scrollTop');} else {sessionStorage.setItem('scrollTop', this.$refs.pageWrapRef.scrollTop);}next();},methods: {initData() {console.log('初始化页面的接口请求');},resetParams() {this.name = 'zhangsan';this.id = '1';console.log('由于页面数据缓存了 所以要把变量重置');}}
};
</script><style scoped>
.demo {padding: 0.16rem 0;height: calc(100vh - 0.8rem);overflow-y: scroll;background-color: #fff;
}
</style>
情况二、B 页面的代码做了组件封装,比如说将 B 页面中的模块拆分成更小的业务组件,每个业务组件单独处理业务逻辑。如下图:
当 B 页面嵌套好几层组件时,这时在处理刷新跨层组件的数据时,如果使用常规的传值,传方法,会有一定的难度。
经过对各种方案的实验,选择了这种方案,B 页面的顶层组件通过 provide 属性向外暴露数顶层组件的页面数据,页面内的业务子组件通过 inject 属性接收顶层组件的数据。
页面交互如下:
二、以下分为三个部分:页面路由配置、页面代码、组件代码,如下:
1、页面路由配置:
export default [{path: '/demo/demoA',name: 'demoA',meta: { keepAlive: true },component: () => import('@/page/demo/demoA')},{path: '/demo/demoB',name: 'demoB',meta: { keepAlive: true },component: () => import('@/page/demo/demoB')},{path: '/demo/demoC',name: 'demoC',component: () => import('@/page/demo/demoC')}
];
2、三个页面的代码:
A 页面:
<template><div class="demo-a" ref="pageWrapRef">demoA 页面<divclass="item"v-for="(item, index) in list":key="index"@click="handleJump(item)">{{ item.id }}--{{ item.name }}</div></div>
</template><script>
export default {name: 'demoA',data() {return {list: []};},activated() {const scrollTop = sessionStorage.getItem('scrollTopDemoA');if (scrollTop) {this.$refs.pageWrapRef.scrollTop = scrollTop;}},beforeRouteLeave(to, from, next) {sessionStorage.setItem('scrollTopDemoA', this.$refs.pageWrapRef.scrollTop);next();},mounted() {for (let i = 0; i < 100; i++) {this.list.push({id: `${i}`,name: `demoA`});}},methods: {handleJump(item) {this.$router.push({path: '/demo/demoB',query: {id: item.id}});}}
};
</script><style scoped>
.demo-a {background-color: #fff;height: 100vh;overflow-y: scroll;
}.item {height: 44px;line-height: 44px;border-bottom: 1px #eee solid;padding: 0 15px;
}.item:nth-child(odd) {background-color: paleturquoise;
}
</style>
B 页面
<template><div class="demo-a" ref="pageWrapRef">demoB 页面<demoGrandfather /></div>
</template><script>
import demoGrandfather from './demoGrandfather.vue';export default {name: 'demoB',provide() {return {demoB: this};},components: { demoGrandfather },data() {return {needRefresh: false};},activated() {const scrollTop = sessionStorage.getItem('scrollTopDemoB');if (scrollTop) {this.$refs.pageWrapRef.scrollTop = scrollTop;}},beforeRouteEnter(to, from, next) {if (to.name == 'demoB' && from.name == 'demoA') {next((vm) => {vm.needRefresh = true;});} else {next((vm) => {vm.needRefresh = false;});}next();},beforeRouteLeave(to, from, next) {if (to.name == 'demoA') {sessionStorage.removeItem('scrollTopDemoB');} else {sessionStorage.setItem('scrollTopDemoB',this.$refs.pageWrapRef.scrollTop);}next();},methods: {}
};
</script><style scoped>
.demo-a {background-color: #fff;height: 100vh;overflow-y: scroll;
}.item {height: 44px;line-height: 44px;border-bottom: 1px #eee solid;padding: 0 15px;
}.item:nth-child(odd) {background-color: paleturquoise;
}
</style>
C 页面
<template><div class="demo-c">demoC 页面</div>
</template><script>
export default {name: 'demoC'
};
</script><style scoped>
.demo-c {
}
</style>
3、B 页面中使用到的三个组件
顶层组件,demoGrandfather.vue
<template><div class="demo-grandfather">grandfather page<DemoParent /></div>
</template><script>
import DemoParent from './demoParent.vue';export default {name: 'demoGrandfather',components: { DemoParent },data() {return {name: 'zhangsan',pageSourceName: ''};}
};
</script><style scoped>
.demo {padding: 0.16rem 0;height: calc(100vh - 0.8rem);overflow-y: scroll;background-color: #fff;
}
</style>
中间组件,demoParent.vue
<template><div class="demo-parent">parent page<DemoChildren /></div>
</template><script>
import DemoChildren from './demoChildren.vue';export default {name: 'demoParent',components: { DemoChildren },data() {return {name: 'zhangsan',id: '1',arr: [],pageSourceName: ''};},mounted() {for (let i = 0; i < 100; i++) {this.arr.push({id: i,name: `张三${i}`});}},methods: {initData() {console.log('初始化页面的接口请求');},resetParams() {this.name = 'zhangsan';this.id = '1';console.log('由于页面数据缓存了 所以要把变量重置');}}
};
</script><style scoped>
.demo {padding: 0.16rem 0;height: calc(100vh - 0.8rem);overflow-y: scroll;background-color: #fff;
}
</style>
底层组件,demoChildren.vue
<template><div class="demo-children"><!-- 隐藏域 --><div style="display: none;">{{ refresh }}</div><divclass="item"v-for="(item, index) in list":key="index"@click.stop="handleJump(item)">{{ item.id }} ----- {{ item.name }}</div></div>
</template><script>
export default {name: 'demoChildren',inject: ['demoB'],data() {return {list: [],id: '0',refreshExecuted: false // 是否已刷新,默认未刷新};},deactivated() {this.refreshExecuted = false; // 更新为未刷新状态},computed: {refresh() {if (this.demoB.needRefresh) {if (this.$route.name == 'demoB' && !this.refreshExecuted) {this.refreshExecuted = true;this.resetParams();this.initData();}}return this.demoB.needRefresh;}},methods: {initData() {console.log('初始化页面的接口请求');for (let i = 0; i < 100; i++) {this.list.push({id: `${i}`,name: `demoB`});}},resetParams() {console.log('由于页面数据缓存了 所以要把变量重置');},handleJump(item) {this.$router.push({path: '/demo/demoC',query: {id: item.id}});}}
};
</script><style scoped>
.demo-a {background-color: #fff;height: 100vh;overflow-y: scroll;
}.item {height: 44px;line-height: 44px;border-bottom: 1px #eee solid;padding: 0 15px;
}.item:nth-child(odd) {background-color: paleturquoise;
}
</style>
三、总结:
我们在接到一个需求时,往往只会针对当前的需求进行代码开发,很少有意识去进行开发前的规划工作,这就导致我们在前期开发的有多开心,后期在改动时就有多痛苦。而本次的分享也是基于最近工作中遇到的一个场景,这个问题的出现,让我逐渐意识到规划的重要性,规划就是凡事谋定而后动,前期规划的越多,后期在进行迭代时,限制条件就会越少。