uniapp 微信小程序父级页面数据同步

uniapp 微信小程序父级页面数据同步

这篇文章开头有点难以开始,这边讲一下我业务遇到的需求,我们有一个点赞、关注功能。如果不由前端来处理简单的数据一致性,那就需要在页面 onShow 的时候来加载数据。onShow 按照微信文档的说明是 “页面显示/切入前台时触发”,即我们新打开页面或者返回页面都会调用,打开页面这个不需要讲,那返回的如果想知道数据变更了则需要重新请求后端,而且还有分页来增加请求量,在另外一个是息屏,屏幕关闭重新打开也会调用 onShow 。所以我们需要修改后可以直接本地修改有关页面的数据,不过我们业务不是很复杂,只需要处理上一页的列表数据导致一致即可。

还是首先,我们弄一个评论列表页,然后点击评论可以跳转到该详情页。

components\comment-item.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<template>
<view class="container-comment">
<view class="content" @click="handleToDetails">{{ item.content }}</view>
<view class="like" @click="handleToggleLike">{{ has_like ? '喜欢' : '不喜欢' }}</view>
</view>
</template>

<script>
export default {
props: {
item: {
type: Object,
default () {
return {};
},
},
},
data () {
return {
has_like: this.item.has_like,
}
},
methods: {
handleToggleLike () {
this.has_like = !this.has_like;
},
// 跳转详情页,如果当前已经是详情页则不需要处理
handleToDetails () {
if(this.handleHasDetailsPage()) return;

return uni.navigateTo({
url: '/pages/index/details?id=' + this.item.id,
});
},
handleHasDetailsPage () {
const page = this.$last_page();

return page.route === 'pages/index/details';
},
},
}
</script>

<style lang="scss" scoped>
.container-comment {
display: flex;
justify-content: space-between;
font-size: 24px;
}
</style>

pages\index\index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<template>
<view class="container">
<view v-if="list.length" class="list">
<comment-item v-for="item in list" :key="item.id" :item="item"></comment-item>
</view>
</view>
</template>

<script>
export default {
data() {
return {
list: [],
}
},
onLoad () {
this.handleInit();
},
methods: {
handleInit () {
return uni.request({
url: 'https://cdn.hongfs.cn/blog/uniapp-wechat-mini-program-parent-page-data-synchronization/data.json',
success: (response) => {
this.list = response.data.list;
},
});
},
},
}
</script>

pages\index\details.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<template>
<view v-if="data.id > 0" class="container">
<comment-item :item="data"></comment-item>
</view>
</template>

<script>
export default {
data () {
return {
id: -1,
data: {},
}
},
onLoad (options) {
this.id = parseInt(options.id);
this.handleInit();
},
methods: {
handleInit () {
return uni.request({
url: 'https://cdn.hongfs.cn/blog/uniapp-wechat-mini-program-parent-page-data-synchronization/data.json',
success: (response) => {
const data = response.data.list;

const index = data.findIndex(item => item.id === this.id);

if(index === -1) return;

this.data = data[index];
},
});
},
},
}
</script>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue'
import App from './App'

import comment_item from './components/comment_item.vue';

Vue.config.productionTip = false

// 获取指定页面栈的信息
Vue.prototype.$last_page = function(num = 1) {
var pages = getCurrentPages();
return pages[pages.length - num];
}

Vue.component('comment-item', comment_item);

App.mpType = 'app'

const app = new Vue({
...App
})
app.$mount()

效果,可以看到返回后没有重新读取数据是不会有任何改变的。


同步是依靠页面栈中的 $vm 来修改页面的数据。

components\comment-item.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<template>
<view class="container-comment">
<view class="content" @click="handleToDetails">{{ item.content }}</view>
<view class="like" @click="handleToggleLike">{{ has_like ? '喜欢' : '不喜欢' }}</view>
</view>
</template>

<script>
export default {
props: {
item: {
type: Object,
default () {
return {};
},
},
},
data () {
return {
has_like: this.item.has_like,
}
},
watch: {
// 监听到数据被修改则修改当前的状态
'item.has_like' (value) {
this.has_like = !!value;
},
},
methods: {
handleToggleLike () {
this.has_like = !this.has_like;

if(!this.handleHasDetailsPage()) return;

// 详情页点赞,需要进行数据同步。(详情页打开是每次都会重新读取后端数据的)
this.$comment_like_change(this.item.id, this.has_like);
},
handleToDetails () {
if(this.handleHasDetailsPage()) return;

return uni.navigateTo({
url: '/pages/index/details?id=' + this.item.id,
});
},
handleHasDetailsPage () {
const page = this.$last_page();

return page.route === 'pages/index/details';
},
},
}
</script>

<style lang="scss" scoped>
.container-comment {
display: flex;
justify-content: space-between;
font-size: 24px;
}
</style>

mian.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import Vue from 'vue'
import App from './App'

import comment_item from './components/comment-item.vue';

Vue.config.productionTip = false

Vue.prototype.$last_page = function(num = 1) {
var pages = getCurrentPages();
return pages[pages.length - num];
}

// 评论喜欢-数据同步处理
Vue.prototype.$comment_like_change = function(id, value) {
// 获取当前页面的上一页(父页)信息
const page = Vue.prototype.$last_page(2);

// 判断父页是否需要处理同步
if (['pages/index/index'].indexOf(page.route) === -1) return;

// 父页存储列表的 key
const list_key = 'list';

if (!page.$vm.hasOwnProperty(list_key)) return;

page.$vm[list_key] = page.$vm[list_key].map(item => {
if (item.id === id) {
// 列表数据 id 和当前需修改的 id 一致则对数据进行改变
item.has_like = value;
}

return item;
});
}

Vue.component('comment-item', comment_item);

App.mpType = 'app'

const app = new Vue({
...App
})
app.$mount()

最终效果。

往上