微信小程序项目实战(二)
前言
若文章有误,欢迎读者留言反馈💻Installation1
git clone https://github.com/coding327/mymovies.git
首页数据对接
app.json
里的pages
的home
提到最上面,默认显示home
页面
导航功能完善,点击更多跳转分类页
添加url
指定路径即可1
<navigator url="/pages/list/list">更多 ></navigator>
数据如何对接,具体操作
首页一加载,发请求获取数据渲染,在
home.js
文件里操作
这个在哪里做,其实在onLoad
和onReady
都可以,onLoad
有个options
一般传递参数用
我们选择在onReady
中做请求数据请求都直接写在
onReady
中会很乱,于是三个不同分类最好封装成不同方法,在onReady
中调用即可
这里我们接口是需要做合法域名配置的
后端接口合法域名配置
- 首先去微信小程序直接百度搜索点击小程序登录进去,找到开发管理,横排第三个吧有个开发设置,找到服务器域名咱们把接口上的域名填上去即可
- 回到编辑器右上角有个详情点击进去,再点击项目配置,刷新几次,直到域名信息
request
合法域名出现刚刚咱们配置的域名即可- 如果你不配也可以在详情本地设置里面找到不校验合法域名、
web-view
(业务域名)。。。打上勾,这样也可以
做完上面这些,就可以书写请求接口,然后调接口了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
34data: {
// 一个分类对应一个对象
// type: {
// title: '',
// list: []
// }
// 既然分类有多个,那直接用数组即可
types: [] // 存储所有的分类
},
onReady: function () {
this.loadHotFilms()
},
loadHotFilms() {
wx.request({
url: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items',
data: {
start: 0,
count: 6
},
success: res => {
// console.log(res)
// 每一个分类作为一个对象
let type = {
title: res.data.subject_collection.name,
list: res.data.subject_collection_items
}
// 注意是个对象里面再数组,不好用push
this.setData({
'types[0]': type
})
}
})
},
我们可以在控制台AppData
中查看数据
这里注意一个问题this指向
success
要用箭头函数,不能使用匿名函数,不然拿不到数据,主要是this
指向问题,因为箭头函数没有自己this
,它依赖于父作用域中的this
,而父作用域的this
就是当前页面实例,这样就可以修改数据,这个实例才有data
以及其中的types
数据展示
把原先得数据换成请求到得数据
公共组件film-item
需要传递数据,父组件往子组件传递数据,进入film-item.js
文件里,找到properties
1 | properties: { |
film-item.js
代码如下1
2
3
4
5
6
7
8
9
10<view>
<!-- 使用传递过来数据 -->
<image class="film-img" src="{{ film.cover.url }}"></image>
<view class="film-name">{{ film.title }}</view>
<view class="film-star">
<!-- 星级评分展示处理,十分制,8<8.2图片亮的给4个 -->
<image class="star-img" src="{{ (index+1)*2 <= film.rating.value ? '/imgs/star-open.png' : '/imgs/star-close.png' }}" wx:for="{{ 5 }}" wx:key="index"></image>
<text class="film-source">{{ film.rating.value }}</text>
</view>
</view>
上面三目运算比较长,使用
wxs
处理一下
在项目根目录下按照utils/tools.wxs
这个层级创建文件夹和文件
1 | // 定义一个函数对评分进行处理 |
导入到film-item.wxml
文件里,使用wxs
标签
写在最下面写即可1
2<!-- 模块名叫tools,随便取 -->
<wxs src="../../utils/tools.wxs" module="tools"></wxs>
调用方法1
2
3<!-- 星级评分展示处理,十分制,8<8.2图片亮的给4个 -->
<image class="star-img" src="{{ tools.starImg(index,film.rating.value) }}" wx:for="{{ 5 }}" wx:key="index"></image>
<text class="film-source">{{ film.rating.value }}</text>
API
请求的模块化处理
优化:将所有向后台
api
发送请求都放在一个api
文件夹中,方便管理
项目根目录新建一个文件夹为api
再创建api.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 /**
* API请求的模块化处理
* 将项目中的所有请求都进行统一的管理
* */
// 统一定义接口地址
const URLS = {
hotUrl: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items',
latestUrl: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_latest/items',
freeUrl: 'https://m.douban.com/rexxar/api/v2/subject_collection/movie_free_stream/items',
detailUrl: 'https://m.douban.com/rexxar/api/v2/movie/'
}
const loadHotFilms = function(params={}) {
wx.request({
url: 'URLS.hotUrl',
data: params,
success: res => {
console.log(res)
}
})
}
// 模块导出
module.exports = {
loadHotFilms
}
导入使用,回到home.js
文件里,在最上面引入模块,同时之前写的loadFilms
方法和调用都注释掉
首页加载数据分类有三个,加载数据比较多,可以一个个定义,也可以直接定义一个加载所有数据的方法1
2
3
4
5
6
7
8
9
10
11
12// 加载主页数据
loadHomeData() {
// 加载影院热映数据
api.loadHotFilms({
start: 0,
count: 6
})
// 加载近期热门数据
// 加载免费在线数据
}
数据成功打印,但是怎么把数据放到首页,现在是在api.js
里打印的
利用promise
对于请求再次封装,回到api.js
文件里1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 影院热映数据
const loadHotFilms = function(params={}) {
// 返回Promise对象
return new Promise((resolve, reject) => {
wx.request({
url: URLS.hotUrl,
data: params,
success: resolve,
fail: reject
})
}).then( res => {
// console.log(res)
if (res.statusCode === 200) {
return res.data
} else {
// 如果失败将Promise状态由fulfilled转换为rejected
Promise.reject({
// message换为errMsg是可以处理响应错误,reject(xx)里的xx会作为catch的实参,包括上面fail里的reject的res,失败都会传递给catch里的回调函数
message: res.errMsg
})
}
})
}
接口使用
回到home.js
,调用返回Promise
对象,接着.then
操作,请求失败处理
1 | // 加载主页数据 |
对于请求错误进行封装(一般不止一个页面可能会发送请求错误),就在app.js
里封装1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 处理请求错误[响应错误这里没做处理]
const showError = function (error) {
// 使用微信小程序提供弹出组件显示请求失败
wx.showToast({
title: error.errMsg,
// 消息也可以自己给
// title: '请求失败',
image: '/imgs/error.png'
})
}
module.exports = {
loadHotFilms,
showError
}
home.js
调用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// 加载主页数据
loadHomeData() {
// 加载影院热映数据
// 此时调用返回Promise对象
api.loadHotFilms({
start: 0,
count: 6
}).then(data => {
let type = {
title: data.subject_collection.name,
list: data.subject_collection_items
}
// 注意是个对象里面再数组,不能用push
this.setData({
'types[0]': type
})
}).catch(api.showError) // 注意这里直接放的是函数即回调函数function (xx) { xxx }
// 加载近期热门数据
// 加载免费在线数据
}
同理另外几个分类数据
api
封装也是一样,代码如下,记得导出
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 // 近期热门数据
const loadLatestFilms = function (params = {}) {
// 返回Promise对象
return new Promise((resolve, reject) => {
wx.request({
url: URLS.latestUrl,
data: params,
success: resolve,
fail: reject
})
}).then( res => {
// console.log(res)
if (res.statusCode === 200) {
return res.data
} else {
// 如果失败将Promise状态由fulfilled转换为rejected
Promise.reject({
// message换为errMsg是可以处理响应错误,reject(xx)里的xx会作为catch的实参,包括上面fail里的reject的res,失败都会传递给catch里的回调函数
message: res.errMsg
})
}
})
}
// 免费在线数据
const loadFreeFilms = function (params = {}) {
// 返回Promise对象
return new Promise((resolve, reject) => {
wx.request({
url: URLS.freeUrl,
data: params,
success: resolve,
fail: reject
})
}).then( res => {
// console.log(res)
if (res.statusCode === 200) {
return res.data
} else {
// 如果失败将Promise状态由fulfilled转换为rejected
Promise.reject({
// message换为errMsg是可以处理响应错误,reject(xx)里的xx会作为catch的实参,包括上面fail里的reject的res,失败都会传递给catch里的回调函数
message: res.errMsg
})
}
})
}
home.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
44
45
46// 加载主页数据
loadHomeData() {
// 加载影院热映数据
// 此时调用返回Promise对象
api.loadHotFilms({
start: 0,
count: 6
}).then(data => {
let type = {
title: data.subject_collection.name,
list: data.subject_collection_items
}
// 注意是个对象里面再数组,不能用push
this.setData({
'types[0]': type
})
}).catch(api.showError) // 注意这里直接放的是函数即回调函数function (xx) { xxx }
// 加载近期热门数据
api.loadLatestFilms({
start: 0,
count: 6
}).then(data => {
let type = {
title: data.subject_collection.name,
list: data.subject_collection_items
}
this.setData({
'types[1]': type
})
}).catch(api.showError)
// 加载免费在线数据
api.loadFreeFilms({
start: 0,
count: 6
}).then(data => {
let type = {
title: data.subject_collection.name,
list: data.subject_collection_items
}
this.setData({
'types[2]': type
})
}).catch(api.showError)
}
小程序首页加载优化【三个分类要加载】
向后台发请求是需要花时间的,多保存几次,明显看到首页白屏的,过会才显示数据
loading
效果,我们资源文件里有个加载的gif
图就用它来做loading
效果
像这个loading
很多页面上都会用到,我们把它定义为一个模板
在项目根目录下创建一个templates
文件夹,接着创建loading
文件夹,接着创建loading.wxml
文件【定义为一个独立的模板文件目的是方便复用】
1
2
3
4 <view class="loading">
<image src="/imgs/loading.gif"></image>
<text>数据加载中</text>
</view>在首页中使用,
home.wxml
中【数据没有出来的时候展示,首页数据都是在一个数据中】
模板文件引用使用include
标签,注意是在home.wxml
文件中引入,放最上面,容器里面即可
1
2 <!-- 显示loading正在加载【数据还没请求到】 -->
<include src="/templates/loading/loading"/>
给loading
添加样式,在templates/loading
目录下新建loading.wxss
文件
注意这里有个问题,模板它不是页面,就算同名
wxss
它也不会加载这个样式,不生效
解决方法:在app.wxss
全局导入(加载)样式文件app.wxss
代码如下
1
2
3
4
5
6 /* 全局导入loading */
@import "/templates/loading/loading.wxss";
page {
background-color: #efefef;
}
loading.wxss
代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15.loading {
width: 100%;
text-align: center;
margin-top: 40rpx;
}
.loading image {
width: 80rpx;
height: 80rpx;
}
.loading view {
font-size: 22rpx;
color: #333;
}
有无数据直接通过判断数据长度就行了,直接使用
wx:if
指令即可
回到home.wxml
添加指令1
2<!-- 显示loading正在加载【数据还没请求到】 -->
<include wx:if="{{ types.length === 0 }}" src="/templates/loading/loading"/>
如果想人为让
loading
效果时间长一点,可以使用延时器把加载主页数据调用进行包裹即可
1
2
3
4 // 人为让loading效果时间长一点,只需要让发请求晚一点发即可
setTimeout(() => {
this.loadHomeData()
}, 3000)