自定义组件怎么能像input一样嵌入form表单中, 使用其校验功能(ant vue)

使用 ant vue UI框架时, form表单时常用的组件之一.
内部可以嵌入如 input, select 等子组件, 可以配置字段校验.
但是, 有时, 已有一些组件无法满足需求, 就需要自定义组件作为 form-item.
可是自定义组件怎么还可以用 form 的校验和提示功能呢?

==== 更新 & 解答 2020年3月24日 ====
经过测试发现, 不用任何特殊处理, 自定义组件可直接嵌入 <a-from-item> 中享受form表单的校验功能.

注意:

  1. props.value + $emit('change')事件结合(重要).
  2. value 不可设置默认值, 否则报警告: xxx default valuecan not collect, please useoption.initialValueto set default value.`

测试代码InputX, a-input的包装.

  1. '编辑'和'预览'两种模式切换;
  2. 预览时内容可控制长度, 超过部分自动隐藏(依赖自定义组件 Ellipsis).

先看效果图:
image.png

演示代码:

    <a-form @submit.prevent="searchQuery" :form="form">
      <a-form-item label="Tag">
        <a-input placeholder="请输入tag名称" v-decorator="[ 'tag', {rules: [{ required: true, message: '请输入tag名称'}]}]"></a-input>
      </a-form-item>
      <a-form-item label="创建人">
        <a-input placeholder="请输入创建人名称" v-decorator="[ 'createBy']"></a-input>
      </a-form-item>
      <a-form-item>
        <InputX placeholder="inputx" v-decorator="[ 'inputx', {rules: [{ required: true, message: '请输入inputx'}]}]"></InputX>
      </a-form-item>
    </a-form>
    <div class="drawer-bootom-button">
      <a-button @click="handleSubmit" type="primary">提交</a-button>
    </div>

InputX 代码:

<!-- 点击可编辑  -- dafei 2020/1/20 17:38 -->
<template>
    <div>
      <div class="inputx-item">
        <span class="inputx-label" v-if="label">{{label}}</span>
        <div>
          <div :style="`display: inline-block; width:100%`" @click="handleClick" v-show="viewMode">
            <Ellipsis :length="length" :style="`display: inline-block`">{{valueX}}</Ellipsis>
            <a-icon v-if="editIcon && !valueX" style="margin-left: 8px;" type="edit" @click="handleClick"/>
          </div>
          <div v-show="!viewMode">
            <a-input ref="editor" v-model="valueX" @blur="handleBlur"
                     :class="validateMsg?'validate-fail':''"
                     @change="handleChange" @keyup="handleKeyUp($event)"
                     @keyup.enter="handleEnter"></a-input>
          </div>
          <span v-if="validateMsg" class="warn-tip">{{validateMsg}}</span>
        </div>
      </div>
    </div>
</template>

<script>
  import Ellipsis from "@comp/Ellipsis/Ellipsis";
  export default {
    name: "InputX",
    components:{Ellipsis},
    props:{
      defaultValue:{
        type:[String,Number],
        default: "",
      },
      value:{
        type: [String, Number],
        // default: ""
      },
      // width:{
      //   type:Number,
      //   default:120,
      // },
      length: {
        type: Number,
        default: 40,
      },
      editable:{
        type:Boolean,
        default:false,
      },
      required:{
        type:Boolean,
        default:false,
      },
      /**入参: value; 出参: 校验结果消息, 为null表示校验通过*/
      validateRule:{
        type:Function,
        required:false,
      },
      label:{
        type:String,
        required:false,
      },
      /**独立模式: 点击对否触发编辑; 失去焦点编辑完成*/
      alone: {
        type:Boolean,
        default:true,
      },
      editIcon:{
        type: Boolean,
        default: true,
      }
    },
    watch:{
      value(n) {
        this.valueX = n;
      },
      editable(n) {
        if (n == true) {
          this.enableEdit();
        } else {
          this.disableEdit();
        }
      }
    },
    data() {
      return {
        valueX:this.value || this.defaultValue,
        viewMode:!this.editable,
        validateMsg: undefined,
      }
    },
    mounted() {
      if (this.editable) {
        this.validate();
      }
    },
    methods:{
      handleClick() {
        if (this.alone) {
          this.enableEdit();
        }
      },
      handleBlur() {
        if (this.alone) {
          this.handleOk();
        }
      },
      enableEdit() {
        this.viewMode = false;
        this.$nextTick(() => { this.$refs.editor.focus()})
        this.validate();
      },
      disableEdit() {
        this.viewMode = true;
        this.validateMsg = null;
      },
      handleEnter() {
        // 孤立模式下, 才开启回车快捷键
        if (this.alone) {
          this.handleOk();
        }
      },
      handleOk(e) {
        if (!this.validateMsg) {
          this.disableEdit();
          this.$emit("ok", this.valueX);
        }
      },
      handleChange() {
        this.$emit('change', this.valueX);
      },
      handleKeyUp(e) {
        // '' 时, 保持编辑状态

        this.validate();
      },
      validate() {
        // 校验
        if (this.validateRule != null) {
          this.validateMsg = this.validateRule(this.valueX);
        }
        this.$emit('validate', this.validateMsg ? false : true);
      }
    },
    model: {
      prop: 'value',
      event: 'change'
    }
  }
</script>

<style scoped>
  .warn-tip{
    color: #f5222d;
    font-size: 14px;
    position: absolute;
  }
  .validate-fail{
    border-color: #f5222d;
    /*box-shadow:0 0 4px #f5222d;*/
  }
  .inputx-label{
    margin-right: 8px;
  }
  .inputx-item{
    display: flex;
    align-items: center;
  }
  /*.inputx-required{*/
  /*  display: inline-block;*/
  /*  margin-right: 4px;*/
  /*  color: #f5222d;*/
  /*  font-size: 14px;*/
  /*  font-family: SimSun, sans-serif;*/
  /*  line-height: 1;*/
  /*  content: '*';*/
  /*}*/
</style>
阅读 909
评论
    1 个回答
    • 167

    props.value+$emit('change')事件结合, 放入 <a-form-item> 中自动生效.

      撰写回答

      登录后参与交流、获取后续更新提醒

      相似问题
      推荐文章