前言

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

💻Installation

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

首页数据对接

app.json里的pageshome提到最上面,默认显示home页面

导航功能完善,点击更多跳转分类页

添加url指定路径即可

1
<navigator url="/pages/list/list">更多 ></navigator>

数据如何对接,具体操作

  1. 首页一加载,发请求获取数据渲染,在home.js文件里操作
    这个在哪里做,其实在onLoadonReady都可以,onLoad有个options一般传递参数用
    我们选择在onReady中做请求数据

  2. 请求都直接写在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
34
data: {
// 一个分类对应一个对象
// 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
2
3
4
5
6
properties: {
film: {
type: Object,
value: {}
}
},

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
2
3
4
5
6
7
8
9
10
11
12
13
// 定义一个函数对评分进行处理

// 参数1星星的序号
// 参数2评分
function starImg(index, source) {
return (index+1)*2 <= source ? '/imgs/star-open.png' : '/imgs/star-close.png'
}

// 函数导出
module.exports = {
// 注意这里不能简写
starImg: starImg
}

导入到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
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
// 加载主页数据
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(err => {
// 使用微信小程序提供弹出组件显示请求失败
wx.showToast({
// 消息可以自己给
// title: 'err.errMsg',
title: '请求失败',
image: '/imgs/error.png'
})
})
// 加载近期热门数据

// 加载免费在线数据

}

对于请求错误进行封装(一般不止一个页面可能会发送请求错误),就在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)