前言

若文章有误,欢迎读者留言反馈

💻Installation

1
git clone https://github.com/coding327/mymovies.git

关于页及授权登录的实现

绘制关于页面

这里wxmlwxss代码我就不做展示了,可以到about文件夹下查看

用户授权登陆

使用按钮里绑定的getUserProfile函数,用户信息拿到了将它存储到数据仓库中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 页面的初始数据
*/
data: {
userInfo: null, // 存储局部用户信息
},
getUserProfile(e) { // 获取用户信息【这个事件对象建议带上】
// 【注意wx.getUserProfile必须搭配点击事件才能使用】推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '用于完善用户个人信息',
success: res => {
// console.log(res);
this.setData({
userInfo: res.userInfo
})
app.userInfo = res.userInfo // 考虑到很多页面会使用用户信息,添加到全局实例中
}
})
},

回到about.wxml文件中展示用户信息,需要使用或运算符,只有当数据仓库中有用户信息才展示用户信息,没有显示默认的

1
2
3
4
5
6
7
8
9
<!-- 用户信息 start -->
<view class="userinfo">
<image class="user-img" src="{{ userInfo.avatarUrl || '/imgs/user.png' }}"></image>
<!-- 昵称默认没授权不显示 -->
<view wx:if="{{ userInfo }}" class="user-nickname">{{ userInfo.nickName }}</view>
<!-- plain镂空 -->
<button wx:else class="login" plain bindtap="getUserProfile">点击授权登陆</button>
</view>
<!-- 用户信息 end -->

需要注意一个问题,如果授权登陆了,数据是会存储到本地缓存中的,但是下次再进来还要再点一下按钮才能显示用户头像和昵称?
【原先的getUserInfo解决方案】
也就是说当小程序启动时就要尝试去获取本地缓存中的用户信息,如果用户已经授权过了,用户进入about页面就要直接展示用户头像和昵称,小程序启动是在app.js,进入app.js文件中,启动时获取到的用户信息,咱们需要把这个用户信息定义为全局的,全局存储这个用户信息,然后再到about.js文件中,当about页面加载时,判断全局用户信息有没有,如果有就获取并放到about里的局部用户信息中,注意需要获取全局实例app才能拿到用户信息;考虑到用户信息很多页面可能会用到,所以添加到全局实例中,需要注意一个问题,小程序启动过程中有个获取用户信息,而获取用户信息是个异步的过程,可能出现关于页面还拿着全局用户信息null直接加载完了页面,显然这是小程序和页面加载时机的问题,解决方法就是给全局实例绑定回调,然后判断有没有这个callback,如果有就调用并把结果作为实参传递进去。

【目前直接用同步缓存wx.setStorageSyncwx.getStorageSync方法】

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
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let userInfo = wx.getStorageSync('userInfo') // 从本地存储中获取用户信息
this.setData({
userInfo
})
},
getUserProfile(e) { // 获取用户信息【这个事件对象可传可不传】
// 【注意wx.getUserProfile必须搭配点击事件才能使用】推荐使用 wx.getUserProfile 获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认
// 开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
wx.getUserProfile({
desc: '用于完善用户个人信息',
success: res => {
// console.log(res);
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
})
app.userInfo = res.userInfo // 考虑到很多页面会使用用户信息,添加到全局实例中
wx.setStorageSync('userInfo', res.userInfo) // 将用户信息保存到本地存储中
}
})
},

添加收藏到本地缓存

当我们到详情页点击收藏了,关于页面需要展示出来,我们可以使用小程序里的缓存,把数据存到本地缓存中,这样就可以实现多页面之间数据的共享
先到about页面,定义一个收藏电影信息的属性,考虑到每个电影有个唯一id,方便删除操作,这里定义为对象比较合适

1
2
3
4
5
6
7
/**
* 页面的初始数据
*/
data: {
userInfo: null, // 存储局部用户信息
favorites: {}, // 存储收藏的电影信息
},

进入about.wxml展示页面,直接遍历这个收藏电影对象,如果为空就显示不会收藏电影,从而显示下面暂无收藏,当有电影时得让暂无收藏消失,这时可以使用一个变量,最开始默认是没有收藏的,设置为true,让它显示暂无收藏【这个开关的控制阀门在哪后面再处理】

1
2
3
4
5
data: {
userInfo: null, // 存储局部用户信息
favorites: {}, // 存储收藏的电影信息
showNoFavorite: true, // 是否显示暂无收藏
},

详情页面点击收藏有个前提条件,必须是登陆了的用户才能点击收藏,进入detail.wxml,找到收藏按钮,给它绑定一个事件addFavorite,进入detail.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
// 添加收藏
addFavorite() {
// 如果用户没有登陆,给一个提示,让用户先登陆了才能收藏
let userInfo = wx.getStorageSync('userInfo')
// 判断用户是否登陆
if (!userInfo) {
wx.showModal({
title: '提示',
content: '请先登陆'
})
return // 终止掉函数
}
// 已经登陆,添加电影到本地缓存,如果取不到【首次】就是空字符串,而我们favorite设计的是对象,处理一下即可
// 获取本地缓存中收藏的电影
var favorites = wx.getStorageSync('favorites') || {}
// 判断是否已收藏
if (favorites[this.data.filmId]) {
wx.showToast({
title: '已收藏',
image: '/imgs/error.png'
})
return
}
// 添加电影到本地缓存
favorites[this.data.filmId] = this.data.film
// 存到缓存中【下方控制台Storage可以查看有没有存进去】
wx.setStorageSync('favorites', favorites)
// 收藏成功提示
wx.showToast({
title: '收藏成功',
image: '/imgs/success.png'
})
},

展示本地缓存中收藏的电影

进入about.js文件中,这里考虑一个问题,是在onload中获取本地缓存中收藏的电影吗?
首先我们得知道onload只执行一次,这个所谓得一次会造成,当我们从首页进入关于页面这个onload执行了一次,但是这个时候我又回到详情页收藏了一部电影,本地缓存数据变了,再进关于页面你这个onload不会再执行了,那你刚刚新收藏的电影也就无法获取展示出来。
为了解决这个问题,我们应该使用onshow这个生命周期,从其它页面切换到这个页面它都会执行

1
2
3
4
5
6
7
8
9
onShow: function () {
// 从本地缓存中把收藏电影取出来
let favorites = wx.getStorageSync('favorites')
// 要在页面上使用,需要放到数据仓库中
this.setData({
favorites,
showNoFavorite: Object.keys(favorites) == 0 // 当收藏为空时显示【需要拿到最新的收藏电影来做这个判断,所以开关阀门在这里】
})
},

页面上展示,由于遍历favorites对象,需要把每个值也就是单个电影对象往film-item传,直接传递item即可

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 我的收藏 start -->
<view class="favorite">
<view class="favorite-title">我的收藏</view>
<view class="favorite-list">
<view class="favorite-item" wx:for="{{ favorites }}" wx:key="index">
<film-item film="{{ item }}"></film-item>
<button class="delete" size="mini" plain type="warn">删除</button>
</view>
</view>
<view wx:if="{{ showNoFavorite }}" class="favorite-no">~~暂无收藏~~</view>
</view>
<!-- 我的收藏 end -->

最后一个问题就是接口问题,图片不显示,由于传递给film-item组件,不好到组件中修改,最好存储到本地换成之前替换上图片,进入detail.js文件中,把下面代码加到在给favorites对象添加属性和属性值之前

1
2
3
// 添加电影到本地缓存
// 由于图片原因,不好到film-item组件中修改,所以到这里修改图片路径【detail和home接口问题,这里需要把图片给它换成有效的图片】
this.data.film.cover.url = this.data.film.cover_url

删除收藏电影

进入about.wxml页面给删除按钮绑定事件deleteFavorite,但是点击对应的电影我们应该传个参数过去,这样才能对应删除哪个收藏电影,由于遍历的是对象,index不就是电影对象的keyid吗,item就是单个电影对象,传递方式采用data-即自定义属性,取得话直接用事件对象

1
<button class="delete" size="mini" plain type="warn" bindtap="deleteFavorite" data-id="{{ index }}">删除</button>

接着进入about.js,定义这个删除函数,同时传递事件对象,取出电影id,接着就是关于页面数据仓库的删除和本地缓存的删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
deleteFavorite(e) { // 删除收藏电影
// console.log(e); // 打印一下事件对象,里面有个currentTarget属性接着还有个dataset属性里面存储着id
// console.log(e.currentTarget.dataset.id); // 成功打印id
let id = e.currentTarget.dataset.id // 获取事件触发时传递的参数

// 先从数据仓库中删除,delete之后是要重新赋值数据仓库的,不然页面上不会改变
delete this.data.favorites[id]
this.setData({
favorites: this.data.favorites,
showNoFavorite: Object.keys(this.data.favorites).length == 0 // 注意这里是this.data.favorites,它是刚刚delete删除了的最新的收藏数据,如果长度为0说明删完了
})

// 从本地缓存中删除
wx.setStorageSync('favorites', this.data.favorites) // 直接用上面已经删除的faborites
},

完结✨