form.uvue 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. <template>
  2. <cl-page>
  3. <view class="p-3">
  4. <demo-item>
  5. <cl-form
  6. :pt="{
  7. className: 'p-2 pb-0'
  8. }"
  9. v-model="formData"
  10. ref="formRef"
  11. :rules="rules"
  12. :disabled="saving"
  13. label-position="top"
  14. >
  15. <cl-form-item label="头像" prop="avatarUrl" required>
  16. <cl-upload v-model="formData.avatarUrl"></cl-upload>
  17. </cl-form-item>
  18. <cl-form-item label="用户名" prop="nickName" required>
  19. <cl-input v-model="formData.nickName" placeholder="请输入用户名"></cl-input>
  20. </cl-form-item>
  21. <cl-form-item label="邮箱" prop="email">
  22. <cl-input v-model="formData.email" placeholder="请输入邮箱地址"></cl-input>
  23. </cl-form-item>
  24. <cl-form-item label="年龄" prop="age">
  25. <cl-input-number
  26. v-model="formData.age"
  27. :min="18"
  28. :max="50"
  29. ></cl-input-number>
  30. </cl-form-item>
  31. <cl-form-item label="性别" prop="gender">
  32. <cl-select
  33. v-model="formData.gender"
  34. :options="options['gender']"
  35. ></cl-select>
  36. </cl-form-item>
  37. <cl-form-item label="个人简介" prop="description">
  38. <cl-textarea
  39. v-model="formData.description"
  40. placeholder="请输入个人简介"
  41. :maxlength="200"
  42. ></cl-textarea>
  43. </cl-form-item>
  44. </cl-form>
  45. </demo-item>
  46. <demo-item>
  47. <cl-text :pt="{ className: '!text-sm p-2' }">{{
  48. JSON.stringify(formData, null, 4)
  49. }}</cl-text>
  50. </demo-item>
  51. </view>
  52. <cl-footer>
  53. <view class="flex flex-row">
  54. <cl-button type="info" :pt="{ className: 'flex-1' }" @click="reset">重置</cl-button>
  55. <cl-button
  56. type="primary"
  57. :loading="saving"
  58. :pt="{ className: 'flex-1' }"
  59. @click="submit"
  60. >提交</cl-button
  61. >
  62. </view>
  63. </cl-footer>
  64. </cl-page>
  65. </template>
  66. <script setup lang="ts">
  67. import { reactive, ref, type Ref } from "vue";
  68. import DemoItem from "../components/item.uvue";
  69. import { useForm, useUi, type ClFormRule, type ClSelectOption } from "@/uni_modules/cool-ui";
  70. const ui = useUi();
  71. const { formRef, validate, clearValidate } = useForm();
  72. const options = reactive({
  73. gender: [
  74. {
  75. label: "未知",
  76. value: 0
  77. },
  78. {
  79. label: "男",
  80. value: 1
  81. },
  82. {
  83. label: "女",
  84. value: 2
  85. }
  86. ] as ClSelectOption[]
  87. });
  88. type FormData = {
  89. avatarUrl: string;
  90. nickName: string;
  91. email: string;
  92. age: number;
  93. gender: number;
  94. description: string;
  95. pics: string[];
  96. };
  97. // 表单数据
  98. const formData = ref<FormData>({
  99. avatarUrl: "",
  100. nickName: "神仙都没用",
  101. email: "",
  102. age: 18,
  103. gender: 0,
  104. description: "",
  105. pics: []
  106. }) as Ref<FormData>;
  107. // 表单验证规则
  108. const rules = new Map<string, ClFormRule[]>([
  109. ["avatarUrl", [{ required: true, message: "头像不能为空" }]],
  110. [
  111. "nickName",
  112. [
  113. { required: true, message: "用户名不能为空" },
  114. { min: 3, max: 20, message: "用户名长度在3-20个字符之间" }
  115. ]
  116. ],
  117. [
  118. "email",
  119. [
  120. { required: true, message: "邮箱不能为空" },
  121. { pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: "邮箱格式不正确" }
  122. ]
  123. ]
  124. ]);
  125. // 是否保存中
  126. const saving = ref(false);
  127. function reset() {
  128. formData.value.avatarUrl = "";
  129. formData.value.nickName = "";
  130. formData.value.email = "";
  131. formData.value.age = 18;
  132. formData.value.gender = 0;
  133. formData.value.description = "";
  134. formData.value.pics = [];
  135. clearValidate();
  136. }
  137. function submit() {
  138. validate((valid, errors) => {
  139. if (valid) {
  140. saving.value = true;
  141. setTimeout(() => {
  142. ui.showToast({
  143. message: "提交成功",
  144. icon: "check-line"
  145. });
  146. saving.value = false;
  147. reset();
  148. }, 2000);
  149. } else {
  150. ui.showToast({
  151. message: errors[0].message
  152. });
  153. }
  154. });
  155. }
  156. </script>