场景:移动端有 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 页面
<div
class="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>
<div
class="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>
三、总结:
我们在接到一个需求时,往往只会针对当前的需求进行代码开发,很少有意识去进行开发前的规划工作,这就导致我们在前期开发的有多开心,后期在改动时就有多痛苦。而本次的分享也是基于最近工作中遇到的一个场景,这个问题的出现,让我逐渐意识到规划的重要性,规划就是凡事谋定而后动,前期规划的越多,后期在进行迭代时,限制条件就会越少。