# 安装 WeUI
app.json
app.json
"useExtendedLib": {
"weui": true
}
在项目根目录下新建 components
文件夹,然后在 components
下新建 Form
文件夹
components/Form
# index.json
components/Form/index.json
{
"component": true,
"usingComponents": {
"mp-form": "weui-miniprogram/form/form",
"mp-cells": "weui-miniprogram/cells/cells",
"mp-cell": "weui-miniprogram/cell/cell",
"mp-uploader": "weui-miniprogram/uploader/uploader"
}
}
# index.js
components/Form/index.js
上传方法需要自己修改成你们api的格式
// components/Form/index.js
Component({
options: {
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
/**
* 组件的属性列表
*/
properties: {
// 表单绑定数据,用于初始化
formData: {
type: Object,
value: {}
},
// 表单配置
options: {
type: Array,
value: []
},
// 表单验证规则
rules: {
type: Array,
value: []
},
// 卡片标题
title: {
type: String,
value: ""
}
},
/**
* 组件的初始数据
*/
data: {
fileKey: ""
},
/**
* 组件生命周期函数-在组件布局完成后执行)
*/
ready: function () {
// 初始化表单验证
this.addRules(this.properties.options);
// 初始化上传文件事件
this.setData({
uplaodFile: this.uplaodFile.bind(this)
});
},
/**
* 组件的方法列表
*/
methods: {
// 初始化表单验证
addRules(options) {
for (let i = 0; i < options.length; i++) {
// 判断用户是否已经自定义验证了
var result = this.data.rules.some(function (item) {
if (item.name == options[i].key) {
return true;
}
});
// 如果没有自定义就执行
if (!result) {
// 动态生成验证方法
let data = {
name: options[i].key,
rules: {
required: options[i].rules ? true : false,
message: options[i].title + "是必填项"
}
};
// 动态添加验证规则
let index = this.data.rules.length;
this.setData({
[`rules[${index}]`]: data
});
}
}
},
// 表单发生改变事件
formInputChange(e) {
// 获取key
const { field } = e.currentTarget.dataset;
// 动态修改值
this.setData({
[`formData.${field}`]: e.detail.value
});
},
// 表单验证
validate() {
// 验证结果
let isValidate = false;
// 开始验证
this.selectComponent("#form").validate((valid, errors) => {
if (!valid) {
// 验证不过
// console.log('valid', valid, errors);
const firstError = Object.keys(errors);
if (firstError.length) {
wx.showToast({
icon: "error",
title: errors[firstError[0]].message
});
}
} else {
// 验证通过
isValidate = true;
}
});
// 返回验证结果
return isValidate;
},
// 临时存储图片上传指定的key
formFileChange(event) {
this.setData({
fileKey: event.currentTarget.dataset.field
});
},
// 图片上传
uplaodFile(files) {
// console.log('upload files', files);
const tempFilePaths = files.tempFilePaths[0];
// 文件上传的函数,返回一个promise
return new Promise((resolve, reject) => {
wx.uploadFile({
url: "url",
filePath: tempFilePaths,
name: "file",
header: {
"content-type": "multipart/form-data"
},
success: res => {
// res.data 是由你们后端返回的相关数据
const data = JSON.parse(res.data);
console.log(data);
let urls = [data.data];
// 格式: {urls: ["后端返回的图片地址"]}
resolve({
urls: urls
});
},
fial: () => {
reject("error");
}
});
});
},
// 图片上传成功
uploadSuccess(e) {
console.log(e.detail);
// 获取图片指定的key
const field = this.data.fileKey;
let data = [
{
url: e.detail.urls[0]
}
];
// 动态赋值图片指定key的数据
this.setData({
[`formData.${field}`]: data
});
// console.log('upload success', e.detail);
}
}
});
# index.wxml
components/Form/index.wxml
<!--components/Form/index.wxml-->
<view>
<mp-form id="form" rules="{{rules}}" models="{{formData}}">
<mp-cells title="{{title}}">
<mp-cell
prop="{{item.key}}"
title="{{item.title}}"
wx:for="{{options}}"
wx:key="index"
>
<view wx:if="{{item.slot}}">
<slot name="{{item.key}}"></slot>
</view>
<view wx:else>
<input
type="text"
wx:if="{{item.type === 'text'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindinput="formInputChange"
data-field="{{item.key}}"
class="weui-input"
placeholder="请输入{{item.title}}"
/>
<textarea
wx:if="{{item.type === 'textarea'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindblur="formInputChange"
data-field="{{item.key}}"
auto-height
placeholder="请输入{{item.title}}"
/>
<input
type="number"
wx:if="{{item.type === 'number'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindinput="formInputChange"
data-field="{{item.key}}"
class="weui-input"
placeholder="请输入{{item.title}}"
/>
<input
type="idcard"
wx:if="{{item.type === 'idcard'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindinput="formInputChange"
data-field="{{item.key}}"
class="weui-input"
placeholder="请输入{{item.title}}"
/>
<input
type="digit"
wx:if="{{item.type === 'digit'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindinput="formInputChange"
data-field="{{item.key}}"
class="weui-input"
placeholder="请输入{{item.title}}"
/>
<input
type="text"
password
wx:if="{{item.type === 'password'}}"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindinput="formInputChange"
data-field="{{item.key}}"
class="weui-input"
placeholder="请输入{{item.title}}"
/>
<switch
bindchange="formInputChange"
checked="{{formData[item.key]}}"
data-field="{{item.key}}"
wx:if="{{item.type === 'switch'}}"
disabled="{{item.disabled}}"
/>
<picker
data-field="{{item.key}}"
wx:if="{{item.type === 'date'}}"
disabled="{{item.disabled}}"
mode="date"
value="{{formData[item.key]}}"
bindchange="formInputChange"
>
<view
class="weui-input"
style="color: #808080;"
wx:if="{{!formData[item.key]}}"
>请选择{{ item.title }}</view
>
<view class="weui-input" wx:else>{{ formData[item.key] }}</view>
</picker>
<picker
data-field="{{item.key}}"
wx:if="{{item.type === 'time'}}"
mode="time"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindchange="formInputChange"
placeholder="请选择{{item.title}}"
>
<view
class="weui-input"
style="color: #808080;"
wx:if="{{!formData[item.key]}}"
>请选择{{ item.title }}</view
>
<view class="weui-input" wx:else>{{ formData[item.key] }}</view>
</picker>
<picker
data-field="{{item.key}}"
wx:if="{{item.type === 'region'}}"
mode="region"
disabled="{{item.disabled}}"
value="{{formData[item.key]}}"
bindchange="formInputChange"
>
<view
class="weui-input"
style="color: #808080;"
wx:if="{{!formData[item.key]}}"
>请选择{{ item.title }}</view
>
<view class="weui-input" wx:else>{{ formData[item.key] }}</view>
</picker>
<picker
data-field="{{item.key}}"
wx:if="{{item.type === 'selector'}}"
mode="selector"
disabled="{{item.disabled}}"
range="{{item.option.data}}"
range-key="{{item.option.props.key}}"
value="{{formData[item.key]}}"
bindchange="formInputChange"
>
<view
class="weui-input"
style="color: #808080;"
wx:if="{{!formData[item.key]}}"
>请选择{{ item.title }}</view
>
<view class="weui-input" wx:elif="{{item.option.props.key}}">
{{
item.option.data[formData[item.key]][item.option.props.key]
}}</view
>
<view class="weui-input" wx:else>{{
item.option.data[formData[item.key]]
}}</view>
</picker>
<mp-uploader
bindtap="formFileChange"
bindsuccess="uploadSuccess"
upload="{{uplaodFile}}"
files="{{formData[item.key]}}"
title=""
wx:if="{{item.type === 'file'}}"
data-field="{{item.key}}"
class="weui-input"
>
</mp-uploader>
</view>
</mp-cell>
</mp-cells>
</mp-form>
</view>
# index.wxss
components/Form/index.wxss
/* components/Form/index.wxss */
# 参数说明
属性 | 描述 | 默认值 | 必需 |
---|---|---|---|
formData | 表单绑定数据,用于初始化 | {} | 是 |
options | 表单配置 | [] | 是 |
rules | 表单验证规则 | [] | 否 |
title | 卡片标题 | “” | 否 |
# options
属性 | 描述 | 必需 |
---|---|---|
title | 表单表头 | 是 |
key | 表单对应的字段 | 是 |
type | 控件类型 | 是 |
rules | 是否开启验证 | 否 |
option | 表单配置 | 否 |
disabled | 禁用 | 否 |
slot | 开启自定义控件 | 否 |
如果开启了
slot
,一定要指定好slot="需要自定义的字段"
# type
属性 | 描述 |
---|---|
selector | 选择框 |
text | 文本输入框 |
textarea | 文本域 |
number | 数字 |
idcard | 身份证 |
digit | 小数点 |
password | 密码 |
switch | 开关 |
date | 日期 |
time | 时间 |
region | 地区选择 |
file | 图片上传 |
# option
只有在
type
为[selector]
时才需要设置
属性 | 描述 | 必需 |
---|---|---|
data | 数据源 | 是 |
props | 配置 | 是 |
# props
如果是普通选择框无需设置
属性 | 描述 | 必需 |
---|---|---|
Key | 指定对象选择框的显示字段 | 是 |
# 方法
属性 | 描述 | 回调函数 |
---|---|---|
validate() | 表单验证 | isValidate |
# 页面使用
test.json
pages/test/test.json
引入封装自定义组件
{
"usingComponents": {
"my-form": "/components/Form"
},
"navigationBarTitleText": "测试页面"
}
test.js
pages/test/test.js
// pages/test/test.js
Page({
/**
* 页面的初始数据
*/
data: {
myFormData: {
formData: {
1: "",
2: "",
3: "",
4: "",
5: "",
6: "",
7: "",
8: "",
9: "",
10: "",
11: "",
12: "",
13: ""
},
options: [{
title: "对象选择框",
key: "1",
type: "selector",
rules: true,
option: {
data: [{
id: 1,
name: "选项1"
},
{
id: 2,
name: "选项2"
},
{
id: 3,
name: "选项3"
},
{
id: 4,
name: "选项4"
}
],
props: {
key: "name"
}
}
},
{
title: "普通选择框",
key: "2",
type: "selector",
rules: true,
option: {
data: ["选项1", "选项2", "选项3"]
}
},
{
title: "文本",
key: "3",
type: "text",
rules: true
},
{
title: "文本域",
key: "4",
type: "textarea",
rules: true
},
{
title: "数字",
key: "5",
type: "number",
rules: true
},
{
title: "身份证",
key: "6",
type: "idcard",
rules: true
},
{
title: "小数点",
key: "7",
type: "digit",
rules: true
},
{
title: "密码",
key: "8",
type: "password",
rules: true
},
{
title: "开关",
key: "9",
type: "switch",
rules: true
},
{
title: "日期",
key: "10",
type: "date",
rules: true
},
{
title: "时间",
key: "11",
type: "time",
rules: true
},
{
title: "地区选择",
key: "12",
type: "region",
rules: true
},
{
title: "图片上传",
key: "13",
type: "file",
rules: true
}
],
rules: []
},
},
// 提交表单
submitForm() {
// 获取组件对象
const myForm = this.selectComponent("#my-form");
// 调用验证方法
if (myForm.validate()) {
console.log(myForm.data.formData);
}
}
})
test.wxml
pages/test/test.wxml
<!--pages/test/test.wxml-->
<view class="main">
<my-form id="my-form" rules="{{myFormData.rules}}" formData="{{myFormData.formData}}" options="{{myFormData.options}}"
title="这是标题"></my-form>
<view class="weui-btn-area">
<button class="weui-btn" type="primary" bindtap="submitForm">立刻创建</button>
</view>
</view>
test.wxss
pages/test/test.wxss
/* pages/test/test.wxss */
.main {
padding: 5vh 0;
}