微信小程序 WeUI 表单封装

# 安装 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;
}


# 效果图

WechatIMG297

WechatIMG298

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值