小程序 template 玩转内容填写

在小程序开发过程中,很多地方会用到一些相同的需要输入的表弟页面,具体类型有输入单行文字、多行文字、使用单选框选择、使用对话框输入时间、拍摄图片等。这些东西实际都不难,可以抽象起来使用,下面简单说说。

先看看效果

在这里插入图片描述

这是简单用法

在这里插入图片描述

这是选择日期,使用的是有赞的

在这里插入图片描述

这个稍微复杂一些,图片支持添加、长按删除以及多图预览

看看代码

  • WXML
<template name="input"><view class="item"><view class="title">{{title}}view><view class="text"><input maxlength='{{length}}' value="{{input}}" type="{{inputType}}" data-order="{{order}}"bindinput="inputText" placeholder="{{hint}}" />view>view>
template><template name="radio"><view class="item"><view class="title">{{title}}view><view class="radio-container"><van-radio-group direction="horizontal" value="{{input}}" data-order="{{order}}"bind:change="onSelectRadio"><van-radio wx:for='{{items}}' wx:key='this' data-index='{{index}}' name="{{index}}" icon-size="40rpx"custom-class=""><text class="text">{{item}}text>van-radio>van-radio-group>view>view>
template><template name="select"><view class="item"><view class="title">{{title}}view><view class="row-center text" data-order="{{order}}" bindtap="showPopup"><text class="flex1">{{input==''?hint:input}}text><van-icon name="arrow" size="32rpx" color="#949494FF" />view>view>
template><template name="photos"><view class="item"><view class="title">{{title}}view><view class="photo-container row"><view wx:for='{{images}}' wx:key='this' data-index='{{index}}' data-photos="{{images}}" bindtap="previewImage"><van-image radius='16rpx' width="112rpx" height="112rpx" custom-class="margin-right-24" src="{{item.url}}"data-index="{{index}}" data-order="{{order}}" bindlongpress="deletePhoto" />view><view wx:if="{{images.length" class="row-center img-add-item" data-order="{{order}}" bindtap="takePhoto"><van-icon name="plus" size="48rpx" color="#C9C9C9FF"/>view>view>view>
template><template name="textarea"><view class="item" style="border-top:{{}}"><view class="title">{{title}}view><view class="text"><textarea class="textarea" maxlength='{{length}}' value="{{input}}" data-order="{{order}}"bindinput="inputText" placeholder="{{hint}}" />view>view>
template><view class="container" style="height:{{containerHeight}}rpx"><block wx:for='{{forms}}' wx:key='this' data-index='{{index}}'><view wx:if="{{item.groupStart}}" class="margin-top-24" /><template is="{{item.type==0?'input':item.type==1?'radio':item.type==2?'select':item.type==3?'photos':'textarea'}}" data="{{...item}}" /><view wx:if="{{index!=forms.length-1}}" class="divider">view>block>
view><button class="button" style="margin-bottom:{{bottomHeight}}rpx;margin-top:24rpx" bind:tap="submit">提交button><van-popup round show="{{ showPop }}" position="bottom" custom-style="height: 40%;overflow: hidden;"bind:close="hidePopup"><van-datetime-picker type="date" value="{{ currentDate }}" min-date="{{ minDate }}" max-date="{{ maxDate }}"bind:cancel="hidePopup" bind:confirm="selectTime" />
van-popup><van-dialog id="van-dialog" confirm-button-color="#0B7BFBFF" />

这里定义了五种类型的填写 template,使用循环渲染出来,每个类型会判断是否要分组,即增加上边距,下面加了一条分割线。还有就是底部提交的按钮,一个日期选取对话框,一个函数调用的有赞对话框。

有赞的组件具体看下说明吧,不多说,至于 containerHeight 和 bottomHeight 两个适配的值,可以看看我自定义底部导航栏的博客,不说第三遍了。

  • WXSS
.container {overflow: scroll;box-sizing: border-box;
}.item {box-sizing: border-box;background: white;padding: 24rpx 32rpx;
}.divider{height: 2rpx;margin-left: 32rpx;background: #E5E5E5;
}.title {font-size: 30rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #2E2E2E;line-height: 42rpx;
}.text {margin-top: 22rpx;font-size: 32rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #949494;line-height: 44rpx;margin-right: 24rpx;
}.textarea {width: 100%;max-height: 144rpx;overflow: scroll;
}.radio-container{margin-top: 22rpx;
}.photo-container{margin-top: 22rpx;box-sizing: border-box;
}.img-add-item {width: 108rpx;height: 108rpx;border-radius: 16rpx;box-sizing: border-box;border: 2rpx solid #E5E5E5;padding: 0 30rpx;
}.button {width: 686rpx;height: 96rpx;background: #0B7BFB;border-radius: 12rpx;overflow: hidden;box-sizing: border-box;font-size: 36rpx;font-family: PingFangSC-Regular, PingFang SC;font-weight: 400;color: #FFFFFF;line-height: 96rpx;
}

样式没什么说的,containerHeight 值的使用是希望中间部分内容能够滚动。

  • Page.js
import Dialog from '../../../../../miniprogram_npm/@vant/weapp/dialog/dialog';
var app = getApp()Page({data: {//底部高度bottomHeight: app.globalData.bottomHeight,//容器高度 = 屏幕高度 - 顶部高度 - 底部高度 - 底部按钮栏高度 - 24rpx的paddingcontainerHeight: app.globalData.screenHeight - app.globalData.topHeight - app.globalData.bottomHeight - 96 - 24,forms: [{order: 0,type: 0,typeName: 'item',title: "姓名",hint: "请输入姓名",length: 14,inputType: "text",input: ""}, {order: 1,type: 1,typeName: 'radio',title: "性别",hint: "请选择性别",items: ['男', '女'],input: -1}, {order: 2,type: 2,typeName: 'select',title: "出生日期",hint: "请选择出生年月",input: ""}, {order: 3,type: 0,length: 18,typeName: 'item',title: "身份证号码",hint: "请输入身份证号码",inputType: 'text',input: ""}, {order: 4,type: 2,typeName: 'select',title: "起始有效期",hint: "请选择起始有效期",input: ""}, {order: 5,type: 2,typeName: 'select',title: "截止有效期",hint: "请选择截止有效期",input: ""}, {order: 6,type: 3,typeName: 'photos',title: "身份证正反面(按顺序)",hint: "请按顺序选择身份证正反面",uploadPhotos: [],delAtts: [],imagesNumb: 2,images: [//   {//   url: 'https://img.yzcdn.cn/vant/cat.jpeg'// }],input: ""}],showPop: false,minDate: new Date(1911, 10, 1).getTime(),maxDate: new Date(2111, 10, 1).getTime(),currentDate: new Date().getTime(),selectOrder: -1},inputText: function (event) {var temp = this.data.forms;let order = event.currentTarget.dataset.order;temp[order].input = event.detail.value;this.setData({forms: temp,});},onSelectRadio: function (event) {var temp = this.data.forms;let order = event.currentTarget.dataset.order;temp[order].input = event.detail;this.setData({forms: temp,});},showPopup(event) {this.setData({selectOrder: event.currentTarget.dataset.order,showPop: true});},hidePopup() {this.setData({showPop: false});},selectTime: function (event) {var temp = this.data.forms;temp[this.data.selectOrder].input = util.formatDate(event.detail);this.setData({forms: temp,});this.hidePopup();},takePhoto(e) {var that = this;let order = e.currentTarget.dataset.order;let photoForms = this.data.forms[order]if (photoForms.images.length >= photoForms.imagesNumb) {app.showErrToast("数量过多")}wx.chooseImage({sizeType: ['compressed'],sourceType: ['album', 'camera'],success: function (res) {app.log(res.tempFilePaths[0]);let photo = {attId: -1,ext: 'png',form: 'local',url: res.tempFilePaths[0]}photoForms.images.push(photo)that.setData({forms: that.data.forms})}})},previewImage(e) {let photos = e.currentTarget.dataset.photoslet urls = []photos.forEach(element => {urls.push(element.url)});wx.previewImage({urls: urls,})},deletePhoto(e) {var that = this;let order = e.currentTarget.dataset.order;let index = e.currentTarget.dataset.indexlet photoForms = this.data.forms[order]Dialog.confirm({title: '删除图片',message: '是否删除所选图片?',}).then(() => {// on confirmlet photo = photoForms.images[index]photoForms.images.splice(index, 1)that.setData({forms: that.data.forms})})},submit() {//自行编写}
})

这里代码较多,但是不难,一个是适配的数据,一个是 forms 信息,还有就是对应的操作函数,下面详细讲讲。

表单数据

私有数据内的 forms 字段,有两个功能,一是用来控制页面显示数据,而是填写内容,内容存放在 input 字段内,图片内容放在 images 数组中。

控制字段中 order 用来标志顺序,当然传数据进 template 的时候把 index 传进去也是可以的,这里写死是为了后面填写内容。type 用来判断 template 类型,title 就是标题了,input 是填写内容,inputType 用来限制输入类型(根据官方文档填写),length 用来限制输入长度,其他属性可以按需要随便加。

inputType 填写

https://developers.weixin.qq.com/miniprogram/dev/component/input.html

文本输入

文本输入使用 inputText 函数,这里没有使用双向绑定是因为,当弹出对话框的时候双向绑定会丢失数据,没法用。

单选输入

单选使用 onSelectRadio 函数,值存在 event.detail 中。

选择时间

选择时间用到了 showPopup、hidePopup、selectTime三个函数,但是逻辑很简单,在 showPopup 函数里面要确定选择的 template 的 order 值,并填写到全局变量中,当点击对话框中确定按钮选中时间的时候,根据全局变量的 order 再去修改对应 forms 的 input 值。

图片功能

图片这里设计到拍摄图片、删除图片、预览图片。

这里拍摄图片给了两种选择来源:相册和拍照,并且拿到图片路径后并没有直接存到 images 数组里面,而是构建了一个对象,把链接放在对象里面,如果需要在提交的时候需要先上传图片,并把图片链接换成网络链接,对象的唯一性可是很方便的。

预览图片可以直接传入一个字符串数组,因为我们的图片存在对象里面,需要转换一下。

删除图片这里只是找到对应的图片,从数组里面移除了,实际上如果这些图片里面包含网络图片和本地新添加的图片,应该在回调里面分别处理的。

结语

初始化数据和收集数据的代码我没写,根据 order 值去改和拿就可以。有一点要注意的就是input 可以直接覆盖数据,但是 images 里面别总用 push,应该考虑考虑清除不需要的图片,不然图片多了就不对了。

end

完美撒花


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部