quanyawei
2024-01-11 da25434b85fc5b4321c429bf95e719d00ec395bb
uni_modules/uview-ui/components/u-form-item/u-form-item.vue
New file
@@ -0,0 +1,235 @@
<template>
   <view class="u-form-item">
      <view
         class="u-form-item__body"
         @tap="clickHandler"
         :style="[$u.addStyle(customStyle), {
            flexDirection: (labelPosition || parentData.labelPosition) === 'left' ? 'row' : 'column'
         }]"
      >
         <!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" -->
         <slot name="label">
            <!-- {{required}} -->
            <view
               class="u-form-item__body__left"
               v-if="required || leftIcon || label"
               :style="{
                  width: $u.addUnit(labelWidth || parentData.labelWidth),
                  marginBottom: parentData.labelPosition === 'left' ? 0 : '5px',
               }"
            >
               <!-- 为了块对齐 -->
               <view class="u-form-item__body__left__content">
                  <!-- nvue不支持伪元素before -->
                  <text
                     v-if="required"
                     class="u-form-item__body__left__content__required"
                  >*</text>
                  <view
                     class="u-form-item__body__left__content__icon"
                     v-if="leftIcon"
                  >
                     <u-icon
                        :name="leftIcon"
                        :custom-style="leftIconStyle"
                     ></u-icon>
                  </view>
                  <text
                     class="u-form-item__body__left__content__label"
                     :style="[parentData.labelStyle, {
                        justifyContent: parentData.labelAlign === 'left' ? 'flex-start' : parentData.labelAlign === 'center' ? 'center' : 'flex-end'
                     }]"
                  >{{ label }}</text>
               </view>
            </view>
         </slot>
         <view class="u-form-item__body__right">
            <view class="u-form-item__body__right__content">
               <view class="u-form-item__body__right__content__slot">
                  <slot />
               </view>
               <view
                  class="item__body__right__content__icon"
                  v-if="$slots.right"
               >
                  <slot name="right" />
               </view>
            </view>
         </view>
      </view>
      <slot name="error">
         <text
            v-if="!!message && parentData.errorType === 'message'"
            class="u-form-item__body__right__message"
            :style="{
               marginLeft:  $u.addUnit(parentData.labelPosition === 'top' ? 0 : (labelWidth || parentData.labelWidth))
            }"
         >{{ message }}</text>
      </slot>
      <u-line
         v-if="borderBottom"
         :color="message && parentData.errorType === 'border-bottom' ? $u.color.error : propsLine.color"
         :customStyle="`margin-top: ${message && parentData.errorType === 'message' ? '5px' : 0}`"
      ></u-line>
   </view>
</template>
<script>
   import props from './props.js';
   /**
    * Form 表单
    * @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
    * @tutorial https://www.uviewui.com/components/form.html
    * @property {String}         label         input的label提示语
    * @property {String}         prop         绑定的值
    * @property {String | Boolean}   borderBottom   是否显示表单域的下划线边框
    * @property {String | Number}   labelWidth      label的宽度,单位px
    * @property {String}         rightIcon      右侧图标
    * @property {String}         leftIcon      左侧图标
    * @property {String | Object} leftIconStyle 左侧图标的样式
    * @property {Boolean}         required      是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置 (默认 false )
    *
    * @example <u-form-item label="姓名" prop="userInfo.name" borderBottom ref="item1"></u-form-item>
    */
   export default {
      name: 'u-form-item',
      mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
      data() {
         return {
            // 错误提示语
            message: '',
            parentData: {
               // 提示文本的位置
               labelPosition: 'left',
               // 提示文本对齐方式
               labelAlign: 'left',
               // 提示文本的样式
               labelStyle: {},
               // 提示文本的宽度
               labelWidth: 45,
               // 错误提示方式
               errorType: 'message'
            }
         }
      },
      // 组件创建完成时,将当前实例保存到u-form中
      computed: {
         propsLine() {
            return uni.$u.props.line
         }
      },
      mounted() {
         this.init()
      },
      methods: {
         init() {
            // 父组件的实例
            this.updateParentData()
            if (!this.parent) {
               uni.$u.error('u-form-item需要结合u-form组件使用')
            }
         },
         // 获取父组件的参数
         updateParentData() {
            // 此方法写在mixin中
            this.getParentData('u-form');
         },
         // 移除u-form-item的校验结果
         clearValidate() {
            this.message = null
         },
         // 清空当前的组件的校验结果,并重置为初始值
         resetField() {
            // 找到原始值
            const value = uni.$u.getProperty(this.parent.originalModel, this.prop)
            // 将u-form的model的prop属性链还原原始值
            uni.$u.setProperty(this.parent.model, this.prop, value)
            // 移除校验结果
            this.message = null
         },
         // 点击组件
         clickHandler() {
            this.$emit('click')
         }
      },
   }
</script>
<style lang="scss" scoped>
   @import "../../libs/css/components.scss";
   .u-form-item {
      @include flex(column);
      font-size: 14px;
      color: $u-main-color;
      &__body {
         @include flex;
         padding: 10px 0;
         &__left {
            @include flex;
            align-items: center;
            &__content {
               position: relative;
               @include flex;
               align-items: center;
               padding-right: 10rpx;
               flex: 1;
               &__icon {
                  margin-right: 8rpx;
               }
               &__required {
                  position: absolute;
                  left: -9px;
                  color: $u-error;
                  line-height: 20px;
                  font-size: 20px;
                  top: 3px;
               }
               &__label {
                  @include flex;
                  align-items: center;
                  flex: 1;
                  color: $u-main-color;
                  font-size: 15px;
               }
            }
         }
         &__right {
            flex: 1;
            &__content {
               @include flex;
               align-items: center;
               flex: 1;
               &__slot {
                  flex: 1;
                  /* #ifndef MP */
                  @include flex;
                  align-items: center;
                  /* #endif */
               }
               &__icon {
                  margin-left: 10rpx;
                  color: $u-light-color;
                  font-size: 30rpx;
               }
            }
            &__message {
               font-size: 12px;
               line-height: 12px;
               color: $u-error;
            }
         }
      }
   }
</style>