请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册
搜索

技术分享 快应用开发教程(4):APP开发实战-接入数据

3
回复
2986
查看
[复制链接]
 楼主| 2018-11-27 20:06:02 显示全部楼层 |阅读模式
本帖最后由 vivo技术弟 于 2018-11-27 10:53 编辑
上一篇中我们把应用需要的页面搭建了出来,已经可以看出整个应用的雏形了,可是数据都还是写死在模板中的,所以接下来我们把数据接口中的动态数据接入,让我们的应用真正可用起来。
准备工作数据接口1. 查询正在上映的院线电影列表
接口功能
获取院线正在上映的电影列表
URL
支持格式
JSON
HTTP请求方式
GET
请求参数
参数
必选
类型
默认值
说明
countfalseint20请求的电影列表每页的数量
startfalseint0请求的电影列表开始的位置
cityfalsestring'北京'请求所在城市的电影列表
返回字段
返回字段
字段类型
说明
countint电影列表每页的数量
startint请求的电影列表开始的位置
totalint列表全部元素数量
subjectsarray电影列表数据
titlestring标题
接口示例
  1. {
  2. "count": 20,
  3. "start": 0,
  4. "total": 38,
  5. "subjects": [···],
  6. "title": "正在上映的电影-深圳"
  7. }
复制代码
2. 查询即将上映的院线电影列表
接口功能
获取即将上映的电影列表
URL
支持格式
JSON
HTTP请求方式
GET
请求参数
参数
必选
类型
默认值
说明
countfalseint20请求的电影列表每页的数量
startfalseint0请求的电影列表开始的位置
返回字段
返回字段
字段类型
说明
countint电影列表每页的数量
startint请求的电影列表开始的位置
totalint列表全部元素数量
subjectsarray电影列表数据
titlestring标题
接口示例
  1. {
  2. "count": 20,
  3. "start": 0,
  4. "total": 38,
  5. "subjects": [···],
  6. "title": "即将上映的电影"
  7. }
复制代码
3. 查询豆瓣电影TOP250电影列表
接口功能
获取豆瓣电影TOP250电影列表
URL
支持格式
JSON
HTTP请求方式
GET
请求参数
参数
必选
类型
默认值
说明
countfalseint20请求的电影列表每页的数量
startfalseint0请求的电影列表开始的位置
返回字段
返回字段
字段类型
说明
countint电影列表每页的数量
startint请求的电影列表开始的位置
totalint列表全部元素数量
subjectsarray电影列表数据
titlestring标题
接口示例
  1. {
  2. "count": 20,
  3. "start": 0,
  4. "total": 38,
  5. "subjects": [···],
  6. "title": "豆瓣电影Top250"
  7. }
复制代码
4. 查询单个电影详情信息
接口功能
获取单个电影详情信息
URL
支持格式
JSON
HTTP请求方式
GET
返回字段
字段太多请自行点开下面的接口示例查看
接口示例
  1. {
  2. "id": "3168101",
  3. "title": "毒液:致命守护者",
  4. "year": "2018",
  5. "directors": [···],
  6. "original_title": "Venom",
  7. ···
  8. }
复制代码
请求数据的方法
有了数据接口,接下来就是要发起请求了,在快应用中提供了请求数据的系统接口@sytem.fetch。接口的使用按照下列步骤进行。
  • 在manifest.json文件中的feature字段下声明要使用的接口
  1. {
  2. ···
  3. "feature": [
  4. {"name": "system.fetch"},
  5. ···
  6. ]
  7. }
复制代码
  • 在要使用接口的位置导入
  1. import fetch from '@system.fetch'
复制代码
  • 使用fetch请求数据
  1. fetch.fetch({
  2. url: 'http://www.example.com',
  3. success: function (response) {
  4. console.log(`the status code of the response: ${response.code}`)
  5. console.log(`the data of the response: ${response.data}`)
  6. console.log(`the headers of the response: ${JSON.stringify(response.headers)}`)
  7. },
  8. fail: function (err, code) {
  9. console.log(`handling fail, code = ${code}`)
  10. }
  11. })
复制代码
关于数据请求接口更详细的说明可以在官方文档中查看。
绑定数据的方法
数据请求回来了,我们还需要让数据渲染到组件上去,快应用中模板数据的绑定方法和目前主流前端框架的方式类似。首先在页面script中提前声明需要绑定的数据。
  1. <template>
  2. <text>{{message}}</text>
  3. </template>
  4. <script>
  5. export default {
  6. protected: {
  7. message: 'Hello'
  8. }
  9. }
  10. </script>
复制代码
protected是快应用数据位置的关键字,和它功能相似的还有public和private。他们之间的区别见下表。
[td]
属性
类型
描述
publicObjectpublic内定义的属性允许被传入的数据覆盖,如果外部传入数据的某个属性未被声明,在public中不会新增这个属性
protectedObjectprotected内定义的属性,允许被应用内部页面请求传递的数据覆盖,不允许被应用外部请求传递的数据覆盖
privateObjectprivate内定义的属性不允许被覆盖
接入数据
在做好上述的准备工作后,可以正式把数据接入到我们的应用上了。用上面准备的方式写好请求数据的方法。这里以首页正在热映的数据请求为例。
template代码
  1. <list class="movie-list">
  2. <block for="movie in movies">
  3. <list-item type="movie">
  4. <div class="movie">
  5. <div class="poster">
  6. <image src="{{movie.images.large}}"></image>
  7. </div>
  8. <div class="info">
  9. <div class="top">
  10. <div class="title">
  11. <text class="name">{{movie.title}}</text>
  12. <text class="year">{{movie.year}}</text>
  13. </div>
  14. <div class="rating">
  15. <text class="average">{{movie.rating.average}}</text>
  16. </div>
  17. </div>
  18. <div class="bottom">
  19. <div class="wrap">
  20. <text>类型: </text>
  21. <text>
  22. <block for="type in movie.genres">
  23. <span>{{type}}</span>
  24. </block>
  25. </text>
  26. </div>
  27. <div class="wrap">
  28. <text>演员: </text>
  29. <text>
  30. <block for="actor in movie.casts">
  31. <span>{{actor.name}}</span>
  32. </block>
  33. </text>
  34. </div>
  35. <div class="wrap">
  36. <text>导演: </text>
  37. <text>
  38. <block for="director in movie.directors">
  39. <span>{{director.name}}</span>
  40. </block>
  41. </text>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </list-item>
  47. </block>
  48. <list-item type="nomore">
  49. <text>没有更多了~</text>
  50. </list-item>
  51. </list>
复制代码
script代码
  1. import router from "@system.router";
  2. import fetch from "@system.fetch";
  3. export default {
  4. protected: {
  5. movies: []
  6. },
  7. onInit: function () {
  8. this.getMovieList(); // 在页面初始化的时候后请求数据
  9. },
  10. switchTab: function (uri) {
  11. router.replace({
  12. uri: uri
  13. })
  14. },
  15. getMovieList: function () {
  16. const that = this; // 保存当前this
  17. fetch.fetch({
  18. url: 'https://api.douban.com/v2/movie/in_theaters?count=10&start=0',
  19. success: function (response) {
  20. let data = JSON.parse(response.data); // 解析请求回来的数据为对象
  21. if (response.code === 200) { // 判断当前请求是否成功返回
  22. that.movies = data.subjects; // 把请求到的数据赋值到定义的变量上去
  23. }
  24. },
  25. fail: function (err, code) {
  26. console.log(`handling fail, code = ${code}`);
  27. }
  28. })
  29. }
  30. }
复制代码
现在页面已经像是那么回事了,但是还缺少数据请求的交互,例如顶部筛选器的点击事件还没有,电影列表滚动到底部加载更多也还没有处理,下面我们一个一个处理。
滚动到底部加载更多
监听列表滚动到底部的是list组件的scrollbottom事件,事件有两种方式绑定到组件上。
  1. <div>
  2. <!-- 正常格式 -->
  3. <list></list>
  4. <!-- 缩写 -->
  5. <list @scrollbottom="getMore"></list>
  6. </div>
复制代码
给list组件绑定好的监听滚动底部事件的方法,然后我们要处理的就是滚动到底部后要执行的方法了,这个方法是这样处理的。
  1. protected: {
  2. movies:[],
  3. start: 0, // 请求数据开始的位置
  4. count: 10 // 每次请求回来的列表元素个数
  5. },
  6. getMovieList: function () {
  7. const that = this; // 保存当前this
  8. fetch.fetch({
  9. url: 'https://api.douban.com/v2/movie/in_theaters?count='+ that.count +'&start='+ that.start,
  10. success: function (response) {
  11. let data = JSON.parse(response.data); // 解析请求回来的数据为对象
  12. if (response.code === 200) { // 判断当前请求是否成功返回
  13. that.movies = that.movies.concat(data.subjects); // 把请求到的数据赋值到定义的变量上去
  14. that.start += that.count; // 每次请求成功后给start增加页码
  15. }
  16. },
  17. fail: function (err, code) {
  18. console.log(`handling fail, code = ${code}`);
  19. }
  20. })
  21. }
复制代码
为了优化数据加载的体验,我们简单给数据列表加上loading和没有更多数据的提示。
  1. <list>
  2. ···
  3. <list-item class="more" type="more">
  4. <div if="!more"><progress type="circular"></progress></div>
  5. <div if="more"><text>没有更多了~</text></div>
  6. </list-item>
  7. </list>.more {
  8. justify-content: center;
  9. } protected: {
  10. movies: [],
  11. start: 0,
  12. count: 10,
  13. + more: false
  14. },
  15. getMovieList: function () {
  16. const that = this; // 保存当前this
  17. fetch.fetch({
  18. url: 'https://api.douban.com/v2/movie/in_theaters?count=' + that.count + '&start=' + that.start,
  19. success: function (response) {
  20. let data = JSON.parse(response.data); // 解析请求回来的数据为对象
  21. if (response.code === 200) { // 判断当前请求是否成功返回
  22. that.movies = that.movies.concat(data.subjects); // 把请求到的数据赋值到定义的变量上去
  23. that.start += that.count; // 每次请求成功后给start增加页码
  24. }
  25. + if (that.movies.length === data.total) {
  26. + that.more = true;
  27. + }
  28. },
  29. fail: function (err, code) {
  30. console.log(`handling fail, code = ${code}`);
  31. }
  32. })
  33. }
复制代码
顶部筛选器事件处理
筛选器的实现有很多种方式,这里采取最简单的方式。
template代码
  1. <div class="filter-wrap">
  2. <text class="filter {{type === 'in_theaters'? 'active': ''}}">正在热映</text>
  3. <text class="filter {{type === 'coming_soon'? 'active': ''}}">即将上映</text>
  4. </div>
复制代码
script代码
  1. export default {
  2. protected: {
  3. movies: [],
  4. start: 0,
  5. count: 10,
  6. more: false,
  7. + type: 'in_theaters'
  8. },
  9. onInit: function () {
  10. this.getMovieList();
  11. },
  12. switchTab: function (uri) {
  13. router.replace({
  14. uri: uri
  15. })
  16. },
  17. getMovieList: function () {
  18. const that = this; // 保存当前this
  19. fetch.fetch({
  20. + url: 'https://api.douban.com/v2/movie/' + that.type + '?count=' + that.count + '&start=' + that.start,
  21. success: function (response) {
  22. let data = JSON.parse(response.data); // 解析请求回来的数据为对象
  23. if (response.code === 200) { // 判断当前请求是否成功返回
  24. that.movies = that.movies.concat(data.subjects); // 把请求到的数据赋值到定义的变量上去
  25. that.start += that.count; // 每次请求成功后给start增加页码
  26. }
  27. if (that.movies.length === data.total) {
  28. that.more = true;
  29. }
  30. },
  31. fail: function (err, code) {
  32. console.log(`handling fail, code = ${code}`);
  33. }
  34. })
  35. },
  36. + getMovieListByType: function (type) {
  37. + this.start = 0;
  38. + this.movies = [];
  39. + this.more = false;
  40. + this.type = type;
  41. + this.getMovieList();
  42. + }
  43. }
复制代码
处理跳转详情页
现在我们给单个电影加上跳转详情页的事件。
template代码
  1. <list-item type="movie">
  2. ···
  3. </list-item>
复制代码
script代码
  1. gotoDetail: function (id) {
  2. router.push({
  3. uri: '/page/detail',
  4. params: {
  5. id: id
  6. }
  7. })
  8. }
复制代码
这个跳转方法我们采用router模块的push方法,同时在跳转的同时把当前点击的电影ID当做参数传到详情页,详情页取到传递过来的id,根据这个再请求到对应的电影详细信息。
详情页数据接入
详情页通过传递进来的id,发送获取详细信息的请求,根据请求回来的数据渲染页面。绑定数据的方法上面已经演示过了,下面就不再赘述了。
详情页script代码
  1. import fetch from "@system.fetch";
  2. export default {
  3. protected: {
  4. id: 0, // 上个页面传过来的id,一定要在此定义,不然无法访问
  5. movie: {}
  6. },
  7. onInit: function () {
  8. this.getMovieById();
  9. },
  10. getMovieById: function () {
  11. const that = this; // 保存当前this
  12. fetch.fetch({
  13. url: 'https://api.douban.com/v2/movie/subject/' + that.id,
  14. success: function (response) {
  15. let data = JSON.parse(response.data);
  16. if (response.code === 200) {
  17. that.movie = data;
  18. that.$page.setTitleBar({ text: data.title }); // 设置页面标题
  19. }
  20. },
  21. fail: function (err, code) {
  22. console.log(`handling fail, code = ${code}`);
  23. }
  24. })
  25. }
  26. }
复制代码
现在还剩下最后一个页面榜单页作为练习留给大家自行实现数据接入。
下一篇我们来讲如何把我们写的代码组件化,降低代码耦合度,增加代码的可复用性,提高整个应用的组件化程度。

文档github项目地址:https://github.com/vivoquickapp/quickapp-tutorial/tree/master
作者:dadong
时间:2018.11.23
回复

使用道具 举报

0

主题

2

帖子

10

积分

2019-3-9 14:36:06 显示全部楼层
赞!!!
回复

使用道具 举报

6

主题

22

帖子

140

积分

2019-9-23 18:02:34 显示全部楼层
请问 接口跨域 后台不可修改,快应用里边能不能和小程序一样在后台配置一个接口网址,或者vue一样进行反向代理,进行解决 接口跨域问题的处理
回复

使用道具 举报

0

主题

7

帖子

35

积分

2023-2-15 11:43:45 显示全部楼层
官网开发者文档 里面 为什么没有数据模型的介绍, private只能在页面里面使用,组件里面使用不了,为什么? 都是ux文件,怎么区分是组件还是页面,在路由里面添加的就是页面吗?那一个ux文件,不能既是组件又是页面吗? 这种情况private使用不矛盾吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册