当前位置:   article > 正文

【小程序】发布商品(上传图片、数据校验)_10rpx

10rpx

效果

1、主要布局

 重点在分类选择器和时间选择器

1-1.分类选择器

使用官方文档的picker标签,传入的数据为一个对象数组,数组中每一个对象包含两个字段

picker 标签的 

value属性:绑定的是一个数组下标index值;

range属性:绑定data里面的分类数组

range-key: 绑定data分类数组的key值,一般为分类名

用法如下

 selectClassify 方法

 1-2、时间选择器

选择picker mode属性为multiSelector,因为微信官方没有提供日期和时间同时选择器,只有日期和时间分开的选择器,因此我们要自己做一个日期时间选择器,因为这个选择器太复杂,这里只给出代码,里面都有详细注释了

首先在util文件下新建一个js文件

  1. function withData(param) {
  2. return param < 10 ? '0' + param : '' + param;
  3. }
  4. //传入月头和月尾的天数,返回一个天数数组
  5. function getLoopArray(start, end) {
  6. var start = start || 0;
  7. var end = end || 1;
  8. var array = [];
  9. for (var i = start; i <= end; i++) {
  10. array.push(withData(i));
  11. }
  12. return array;
  13. }
  14. //获取每个月份对应的天数
  15. function getMonthDay(year, month) {
  16. var flag = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0),
  17. array = null;
  18. switch (month) {
  19. case '01':
  20. case '03':
  21. case '05':
  22. case '07':
  23. case '08':
  24. case '10':
  25. case '12':
  26. array = getLoopArray(1, 31)
  27. break;
  28. case '04':
  29. case '06':
  30. case '09':
  31. case '11':
  32. array = getLoopArray(1, 30)
  33. break;
  34. case '02':
  35. array = flag ? getLoopArray(1, 29) : getLoopArray(1, 28)
  36. break;
  37. default:
  38. array = '月份格式不正确,请重新输入!'
  39. }
  40. return array;
  41. }
  42. //获取当前日期时间用来默认显示在滑动块上面
  43. function getNewDateArry() {
  44. // 当前时间的处理
  45. var newDate = new Date();
  46. var year = withData(newDate.getFullYear()),
  47. mont = withData(newDate.getMonth() + 1),
  48. date = withData(newDate.getDate()),
  49. hour = withData(newDate.getHours()),
  50. minu = withData(newDate.getMinutes()),
  51. seco = withData(newDate.getSeconds());
  52. return [year, mont, date, hour, minu, seco];
  53. }
  54. function dateTimePicker(startYear, endYear, date) {
  55. // 返回默认显示的数组和联动数组的声明
  56. var dateTime = [],
  57. dateTimeArray = [
  58. [],
  59. [],
  60. [],
  61. [],
  62. [],
  63. []
  64. ];
  65. var start = startYear || 1978;
  66. var end = endYear || 2100;
  67. // 默认开始显示数据
  68. var defaultDate = date ? [...date.split(' ')[0].split('-'), ...date.split(' ')[1].split(':')] : getNewDateArry();
  69. // 处理联动列表数据
  70. /*年月日 时分秒*/
  71. dateTimeArray[0] = getLoopArray(start, end);
  72. dateTimeArray[1] = getLoopArray(1, 12);
  73. dateTimeArray[2] = getMonthDay(defaultDate[0], defaultDate[1]);
  74. dateTimeArray[3] = getLoopArray(0, 23);
  75. dateTimeArray[4] = getLoopArray(0, 59);
  76. dateTimeArray[5] = getLoopArray(0, 59);
  77. dateTimeArray.forEach((current, index) => {
  78. dateTime.push(current.indexOf(defaultDate[index]));
  79. });
  80. return {
  81. dateTimeArray: dateTimeArray,
  82. dateTime: dateTime
  83. }
  84. }
  85. //导出函数
  86. module.exports = {
  87. dateTimePicker: dateTimePicker,
  88. getMonthDay: getMonthDay
  89. }

在页面js文件的onLoad函数里面初始化data

 记得先引入dateTimePicker

 选择时间后的处理

  1. //处理选择的时间
  2. changeDateTime(e) {
  3. let dateTimeArray = this.data.dateTimeArray,
  4. {
  5. type,
  6. param
  7. } = e.currentTarget.dataset;
  8. this.setData({
  9. [type]: e.detail.value,
  10. [param]: dateTimeArray[0][e.detail.value[0]] + '-' + dateTimeArray[1][e.detail.value[1]] + '-' + dateTimeArray[2][e.detail.value[2]] + ' ' + dateTimeArray[3][e.detail.value[3]] + ':' + dateTimeArray[4][e.detail.value[4]] + ':' + dateTimeArray[5][e.detail.value[5]]
  11. })
  12. },
  13. //滑动时间触发
  14. changeDateTimeColumn(e) {
  15. var dateArr = this.data.dateTimeArray,
  16. {
  17. type
  18. } = e.currentTarget.dataset,
  19. arr = this.data[type];
  20. arr[e.detail.column] = e.detail.value;
  21. dateArr[2] = dateTimePicker.getMonthDay(dateArr[0][arr[0]], dateArr[1][arr[1]]);
  22. this.setData({
  23. dateTimeArray: dateArr,
  24. [type]: arr
  25. })
  26. }

在wxml页面引入使用时间选择器

 1-3、选择器效果

2、上传图片到云存储

2-1、wx.cloud.upLoadFile 接口

将递归函数整体放进Promise里面

  1. //上传图片到云存储,异步函数,防止图片还没上传,就执行插入云数据库
  2. uploadImages() {
  3. let _this = this
  4. return new Promise(function(resolve,reject){
  5. function upload(index){
  6. wx.showLoading({
  7. title: '上传第' + index + '张图片'
  8. })
  9. console.log(_this.data.selectImgs)
  10. wx.cloud.uploadFile({
  11. cloudPath: 'goodsImgs/' + new Date().getTime() + '_' + Math.floor(Math.random() * 1000) + '.jpg', //给图片命名
  12. filePath: _this.data.selectImgs[index], //本地图片路径
  13. success: (res) => {
  14. console.log('上传成功', res.fileID)
  15. _this.data.uploadImgs[index] = res.fileID
  16. wx.hideLoading({
  17. success: (res) => {},
  18. })
  19. //判断是否全部上传
  20. if (_this.data.selectImgs.length - 1 <= index) {
  21. console.log('已全部上传')
  22. resolve('success')
  23. return
  24. } else {
  25. upload(index + 1)
  26. }
  27. },
  28. fail: (err) => {
  29. reject('error')
  30. wx.showToast({
  31. title: '上传失败,请重新上传',
  32. type: 'none'
  33. })
  34. }
  35. })
  36. }
  37. upload(0)
  38. })
  39. },

3、保存商品数据到云数据库

 3-1、保存数据前的数据校验

我们要校验起拍价是否输入正确,起拍价规定只能是正数,并且第一位不能为0,小数点后面只能输入2位

 还要校验商品描述,因为我是已拍卖形式交易,价高者才可以获得发布者的联系方式,所以不允许用户在发布商品时暴露联系方式

3-2、提交数据

  1. //提交表单,保存商品到云数据库
  2. submit(e) {
  3. let dateEndTime = Date.parse(this.data.end_time_p) / 1000; //转时间戳,精确到毫秒
  4. let goodsName = e.detail.value.name //商品名
  5. let startPrice = e.detail.value.start_price //起拍价
  6. let describe = e.detail.value.describe //商品描述
  7. let publisherId = wx.getStorageSync('userInfo')._id //获取发布者id
  8. let startTime = Math.floor(new Date().getTime() / 1000) //起拍时间默认为当前时间
  9. let classId = this.data.classifys[this.data.objectIndex] // 当前选择的分类
  10. //先上传图片再添加到云数据库
  11. //点击提交的时候再次校验输入是否有误
  12. if (!this.data.isNum || !this.data.checkDescribe) {
  13. wx.showToast({
  14. title: '起拍价或描述输入不符,请重新输入',
  15. icon: 'none'
  16. })
  17. } else {
  18. this.uploadImages().then((resolve, reject) => {
  19. let imagesUrl = this.data.uploadImgs //云存储的图片列表
  20. wx.showLoading({
  21. title: '发布中'
  22. })
  23. setTimeout(() => {}, 500)
  24. wx.cloud.database().collection('goods').add({
  25. data: {
  26. name: goodsName,
  27. start_price: startPrice,
  28. describe: describe,
  29. current_price: startPrice,
  30. images: imagesUrl,
  31. publisher_id: publisherId,
  32. end_time: dateEndTime,
  33. clicks: 0,
  34. class_id: classId,
  35. start_time: startTime,
  36. auctioning: true
  37. },
  38. success: (res) => {
  39. console.log('添加商品')
  40. wx.hideLoading({
  41. success: (res) => {
  42. wx.navigateBack({
  43. delta: 1,
  44. })
  45. },
  46. })
  47. }
  48. })
  49. })
  50. }
  51. },

 4、完整页面和js代码

4-1、wxml

  1. <view class="container">
  2. <scroll-view class="main" scroll-y="true">
  3. <form bindsubmit="submit" bindreset="reset">
  4. <view class="addGoods">
  5. <view>
  6. <label>标题:</label>
  7. <input type="text" name="name" />
  8. </view>
  9. <view>
  10. <label>起拍价:</label>
  11. <input type="number" name="start_price" bindblur="checkPrice"/>
  12. </view>
  13. <view>
  14. <view>
  15. <picker bindchange="selectClassify" value="{{objectIndex}}" range="{{classifys}}" range-key="className">
  16. <view class="picker" style="display: flex;">
  17. 选择分类:{{classifys[objectIndex].className}}
  18. <image src="/image/select.png" style="width: 50rpx;height: 50rpx;"></image>
  19. </view>
  20. </picker>
  21. </view>
  22. </view>
  23. <view>
  24. <label>描述:</label>
  25. <textarea name="describe" bindblur="checkDescribe"></textarea>
  26. </view>
  27. <view>
  28. <picker mode="multiSelector" value="{{end_time}}" data-type="end_time" data-param='end_time_p' bindchange="changeDateTime" bindcolumnchange="changeDateTimeColumn" range="{{dateTimeArray}}">
  29. <view class="selectTime" style="display: flex;">
  30. 结束时间:
  31. <image src="/image/select.png" wx:if="{{!end_time_p}}" style="width: 50rpx;height: 50rpx;"></image>
  32. <text wx:else >{{end_time_p}}</text>
  33. </view>
  34. </picker>
  35. </view>
  36. <view style="display: flex;">
  37. 选择图片:<image src="/image/camera.png" style="width: 60rpx;height: 60rpx;" bindtap="selectImg"></image>
  38. </view>
  39. <view class="selectImg">
  40. <block wx:for="{{selectImgs}}" wx:key="index1">
  41. <image src="{{item}}" style="height: 200rpx;width: 200rpx; margin: 10rpx; border-radius: 7rpx;" data-url="{{item}}"></image>
  42. </block>
  43. </view>
  44. <button form-type="submit" type="primary">提交</button>
  45. <button form-type="reset" type="default">重置</button>
  46. </view>
  47. </form>
  48. </scroll-view>
  49. </view>>

4-2、wxss

  1. .container{
  2. position: fixed;
  3. top: 0;
  4. left: 0;
  5. right: 0;
  6. bottom: 0;
  7. background-color: white
  8. }
  9. .main{
  10. position: fixed;
  11. width: 80%;
  12. top: 5%;
  13. left: 10%;
  14. bottom: 10rpx;
  15. }
  16. .addGoods view{
  17. margin-bottom: 10rpx;
  18. }
  19. .addGoods input{
  20. border: black solid 1px;
  21. min-height: 60rpx;
  22. margin-bottom: 15rpx;
  23. }
  24. .addGoods textarea{
  25. height: 150rpx;
  26. border: black solid 1px;
  27. }
  28. .addGoods button{
  29. margin-top: 20rpx;
  30. }
  31. .selectTime{
  32. margin-top: 15rpx;
  33. }
  34. .selectImg{
  35. display: flex;
  36. flex-wrap: wrap;
  37. height: auto
  38. }

 4-3、js代码

  1. var dateTimePicker = require('../../util/dateTimer.js')
  2. Page({
  3. data: {
  4. end_time: '',
  5. dateTimeArray: '', //时间数组
  6. startYear: 2022, //最小年份
  7. endYear: 2050, // 最大年份
  8. end_time_p: '', //显示的结束时间
  9. classifys: null,
  10. objectIndex: 0, //默认显示位置
  11. selectImgs: null,
  12. uploadImgs: []
  13. },
  14. onLoad(options) {
  15. // 获取完整的年月日 时分秒,以及默认显示的数组
  16. var obj = dateTimePicker.dateTimePicker(this.data.startYear, this.data.endYear)
  17. this.setData({
  18. end_time: obj.dateTime,
  19. dateTimeArray: obj.dateTimeArray,
  20. })
  21. //获取数据库分类信息
  22. wx.cloud.database().collection('classifys').get({
  23. success: (res) => {
  24. this.setData({
  25. classifys: res.data
  26. })
  27. }
  28. })
  29. },
  30. //选择分类
  31. selectClassify(e) {
  32. this.setData({
  33. objectIndex: e.detail.value
  34. })
  35. },
  36. //选择图片
  37. selectImg() {
  38. wx.chooseImage({
  39. count: 9,
  40. success: (res) => {
  41. this.setData({
  42. selectImgs: res.tempFilePaths
  43. })
  44. }
  45. })
  46. },
  47. //上传图片到云存储,异步函数,防止图片还没上传,就执行插入云数据库
  48. uploadImages() {
  49. let _this = this
  50. return new Promise(function (resolve, reject) {
  51. function upload(index) {
  52. var picnum = index+1
  53. wx.showLoading({
  54. title: '上传第' + picnum + '张图片'
  55. })
  56. console.log(_this.data.selectImgs)
  57. wx.cloud.uploadFile({
  58. cloudPath: 'goodsImgs/' + new Date().getTime() + '_' + Math.floor(Math.random() * 1000) + '.jpg', //给图片命名
  59. filePath: _this.data.selectImgs[index], //本地图片路径
  60. success: (res) => {
  61. _this.data.uploadImgs[index] = res.fileID
  62. wx.hideLoading({
  63. success: (res) => {},
  64. })
  65. //判断是否全部上传
  66. if (_this.data.selectImgs.length - 1 <= index) {
  67. console.log('已全部上传')
  68. resolve('success')
  69. return
  70. } else {
  71. upload(index + 1)
  72. }
  73. },
  74. fail: (err) => {
  75. reject('error')
  76. wx.showToast({
  77. title: '上传失败,请重新上传',
  78. type: 'none'
  79. })
  80. }
  81. })
  82. }
  83. upload(0)
  84. })
  85. },
  86. //提交表单,保存商品到云数据库
  87. submit(e) {
  88. let dateEndTime = Date.parse(this.data.end_time_p) / 1000; //转时间戳,精确到毫秒
  89. console.log('time',this.data.end_time_p)
  90. let goodsName = e.detail.value.name //商品名
  91. let startPrice = e.detail.value.start_price //起拍价
  92. let describe = e.detail.value.describe //商品描述
  93. let publisherId = wx.getStorageSync('userInfo')._id //获取发布者id
  94. let startTime = Math.floor(new Date().getTime() / 1000) //起拍时间默认为当前时间
  95. let classId = this.data.classifys[this.data.objectIndex]._id // 当前选择的分类
  96. //先上传图片再添加到云数据库
  97. //点击提交的时候再次校验输入是否有误
  98. if (!this.data.isNum || !this.data.checkDescribe) {
  99. wx.showToast({
  100. title: '起拍价或描述输入不符,请重新输入',
  101. icon: 'none'
  102. })
  103. } else if(goodsName=='' || startPrice==null || classId=='' || this.data.end_time_p=='' || this.data.selectImgs==null){
  104. wx.showToast({
  105. title: '每一项输入信息都不能为空',
  106. icon: 'none'
  107. })
  108. }else{
  109. this.uploadImages().then((resolve, reject) => {
  110. let imagesUrl = this.data.uploadImgs //云存储的图片列表
  111. wx.showLoading({
  112. title: '发布中'
  113. })
  114. setTimeout(() => {}, 500)
  115. wx.cloud.database().collection('goods').add({
  116. data: {
  117. name: goodsName,
  118. start_price: startPrice *1,
  119. describe: describe,
  120. current_price: startPrice *1,
  121. images: imagesUrl,
  122. publisher_id: publisherId,
  123. end_time: dateEndTime,
  124. clicks: 0,
  125. class_id: classId,
  126. start_time: startTime,
  127. auctioning: true
  128. },
  129. success: (res) => {
  130. wx.hideLoading({
  131. success: (res) => {
  132. wx.navigateBack({
  133. delta: 1,
  134. })
  135. },
  136. })
  137. }
  138. })
  139. })
  140. }
  141. },
  142. reset() {
  143. //重置图片和时间
  144. this.setData({
  145. selectImgs: null,
  146. end_time: null,
  147. end_time_p: null
  148. })
  149. },
  150. //处理选择的时间
  151. changeDateTime(e) {
  152. let dateTimeArray = this.data.dateTimeArray,
  153. {
  154. type,
  155. param
  156. } = e.currentTarget.dataset;
  157. this.setData({
  158. [type]: e.detail.value,
  159. [param]: dateTimeArray[0][e.detail.value[0]] + '-' + dateTimeArray[1][e.detail.value[1]] + '-' + dateTimeArray[2][e.detail.value[2]] + ' ' + dateTimeArray[3][e.detail.value[3]] + ':' + dateTimeArray[4][e.detail.value[4]] + ':' + dateTimeArray[5][e.detail.value[5]]
  160. })
  161. },
  162. //滑动时间触发
  163. changeDateTimeColumn(e) {
  164. var dateArr = this.data.dateTimeArray,
  165. {
  166. type
  167. } = e.currentTarget.dataset,
  168. arr = this.data[type];
  169. arr[e.detail.column] = e.detail.value;
  170. dateArr[2] = dateTimePicker.getMonthDay(dateArr[0][arr[0]], dateArr[1][arr[1]]);
  171. this.setData({
  172. dateTimeArray: dateArr,
  173. [type]: arr
  174. })
  175. },
  176. //校验价格输入格式
  177. checkPrice(e) {
  178. let price = e.detail.value
  179. let isNum = /^(([1-9][0-9]*)|(([0]\.\d{1,2}|[1-9][0-9]*\.\d{1,2})))$/
  180. if (isNum.test(price)) {
  181. this.setData({
  182. isNum: true
  183. })
  184. } else {
  185. this.setData({
  186. isNum: false
  187. })
  188. wx.showToast({
  189. title: '起拍价输入有误',
  190. icon: 'none'
  191. })
  192. }
  193. },
  194. //校验描述,不能输入数字,防止透露联系方式
  195. checkDescribe(e) {
  196. let describe = e.detail.value
  197. let notNum = /[0-9]$/
  198. if (notNum.test(describe)) {
  199. wx.showToast({
  200. title: '描述不能含有数字',
  201. icon: 'none'
  202. })
  203. this.setData({
  204. checkDescribe: false
  205. })
  206. } else {
  207. this.setData({
  208. checkDescribe: true
  209. })
  210. }
  211. }
  212. })

发布商品就到这里结束了,期间也发现了好多细节,通过自己踏踏实实的敲每一行代码,真的学到了很多! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/736221
推荐阅读
相关标签
  

闽ICP备14008679号