业务
列表通用模板
小程序列表通用模板代码:首部搜索框,下方数据列表,无数据就显示暂无数据
- 如果数据全部返回,在前端搜索过滤
- 如果数据分页返回,上拉加载、下拉刷新,搜索、清空
- 顶部项目选择
1. 数据全部返回,搜索过滤由前端处理
小程序 UI 组件库:Vant Weapp
index.wxml
<van-search
value="{{ searchValue }}"
placeholder="请输入项目名称"
shape="round"
bind:search="onSearch"
bind:change="onSearch"
bind:clear="onClear"
/>
<view wx:if="{{projectList.length>0}}">
<van-cell-group>
<navigator wx:for="{{projectList}}" wx:key="id" url="/pages/project/detail?proId={{item.id}}">
<van-cell title="{{item.proName}}" label="{{item.proNo}}" />
</navigator>
</van-cell-group>
</view>
<van-empty wx:else description="暂无数据" />
index.json
{
"navigationBarTitleText": "项目管理",
"usingComponents": {
"van-search": "@vant/weapp/search/index",
"van-cell": "@vant/weapp/cell/index",
"van-cell-group": "@vant/weapp/cell-group/index",
"van-empty": "@vant/weapp/empty/index"
}
}
index.js
import { getProjectList } from '../../utils/api.js';
Page({
data: {
searchValue: '',
projectList: [],
originProList: [],
loading: false
},
onLoad() {
this.searchProjectList();
},
searchProjectList() {
this.setData({ loading: true });
getProjectList().then(res => {
this.setData({ loading: false, projectList: res.data.data, originProList: res.data.data });
});
},
onSearch(e) {
this.setData({ searchValue: e.detail });
if (!e.detail) {
this.setData({ projectList: this.data.originProList });
} else {
const arr = this.data.projectList.filter(ele => ele.proName.indexOf(e.detail) !== -1);
this.setData({ projectList: arr });
}
},
onClear() {
this.setData({ projectList: this.data.originProList });
}
});
2. 分页返回数据
index.wxml 去掉了bind:change="onSearch"
,其余同上。index.json 如果要开启下拉刷新,需要添加:"enablePullDownRefresh": true
index.js
import { getProjectList } from '../../utils/api.js';
Page({
data: {
searchValue: '',
listData: [],
pageNum: 1,
total: 0,
loading: false
},
onLoad() {
this.getList(1);
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if (!this.data.loading && this.data.pageNum < Math.ceil(this.data.total / 10)) {
this.getList(this.data.pageNum + 1);
}
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
//启用标题栏显示加载状态
wx.showNavigationBarLoading();
// 调用相关方法,重置数据
this.setData({ listData: [], searchValue: '', pageNum: 1, total: 0 });
// 重新发起请求
this.getList(1);
setTimeout(() => {
wx.hideNavigationBarLoading(); //隐藏标题栏显示加载状态
wx.stopPullDownRefresh(); //结束刷新
}, 2000); //设置执行时间
},
getList(pageNum) {
this.setData({ loading: true });
getProjectList({ pageNum, pageSize: 10, proName: this.data.searchValue }).then(res => {
this.setData({
loading: false,
listData: this.data.listData.concat(res.data.rows),
pageNum,
total: res.data.total
});
});
},
onSearch(e) {
this.setData({ listData: [], searchValue: e.detail, pageNum: 1, total: 0 });
this.getList(1);
},
onClear() {
this.setData({ listData: [], searchValue: '', pageNum: 1, total: 0 });
this.getList(1);
}
});
- 总页数 = Math.ceil(总条数 / 每页显示的条数)
生成随机数
wx.getRandomValues({
length: 30, // 生成 30 个字节长度的随机数
success(res) {
that.setData({ inspectFileUuid: wx.arrayBufferToBase64(res.randomValues) });
}
});
图片上传
使用原生方法上传
使用wx.chooseMedia()
选取图片,默认支持从相册选择和拍照上传,下方是单独区分的。再使用wx.uploadFile()
上传到服务器,
但是该方法不支持多图片上传,可以封装成 promise 并行上传图片
upload.wxml
<view>
<view>
<van-button type="primary" bindtap="photoAlbum">相册上传</van-button>
<van-button type="info" bindtap="photograph">拍照上传</van-button>
</view>
<view>
<view class="num">
<text>图片上传</text>
<text>{{imageList.length}}/9</text>
</view>
<view>imageList: {{imageList}}</view>
<block wx:for="{{imageList}}" wx:key="*this">
<view class="q-image-wrap">
<image
class="q-image"
style="width: 300rpx; height: 300rpx"
src="{{item}}"
mode="aspectFill"
data-idx="{{index}}"
bindtap="handleImagePreview"
></image>
<view data-idx="{{index}}" bindtap="removeImage">删除</view>
</view>
</block>
</view>
<van-button type="primary" block color="#409eff" bindtap="submitForm">保存</van-button>
</view>
upload.js
Page({
data: {
imageList: []
},
// 相册上传
photoAlbum() {
let that = this;
const imgNum = this.data.imageList.length;
if (imgNum >= 9) {
wx.showToast({ title: '最多上传9张图片', icon: 'loading', duration: 2000 });
return false;
} else {
imgNum = 9 - imgNum;
}
wx.chooseMedia({
count: imgNum,
mediaType: ['image'],
sourceType: ['album'],
success(res) {
const arr = [];
res.tempFiles.forEach(e => {
arr.push(e.tempFilePath);
});
that.setData({ imageList: that.data.imageList.concat(arr) });
},
fail(res) {
console.log('接口调用失败的回调函数', res);
}
});
},
// 拍照上传
photograph() {
let that = this;
const imgNum = this.data.imageList.length;
if (imgNum >= 9) {
wx.showToast({ title: '最多上传9张图片', icon: 'loading', duration: 2000 });
return false;
} else {
imgNum = 9 - imgNum;
}
wx.chooseMedia({
count: imgNum,
mediaType: ['image'],
sourceType: ['camera'],
success(res) {
const arr = [];
res.tempFiles.forEach(e => {
arr.push(e.tempFilePath);
});
that.setData({
imageList: that.data.imageList.concat(arr)
});
},
fail(res) {
console.log('接口调用失败的回调函数', res);
}
});
},
// 图片预览
handleImagePreview(e) {
const index = e.currentTarget.dataset.idx;
const images = this.data.imageList;
wx.previewImage({
current: images[index], //当前预览的图片
urls: images //所有要预览的图片
});
},
// 删除图片
removeImage(e) {
const that = this;
const imgList = this.data.imageList;
const index = e.currentTarget.dataset.idx;
wx.showModal({
title: '提示',
content: '确定要删除此图片吗?',
success(res) {
if (res.confirm) {
imgList.splice(index, 1);
} else if (res.cancel) {
return false;
}
that.setData({ imageList: imgList });
}
});
},
// wx.uploadFile() 不支持多图片上传。可以封装成 promise
wxUploadFile(filePath) {
let that = this;
return new Promise((resolve, reject) => {
wx.uploadFile({
url: `${config.url.fileServer}/upload`,
filePath,
name: 'file',
formData: { user: 'test' }, // 要传递的参数
method: 'POST',
header: { 'Content-Type': 'multipart/form-data' },
success: resolve,
fail: reject
});
});
},
// 保存提交
submitForm(e) {
const arr = [];
//将选择的图片组成一个Promise数组,准备进行并行上传
for (let path of this.data.imageList) {
arr.push(this.wxUploadFile(path));
}
wx.showLoading({ title: '正在上传...', mask: true });
// 开始并行上传图片
Promise.all(arr)
.then(res => {
// 上传成功,获取这些图片在服务器上的地址,组成一个数组
return res.map(item => JSON.parse(item.data).url);
})
.catch(err => {
console.log('upload images error:', err);
})
.then(urls => {
// 调用保存图片的后端接口
// return saveImages({
// projectID: 1,
// images: urls
// })
})
.then(res => {
// 保存图片成功,返回上一页
const pages = getCurrentPages();
const currPage = pages[pages.length - 1];
const prevPage = pages[pages.length - 2];
wx.navigateBack();
})
.catch(err => {
console.log(err);
})
.then(() => {
wx.hideLoading();
});
}
});
使用 vant 小程序组件库
<van-uploader
file-list="{{ fileList }}"
use-before-read
bind:before-read="beforeRead"
bind:after-read="afterRead"
deletable="{{ true }}"
/>
beforeRead(event) {
const { file, callback } = event.detail
callback(file.type === 'image')
},
afterRead(event) {
const that = this
const { file } = event.detail
wx.uploadFile({
url: `${config.url.apiServer}/manage/file/upload`,
filePath: file.url,
name: 'file',
formData: { businessId: that.data.guid },
header: { 'Content-Type': 'multipart/form-data' },
success(res) {
const data = JSON.parse(res.data)
const kfc = result.data.data
const { fileList = [] } = that.data
let url = kfc.serverUrl
let files = kfc.fileList
files.forEach(f => {
fileList.push({ ...file, url: url + f.fileUrl })
})
that.setData({ fileList })
},
fail(res) {
console.log('error', res)
}
})
}
文件下载
<view style="color: #1990FF" wx:for="{{fileList}}" wx:key="fileUUid" data-url="{{item.fileUrl}}" bindtap="downloadFile">
{{item.name}}
</view>
downloadFile(e) {
const url = this.data.fileServer + e.currentTarget.dataset.url
wx.downloadFile({
url: url,
success(res) {
if (res.statusCode === 200) {
wx.openDocument({
filePath: res.tempFilePath,
showMenu: true,
success(res) {
console.log('打开文档成功')
}
})
}
}
})
}