Skip to content

表单组件

表单组件是用户交互的重要部分,uni-app 提供了丰富的表单组件,用于采集和提交用户输入的数据。

表单组件列表

button 按钮

按钮组件,用于触发操作。

属性说明

属性名类型默认值说明
sizeStringdefault按钮的大小,可选值:default、mini
typeStringdefault按钮的样式类型,可选值:primary、default、warn
plainBooleanfalse按钮是否镂空,背景色透明
disabledBooleanfalse是否禁用
loadingBooleanfalse名称前是否带 loading 图标
form-typeString用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件
open-typeString开放能力,不同平台有不同的支持度
hover-classStringbutton-hover指定按钮按下去的样式类

示例代码

vue
<template>
  <view>
    <button type="primary">主要按钮</button>
    <button type="default">默认按钮</button>
    <button type="warn">警告按钮</button>
    <button type="primary" loading>加载中按钮</button>
    <button type="primary" disabled>禁用按钮</button>
    <button type="primary" plain>镂空按钮</button>
  </view>
</template>

checkbox 多选框

多选框组件,用于选择。

属性说明

属性名类型默认值说明
valueStringcheckbox 标识
disabledBooleanfalse是否禁用
checkedBooleanfalse当前是否选中
colorColorcheckbox 的颜色

示例代码

vue
<template>
  <view>
    <checkbox-group @change="checkboxChange">
      <label v-for="item in items" :key="item.value">
        <checkbox :value="item.value" :checked="item.checked" />
        {{item.name}}
      </label>
    </checkbox-group>
  </view>
</template>

<script>
export default {
  data() {
    return {
      items: [
        {value: 'USA', name: '美国', checked: false},
        {value: 'CHN', name: '中国', checked: true},
        {value: 'JPN', name: '日本', checked: false}
      ]
    }
  },
  methods: {
    checkboxChange(e) {
      console.log(e.detail.value)
    }
  }
}
</script>

input 输入框

输入框组件,用于文本输入。

属性说明

属性名类型默认值说明
valueString输入框的初始内容
typeStringtextinput 的类型,可选值:text、number、idcard、digit、password
passwordBooleanfalse是否是密码类型
placeholderString输入框为空时占位符
placeholder-styleString指定 placeholder 的样式
disabledBooleanfalse是否禁用
maxlengthNumber140最大输入长度
focusBooleanfalse获取焦点
confirm-typeStringdone设置键盘右下角按钮的文字,可选值:send、search、next、go、done

示例代码

vue
<template>
  <view>
    <input type="text" placeholder="请输入用户名" v-model="username" />
    <input type="password" placeholder="请输入密码" v-model="password" />
    <input type="number" placeholder="请输入年龄" v-model="age" />
  </view>
</template>

<script>
export default {
  data() {
    return {
      username: '',
      password: '',
      age: ''
    }
  }
}
</script>

picker 选择器

选择器组件,支持普通选择器、多列选择器、时间选择器、日期选择器。

普通选择器

vue
<template>
  <view>
    <picker :range="array" @change="bindPickerChange">
      <view class="picker">
        当前选择:{{array[index]}}
      </view>
    </picker>
  </view>
</template>

<script>
export default {
  data() {
    return {
      array: ['中国', '美国', '日本', '韩国'],
      index: 0
    }
  },
  methods: {
    bindPickerChange(e) {
      this.index = e.detail.value
    }
  }
}
</script>

时间选择器

vue
<template>
  <view>
    <picker mode="time" :value="time" start="09:00" end="18:00" @change="bindTimeChange">
      <view class="picker">
        当前选择:{{time}}
      </view>
    </picker>
  </view>
</template>

<script>
export default {
  data() {
    return {
      time: '12:00'
    }
  },
  methods: {
    bindTimeChange(e) {
      this.time = e.detail.value
    }
  }
}
</script>

日期选择器

vue
<template>
  <view>
    <picker mode="date" :value="date" start="2015-09-01" end="2025-09-01" @change="bindDateChange">
      <view class="picker">
        当前选择:{{date}}
      </view>
    </picker>
  </view>
</template>

<script>
export default {
  data() {
    return {
      date: '2021-09-01'
    }
  },
  methods: {
    bindDateChange(e) {
      this.date = e.detail.value
    }
  }
}
</script>

radio 单选框

单选框组件,用于单选。

属性说明

属性名类型默认值说明
valueStringradio 标识
checkedBooleanfalse当前是否选中
disabledBooleanfalse是否禁用
colorColorradio 的颜色

示例代码

vue
<template>
  <view>
    <radio-group @change="radioChange">
      <label v-for="item in items" :key="item.value">
        <radio :value="item.value" :checked="item.checked" />
        {{item.name}}
      </label>
    </radio-group>
  </view>
</template>

<script>
export default {
  data() {
    return {
      items: [
        {value: 'USA', name: '美国', checked: false},
        {value: 'CHN', name: '中国', checked: true},
        {value: 'JPN', name: '日本', checked: false}
      ]
    }
  },
  methods: {
    radioChange(e) {
      console.log(e.detail.value)
    }
  }
}
</script>

slider 滑动选择器

滑动选择器,用于选择一个数值。

属性说明

属性名类型默认值说明
minNumber0最小值
maxNumber100最大值
stepNumber1步长,取值必须大于 0,并且可被(max - min)整除
disabledBooleanfalse是否禁用
valueNumber0当前取值
show-valueBooleanfalse是否显示当前 value
activeColorColor#1aad19已选择的颜色
backgroundColorColor#e9e9e9背景条的颜色
block-sizeNumber28滑块的大小,取值范围为 12 - 28
block-colorColor#ffffff滑块的颜色

示例代码

vue
<template>
  <view>
    <slider value="50" @change="sliderChange" show-value />
  </view>
</template>

<script>
export default {
  methods: {
    sliderChange(e) {
      console.log('slider value 发生变化:' + e.detail.value)
    }
  }
}
</script>

switch 开关选择器

开关选择器,用于切换选中状态。

属性说明

属性名类型默认值说明
checkedBooleanfalse是否选中
disabledBooleanfalse是否禁用
typeStringswitch样式,有效值:switch, checkbox
colorColorswitch 的颜色

示例代码

vue
<template>
  <view>
    <switch checked @change="switchChange" />
    <switch type="checkbox" />
  </view>
</template>

<script>
export default {
  methods: {
    switchChange(e) {
      console.log('switch 发生 change 事件,携带值为', e.detail.value)
    }
  }
}
</script>

textarea 多行输入框

多行输入框,用于多行文本输入。

属性说明

属性名类型默认值说明
valueString输入框的内容
placeholderString输入框为空时占位符
placeholder-styleString指定 placeholder 的样式
disabledBooleanfalse是否禁用
maxlengthNumber140最大输入长度
focusBooleanfalse获取焦点
auto-heightBooleanfalse是否自动增高
fixedBooleanfalse如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true

示例代码

vue
<template>
  <view>
    <textarea placeholder="请输入留言" v-model="message" auto-height />
  </view>
</template>

<script>
export default {
  data() {
    return {
      message: ''
    }
  }
}
</script>

form 表单

表单容器,用于将表单组件内的用户输入的数据提交。

属性说明

属性名类型默认值说明
report-submitBooleanfalse是否返回 formId 用于发送模板消息

示例代码

vue
<template>
  <view>
    <form @submit="formSubmit" @reset="formReset">
      <view class="form-item">
        <text>姓名:</text>
        <input name="name" placeholder="请输入姓名" />
      </view>
      <view class="form-item">
        <text>年龄:</text>
        <input name="age" placeholder="请输入年龄" />
      </view>
      <view class="form-buttons">
        <button type="primary" form-type="submit">提交</button>
        <button form-type="reset">重置</button>
      </view>
    </form>
  </view>
</template>

<script>
export default {
  methods: {
    formSubmit(e) {
      console.log('form发生了submit事件,携带数据为:', e.detail.value)
    },
    formReset(e) {
      console.log('form发生了reset事件')
    }
  }
}
</script>

<style>
.form-item {
  display: flex;
  margin-bottom: 10px;
}
.form-buttons {
  display: flex;
  justify-content: space-around;
  margin-top: 20px;
}
</style>

表单校验

在实际应用中,表单校验是非常重要的一环。uni-app 可以结合第三方表单校验库(如 async-validator)或自定义校验逻辑来实现表单校验。

使用 async-validator 进行表单校验

vue
<template>
  <view class="container">
    <form @submit="submitForm">
      <view class="form-item">
        <text class="label">用户名:</text>
        <input v-model="formData.username" placeholder="请输入用户名" />
        <text v-if="errors.username" class="error">{{errors.username[0]}}</text>
      </view>
      <view class="form-item">
        <text class="label">邮箱:</text>
        <input v-model="formData.email" placeholder="请输入邮箱" />
        <text v-if="errors.email" class="error">{{errors.email[0]}}</text>
      </view>
      <view class="form-item">
        <text class="label">年龄:</text>
        <input v-model="formData.age" type="number" placeholder="请输入年龄" />
        <text v-if="errors.age" class="error">{{errors.age[0]}}</text>
      </view>
      <button type="primary" form-type="submit">提交</button>
    </form>
  </view>
</template>

<script>
import Schema from 'async-validator';

export default {
  data() {
    return {
      formData: {
        username: '',
        email: '',
        age: ''
      },
      errors: {}
    }
  },
  methods: {
    submitForm() {
      // 定义校验规则
      const rules = {
        username: [
          { required: true, message: '请输入用户名' },
          { min: 3, max: 20, message: '用户名长度在 3 到 20 个字符' }
        ],
        email: [
          { required: true, message: '请输入邮箱' },
          { type: 'email', message: '请输入正确的邮箱格式' }
        ],
        age: [
          { required: true, message: '请输入年龄' },
          { type: 'number', message: '年龄必须为数字' },
          { min: 18, max: 100, message: '年龄必须在 18 到 100 之间' }
        ]
      };
      
      // 创建校验器
      const validator = new Schema(rules);
      
      // 执行校验
      validator.validate(this.formData, (errors, fields) => {
        if (errors) {
          // 校验失败,显示错误信息
          this.errors = fields;
        } else {
          // 校验通过,清空错误信息
          this.errors = {};
          // 提交表单数据
          uni.showToast({
            title: '提交成功',
            icon: 'success'
          });
          console.log('表单数据:', this.formData);
        }
      });
    }
  }
}
</script>

<style>
.container {
  padding: 20px;
}
.form-item {
  margin-bottom: 20px;
}
.label {
  display: block;
  margin-bottom: 5px;
}
.error {
  color: #f00;
  font-size: 12px;
  margin-top: 5px;
}
</style>

最佳实践

  1. 表单数据统一管理:将表单数据统一放在 data 中管理,便于提交和校验。
  2. 合理使用双向绑定:使用 v-model 进行双向数据绑定,简化数据处理。
  3. 分组管理复杂表单:对于复杂表单,可以将其拆分为多个小组件,分别管理。
  4. 表单校验前端先行:在提交到服务器前,先在前端进行数据校验,减轻服务器压力。
  5. 友好的错误提示:提供清晰、具体的错误提示,帮助用户快速修正输入。
  6. 适配不同平台:注意表单组件在不同平台上的表现差异,做好兼容处理。
  7. 合理使用 placeholder:提供有意义的占位符文本,引导用户输入。
  8. 考虑无障碍设计:为表单元素添加适当的标签和描述,提高可访问性。

常见问题

1. 表单组件在不同平台上的差异

uni-app 的表单组件在不同平台上可能存在差异,特别是在样式和交互方面。建议在开发时多测试,确保在各平台上都有良好的表现。

2. 键盘遮挡输入框

在移动端,当用户点击输入框时,键盘弹出可能会遮挡输入框。可以通过调整页面布局或使用 adjust-position 属性来解决。

3. 表单数据的重置

使用 form 组件的 reset 事件可以方便地重置表单数据,但需要注意的是,这只会重置表单组件的值,不会重置绑定的数据模型。如果需要同时重置数据模型,需要在 reset 事件处理函数中手动重置。

4. 表单提交时的防重复提交

为了防止用户多次点击提交按钮导致重复提交,可以在提交时禁用提交按钮,等待服务器响应后再启用。

vue
<template>
  <view>
    <form @submit="submitForm">
      <!-- 表单内容 -->
      <button type="primary" form-type="submit" :disabled="submitting">
        {{submitting ? '提交中...' : '提交'}}
      </button>
    </form>
  </view>
</template>

<script>
export default {
  data() {
    return {
      submitting: false
    }
  },
  methods: {
    submitForm() {
      if (this.submitting) return;
      
      this.submitting = true;
      
      // 模拟提交请求
      setTimeout(() => {
        uni.showToast({
          title: '提交成功',
          icon: 'success'
        });
        this.submitting = false;
      }, 2000);
    }
  }
}
</script>

相关链接

一次开发,多端部署 - 让跨平台开发更简单