Open yundongbot opened 7 years ago
长列表展示是一个常见需求,下面我们开发一个列表页面展示 Github star 数最高的 JavaScript 项目并支持常见的上拉加载、回到顶部等功能。
我们先来看一下我们要实现的效果:
获取 Github 数据需要使用 Github API,本例中,我们使用到 search repositories API。我们根据 q=language:javascript&sort=stars&order=desc 这几个参数能够取到一段 JSON 数据,内容是按 star 数排序的 JavaScript 项目。由于数据太大,Github 支持分页返回数据,只需带上 page 参数即可。
q=language:javascript&sort=stars&order=desc
page
数据非常丰富,但此处我们仅需要三个字段:
full_name
stargazers_count
html_url
我们要在每个 <cell> 中分别展示 repo 的全称和 star 数。基本代码如下:
<cell>
<template> <div class="wrapper"> <list class="list"> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> </list> </div> </template> <style> .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } </style> <script> module.exports = { data: { items:[] }, methods: {} } </script>
这里有一点需要注意,对于内嵌的 <list>,必须有一个可计算的高度,你可以显示的指定高度,也可以使用 position 或 flex 来限制高度。由于我们的列表是全屏显示,我们使用 position 将列表设置为全屏展示。
<list>
position
flex
此时,items 为空数组,无任何数据,我们需要发起异步请求获取数据,并将其填充到 items 数组中。
items
这里,我们会使用到 stream 模块,此模块为我们提供了常用的网络请求 API,我们会用到 fetch。具体信息请查阅 fetch。
stream
fetch
我们在全局下引入 stream 模块,在 created 生命周期内发起异步请求获取第一页数据。此处,我们选择在 created 生命周期,原因在于在 created 生命周期内,页面还未开始渲染,我们能够更早发起请求。
created
我们将发起请求封装为一个方法 renderData(),以便重用。
renderData()
<template> <div class="wrapper"> <list class="list"> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> </list> </div> </template> <style> .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } </style> <script> var stream = require('@weex-module/stream') || {} var SEARCH_URL = 'https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc' module.exports = { data: { page: 1, items:[] }, created: function () { var url = SEARCH_URL + '&page=' + this.page this.renderData(url) this.page++ }, methods: { renderData: function (url) { var self = this stream.fetch({ method: 'GET', url: url, type:'json' }, function(res) { try { var results = res.data.items || [] if (Array.isArray(results)) { for(var i = 0; i < results.length; i++) { self.items.push(results[i]) } } } catch(e) {} },function(res){ }) } } } </script>
我们为页面提供一个吸附在顶部的标题,以便提示页面内容:
在 <cell> 前插入 <header> 标签并添加样式。
<header>
<template> <div class="wrapper"> <list class="list"> <header class="header"> <text class="title">Search Results</text> </header> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> </list> </div> </template> <style> .header { padding: 25; background-color: #efefef; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .title { text-align: center; } .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } </style> <script> var stream = require('@weex-module/stream') || {} var SEARCH_URL = 'https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc' module.exports = { data: { page: 1, items:[] }, created: function () { var url = SEARCH_URL + '&page=' + this.page this.renderData(url) this.page++ }, methods: { renderData: function (url) { var self = this stream.fetch({ method: 'GET', url: url, type:'json' }, function(res) { try { var results = res.data.items || [] if (Array.isArray(results)) { for(var i = 0; i < results.length; i++) { self.items.push(results[i]) } } } catch(e) {} },function(res){ }) } } } </script>
我们添加上拉加载功能以便用户查看更多 repo:
<loading>
loading
loadingData()
<template> <div class="wrapper"> <list class="list"> <header class="header"> <text class="title">Search Results</text> </header> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> <loading onloading="loadingData" style="width: 750; padding: 30;" display="{{loadingDisplay}}"> <text class="text">{{loadingText}}</text> </loading> </list> </div> </template> <style> .header { padding: 25; background-color: #efefef; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .title { text-align: center; } .text { text-align: center; } .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } </style> <script> var stream = require('@weex-module/stream') || {} var SEARCH_URL = 'https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc' module.exports = { data: { isLoaded: true, page: 1, loadingDisplay: 'hide', loadingText: 'Loading...', items:[] }, created: function () { var url = SEARCH_URL + '&page=' + this.page this.renderData(url) this.page++ }, methods: { renderData: function (url) { var self = this stream.fetch({ method: 'GET', url: url, type:'json' }, function(res) { self.loadingDisplay = 'hide' try { var results = res.data.items || [] if (Array.isArray(results)) { for(var i = 0; i < results.length; i++) { self.items.push(results[i]) } } } catch(e) {} },function(res){ }) }, loadingData: function (e) { var url = SEARCH_URL + '&page=' + this.page var self = this if (self.isLoaded === false) return self.loadingDisplay = 'show' if (self.page <=10 ) { self.renderData(url) self.page++ } else { self.loadingDisplay = 'hide' self.loadingText = 'NO MORE!' } } } } </script>
点击回到顶部按钮将会滚动到第一个 <cell>,这一步,我们会用到以下几个 API:
click
this.$el()
this
this.$el('item-0')
scrollToElement
dom
我们按如下步骤编写代码:
goToTop()
<template> <div class="wrapper"> <list class="list"> <header class="header"> <text class="title">Search Results</text> </header> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> <loading onloading="loadingData" style="width: 750; padding: 30;" display="{{loadingDisplay}}"> <text class="text">{{loadingText}}</text> </loading> </list> <div class="up" onclick="goToTop"> <img class="img" src="https://img.alicdn.com/tps/TB1ZVOEOpXXXXcQaXXXXXXXXXXX-200-200.png"></img> </div> </div> </template> <style> .header { padding: 25; background-color: #efefef; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .title { text-align: center; } .text { text-align: center; } .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .up { width: 70; height: 70; position: fixed; right: 20; bottom: 20; } .img { width: 70; height: 70; } </style> <script> var dom = require('@weex-module/dom') || {} var stream = require('@weex-module/stream') || {} var SEARCH_URL = 'https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc' module.exports = { data: { isLoaded: true, page: 1, loadingDisplay: 'hide', loadingText: 'Loading...', items:[] }, created: function () { var url = SEARCH_URL + '&page=' + this.page this.renderData(url) this.page++ }, methods: { renderData: function (url) { var self = this stream.fetch({ method: 'GET', url: url, type:'json' }, function(res) { self.loadingDisplay = 'hide' try { var results = res.data.items || [] if (Array.isArray(results)) { for(var i = 0; i < results.length; i++) { self.items.push(results[i]) } } } catch(e) {} },function(res){ }) }, loadingData: function (e) { var url = SEARCH_URL + '&page=' + this.page var self = this if (self.isLoaded === false) return self.loadingDisplay = 'show' if (self.page <=10 ) { self.renderData(url) self.page++ } else { self.loadingDisplay = 'hide' self.loadingText = 'NO MORE!' } }, goToTop: function (e) { dom.scrollToElement(this.$el('item-0'), { offset: -100 }) } } } </script>
为兼容所有版本,我们在 <header> 组件后插入 <refresh> 组件,并添加 refresh 事件调用 renderData() 重新加载数据。这里和使用 <loading> 类似。
<refresh>
refresh
当用户下拉刷新时,我们弹出一个 toast 提醒用户页面正在刷新数据。这里用到了 modal module 的 toast 方法。详情参考 modal module。
modal
toast
<template> <div class="wrapper"> <list class="list"> <header class="header"> <text class="title">Search Results</text> </header> <refresh style="width: 750; padding: 30;" onrefresh="refreshData" display="{{refreshDisplay}}"> <text class="text"> ↓ Pull to refresh </text> <loading-indicator class="indicator"></loading-indicator> </refresh> <cell class="row" repeat="item in items" id="item-{{$index}}"> <div> <text class="item">Repo name: {{item.full_name}}</text> </div> <div> <text class="item">Repo star: {{item.stargazers_count}}</text> </div> </cell> <loading onloading="loadingData" style="width: 750; padding: 30;" display="{{loadingDisplay}}"> <text class="text">{{loadingText}}</text> </loading> </list> <div class="up" onclick="goToTop"> <img class="img" src="https://img.alicdn.com/tps/TB1ZVOEOpXXXXcQaXXXXXXXXXXX-200-200.png"></img> </div> </div> </template> <style> .header { padding: 25; background-color: #efefef; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .title { text-align: center; } .text { text-align: center; } .wrapper { position: absolute; top: 0; right: 0; bottom: 0; left: 0; } .list{ flex: 1; } .row { padding: 20; border-bottom-color: #eeeeee; border-bottom-width: 2; border-bottom-style: solid; } .up { width: 70; height: 70; position: fixed; right: 20; bottom: 20; } .img { width: 70; height: 70; } </style> <script> var dom = require('@weex-module/dom') || {} var modal = require('@weex-module/modal') || {} var stream = require('@weex-module/stream') || {} var SEARCH_URL = 'https://api.github.com/search/repositories?q=language:javascript&sort=stars&order=desc' module.exports = { data: { isLoaded: true, page: 1, loadingDisplay: 'hide', refreshDisplay: 'hide', loadingText: 'Loading...', items:[] }, created: function () { var url = SEARCH_URL + '&page=' + this.page this.renderData(url) this.page++ }, methods: { renderData: function (url) { var self = this stream.fetch({ method: 'GET', url: url, type:'json' }, function(res) { self.refreshDisplay = 'hide' self.loadingDisplay = 'hide' try { var results = res.data.items || [] if (Array.isArray(results)) { for(var i = 0; i < results.length; i++) { self.items.push(results[i]) } } } catch(e) {} },function(res){ }) }, loadingData: function (e) { var url = SEARCH_URL + '&page=' + this.page var self = this if (self.isLoaded === false) return self.loadingDisplay = 'show' if (self.page <=10 ) { self.renderData(url) self.page++ } else { self.loadingDisplay = 'hide' self.loadingText = 'NO MORE!' } }, goToTop: function (e) { dom.scrollToElement(this.$el('item-0'), { offset: -100 }) }, refreshData: function (e) { var url = SEARCH_URL + '&page=1' if (this.isLoaded === false) return this.refreshDisplay = 'show' modal.toast({ 'message': 'Refreshing...', 'duration': 1 }) this.items = [] this.page = 1 this.renderData(url) this.refreshDisplay = 'hide' } } } </script>
体验一下
使用android集成的方式,提示没有这个方法 fetch.. 是怎么回事呀。 直接weex xxx.we 然后将js文件复制到项目里的...
@Genng 看一下 sdk 里是否集成了 stream 模块
@DoranYun sdk里面有的,是不是安卓集成的时候,还需要初始化什么,或者we的语法不对
语法你可以参考我上面的例子。
厉害
求git下载地址
一个简单的长列表开发教程
长列表展示是一个常见需求,下面我们开发一个列表页面展示 Github star 数最高的 JavaScript 项目并支持常见的上拉加载、回到顶部等功能。
我们先来看一下我们要实现的效果:
预备篇: Github API
获取 Github 数据需要使用 Github API,本例中,我们使用到 search repositories API。我们根据
q=language:javascript&sort=stars&order=desc
这几个参数能够取到一段 JSON 数据,内容是按 star 数排序的 JavaScript 项目。由于数据太大,Github 支持分页返回数据,只需带上page
参数即可。数据非常丰富,但此处我们仅需要三个字段:
full_name
:项目全称stargazers_count
:star 数html_url
:repo 地址第1步:编写基本代码
我们要在每个
<cell>
中分别展示 repo 的全称和 star 数。基本代码如下:这里有一点需要注意,对于内嵌的
<list>
,必须有一个可计算的高度,你可以显示的指定高度,也可以使用position
或flex
来限制高度。由于我们的列表是全屏显示,我们使用position
将列表设置为全屏展示。第2步:请求数据
此时,
items
为空数组,无任何数据,我们需要发起异步请求获取数据,并将其填充到items
数组中。这里,我们会使用到
stream
模块,此模块为我们提供了常用的网络请求 API,我们会用到fetch
。具体信息请查阅fetch
。我们在全局下引入 stream 模块,在
created
生命周期内发起异步请求获取第一页数据。此处,我们选择在created
生命周期,原因在于在created
生命周期内,页面还未开始渲染,我们能够更早发起请求。我们将发起请求封装为一个方法
renderData()
,以便重用。第3步:顶部吸附
我们为页面提供一个吸附在顶部的标题,以便提示页面内容:
在
<cell>
前插入<header>
标签并添加样式。第4步:上拉加载
我们添加上拉加载功能以便用户查看更多 repo:
<cell>
后插入<loading>
组件;<loading>
组件添加loading
事件;loadingData()
方法,获取下一页数据;我们在上拉时显示<loading>
,加载出数据后将其隐藏;第5步:回到顶部
点击回到顶部按钮将会滚动到第一个
<cell>
,这一步,我们会用到以下几个 API:click
事件:毫无疑问,点击时将会触发此事件的执行函数,具体信息参考click
this.$el()
:获取对应 id 的元素对象的引用,可在组件的方法中通过this
访问。e.g.:this.$el('item-0')
scrollToElement
:让页面滚动到指定节点。通过dom
module 访问,更多信息可参考dom
module我们按如下步骤编写代码:
<list>
组件后插入按钮,将其固定在右下角;click
事件;goToTop()
方法回到顶部。第6步:下拉刷新
为兼容所有版本,我们在
<header>
组件后插入<refresh>
组件,并添加refresh
事件调用renderData()
重新加载数据。这里和使用<loading>
类似。当用户下拉刷新时,我们弹出一个 toast 提醒用户页面正在刷新数据。这里用到了
modal
module 的toast
方法。详情参考 modal module。体验一下