Appearance
任务八 实现文章发布与文章分页功能
常见的分页方式
分页是在软件产品中以列表形式呈现内容时一般都会使用到的功能,如新闻列表分页、商品列表分页、图片列表分页等等。而分页的种类多种多样,产品经理会根据列表内容和使用场景,设计一种偏向用户使用习惯、能够给用户带来友好的交互体验的分页方式。下面将为读者介绍目前比较常用的几种分页方式。
瀑布流分页
瀑布流,又称瀑布流式布局。是比较流行的一种网站页面布局,视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载并附加至当前尾部。 瀑布流形式探索性更强、操作体验更优。
自动瀑布流
自动瀑布流分页多用于资讯类、社交类产品,快速浏览内容和发现内容的场景,瀑布流下方没有太多无关信息时。 特点是当列表下滑到底部时会自动加载下一页,例如微博的自动加载。
手动瀑布流
当列表底部存在更多有价值的内容时,不适合自动加载下一页,这是则需要用户手动触发“加载更多”获取更多内容,例如“人人都是产品经理”的手动加载更多 。
自动瀑布流和手动瀑布流相结合
当列表底部内容过多时,采用的一种折中方案,如果说用户是长期关注阅读某网站信息或者本身网站内容不是很多时,前几次分页使用自动加载已经足够展示最近的信息,同时保证用户浏览的流畅,之后便采用手动点击加载更多的形式,保证底部内容不被用户忽略。例如pmtoo网站采用的是自动和手动加载结合使用的形式。
常规数字分页
常规数字分页对内容的形式更具有控制感,有较强的检索功能,同时便于内容的快速定位,直观的数据展现。数字分页一般在列表内容相对固定或者比较重要,需要较强的检索能力时去使用,例如后台管理系统中的信息列表、淘宝网的商品搜索展示列表等等。数字分页的缺点是每次翻页都要点击,对于那些检索需求较弱的,比如朋友圈、微博等不是特别友好。
箭头和圆点分页
箭头和圆点分页通常用于展示型内容,内容大小固定且内容较少时使用。这两种形式通常情况下会一起使用,箭头方便用户进行切换,圆点标识数量和当前的位置。例如网站轮播图。
下拉刷新和上拉加载
下拉刷新和上拉加载适用于移动端中的列表分页,效果上与上文所讲的瀑布流分页相似,只不过是触发条件从用户在PC端滚动鼠标滚轮变为在移动端滑动屏幕,当列表滑动触顶时用户下拉则刷新列表第一页内容,当列表滑动触底时用户上滑则加载列表下一页内容,当所有页加载完成时列表底部提示用户无更多内容。
在实际产品设计中,可能会根据列表内容和使用场景结合几种分页优点去设计分页,以带来最佳的用户交互体验。启嘉校园项目属于移动端,内容检索性较弱,采用的便是下拉刷新和上拉加载的分页形式。
uni.uploadFile文件上传
将本地资源上传到开发者服务器,客户端发起一个POST请求,其中content-type为multipart/form-data。
如页面通过uni.chooseImage 等接口获取到一个本地资源的临时文件路径后,可通过此接口将本地资源上传到指定服务器。
在各个小程序平台运行时,网络相关的 API 在使用前需要配置域名白名单。
OBJECT 参数说明:
| 参数名 | 类型 | 必填 | 说明 | 平台差异说明 |
|---|---|---|---|---|
| url | String | 是 | 开发者服务器 url | |
| files | Array | 是(files和filePath选其一) | 需要上传的文件列表。使用 files 时,filePath 和 name 不生效。 | App、H5( 2.6.15+) |
| fileType | String | 见平台差异说明 | 文件类型,image/video/audio | 仅支付宝小程序,且必填。 |
| file | File | 否 | 要上传的文件对象。 | 仅H5(2.6.15+)支持 |
| filePath | String | 是(files和filePath选其一) | 要上传文件资源的路径。 | |
| name | String | 是 | 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容 | |
| header | Object | 否 | HTTP 请求 Header, header 中不能设置 Referer。 | |
| timeout | Number | 否 | 超时时间,单位 ms | H5(HBuilderX 2.9.9+)、APP(HBuilderX 2.9.9+) |
| formData | Object | 否 | HTTP 请求中其他额外的 form data | |
| success | Function | 否 | 接口调用成功的回调函数 | |
| fail | Function | 否 | 接口调用失败的回调函数 | |
| complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
注意
- App支持多文件上传,微信小程序只支持单文件上传,传多个文件需要反复调用本API。所以跨端的写法就是循环调用本API
- hello uni-app中的客服反馈,支持多图上传
- App平台选择和上传非图像、视频文件
- 网络请求的 超时时间 可以统一在 manifest.json 中配置 networkTimeout
- 支付宝小程序开发工具上传文件返回的http状态码为字符串形式,支付宝小程序真机返回的状态码为数字形式
files参数说明
files 参数是一个 file 对象的数组,file 对象的结构如下:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | String | 否 | multipart 提交时,表单的项目名,默认为 file |
| file | File | 否 | 要上传的文件对象,仅H5(2.6.15+)支持 |
| uri | String | 是 | 文件的本地地址 |
如果 name 不填或填的值相同,可能导致服务端读取文件时只能读取到一个文件。
success 返回参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| data | String | 开发者服务器返回的数据 |
| statusCode | Number | 开发者服务器返回的 HTTP 状态码 |
示例
uni.chooseImage({
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
uni.uploadFile({
url: 'https://www.example.com/upload', //仅为示例,非真实的接口地址
filePath: tempFilePaths[0],
name: 'file',
formData: {
'user': 'test'
},
success: (uploadFileRes) => {
console.log(uploadFileRes.data);
}
});
}});
返回值
如果希望返回一个 uploadTask 对象,需要至少传入 success / fail / complete 参数中的一个。例如:
var uploadTask = uni.uploadFile({
url: 'https://www.example.com/upload', //仅为示例,并非真实接口地址。
complete: ()=> {}});
uploadTask.abort();
如果没有传入 success / fail / complete 参数,则会返回封装后的 Promise 对象:Promise封装
通过 uploadTask,可监听上传进度变化事件,以及取消上传任务。
uploadTask 对象的方法列表
| 方法 | 参数 | 说明 |
|---|---|---|
| abort | 中断上传任务 | |
| onProgressUpdate | callback | 监听上传进度变化 |
| onHeadersReceived | callback | 监听 HTTP Response Header 事件。会比请求完成事件更早,仅微信小程序平台支持,规范详情 |
| offProgressUpdate | callback | 取消监听上传进度变化事件,仅微信小程序平台支持,规范详情 |
| offHeadersReceived | callback | 取消监听 HTTP Response Header 事件,仅微信小程序平台支持,规范详情 |
onProgressUpdate 返回参数说明:
| 参数 | 类型 | 说明 |
|---|---|---|
| progress | Number | 上传进度百分比 |
| totalBytesSent | Number | 已经上传的数据长度,单位 Bytes |
| totalBytesExpectedToSend | Number | 预期需要上传的数据总长度,单位 Bytes |
示例
uni.chooseImage({
success: (chooseImageRes) => {
const tempFilePaths = chooseImageRes.tempFilePaths;
const uploadTask = uni.uploadFile({
url: 'https://www.example.com/upload', //仅为示例,非真实的接口地址
filePath: tempFilePaths[0],
name: 'file',
formData: {
'user': 'test'
},
success: (uploadFileRes) => {
console.log(uploadFileRes.data);
}
});
uploadTask.onProgressUpdate((res) => {
console.log('上传进度' + res.progress);
console.log('已经上传的数据长度' + res.totalBytesSent);
console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
// 测试条件,取消上传任务。
if (res.progress > 50) {
uploadTask.abort();
}
});
}});
uni-app页面间通讯
自 HBuilderX 2.0.0 起支持 uni.$emit、 uni.$on 、 uni.$once 、uni.$off ,可以方便的进行页面的通讯 ,触发的事件都是 App 全局级别的,跨任意组件,页面,nvue,vue 等。
uni.$emit(eventName,OBJECT)
触发全局的自定义事件,附加参数都会传给监听器回调函数。
| 属性 | 类型 | 描述 |
|---|---|---|
| eventName | String | 事件名 |
| OBJECT | Object | 触发事件携带的附加参数 |
示例
uni.$emit('update',{msg:'页面更新'})
uni.$on(eventName,callback)
监听全局的自定义事件,事件由 uni.$emit 触发,回调函数会接收事件触发函数的传入参数。
| 属性 | 类型 | 描述 |
|---|---|---|
| eventName | String | 事件名 |
| callback | Function | 事件的回调函数 |
示例
uni.$on('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
uni.$once(eventName,callback)
监听全局的自定义事件,事件由 uni.$emit 触发,但仅触发一次,在第一次触发之后移除该监听器。
| 属性 | 类型 | 描述 |
|---|---|---|
| eventName | String | 事件名 |
| callback | Function | 事件的回调函数 |
示例
uni.$once('update',function(data){
console.log('监听到事件来自 update ,携带参数 msg 为:' + data.msg);
})
uni.$off([eventName, callback])
移除全局自定义事件监听器。
| 属性 | 类型 | 描述 |
|---|---|---|
| eventName | Array<String> | 事件名 |
| callback | Function | 事件的回调函数 |
- 如果uni.$off没有传入参数,则移除App级别的所有事件监听器
- 如果只提供了事件名(eventName),则移除该事件名对应的所有监听器
- 如果同时提供了事件与回调,则只移除这个事件回调的监听器
- 提供的回调必须跟$on的回调为同一个才能移除这个回调的监听器
具体如何使用呢?我们假设一个场景,进入app是未登陆状态,需要在我的页面点击登陆,进入登陆页面进行登陆。登陆成功之后,返回到我的页面,实时显示登陆后的用户信息。
首先,在我的页面监听事件。
// 我的页面
onLoad(){
// 监听事件
uni.$on('login',(usnerinfo)=>{
this.usnerinfo = usnerinfo;
})
},
onUnload() {
// 移除监听事件
uni.$off('login');
},
因为事件监听是全局的,所以使用 uni.$on ,需要使用 uni.$off 移除全局的事件监听,避免重复监听。
进入登录页面,触发事件:
// 登录页面
uni.$emit('login', {
avatarUrl: 'https://img-cdn-qiniu.dcloud.net.cn/uploads/nav_menu/10.jpg',
token: 'user123456',
userName: 'unier',
login: true
});
使用uni.$emit触发事件后,对应的uni.$on就会监听到事件触发,在回调中去执行相关的逻辑。
以上只是一个简单的场景应用。而我们开发中会遇到很多页面间通讯场景,如:
- vue与nvue,nvue与vue间的通讯
- tabbar页面之间的通讯
- 父页面与多级子页面间的通讯