mirror of https://github.com/ElemeFE/element
				
				
				
			Form: label-width supports width auto (#14944)
							parent
							
								
									e7fdd3dc50
								
							
						
					
					
						commit
						a408b3dd3f
					
				| 
						 | 
				
			
			@ -593,7 +593,7 @@ All components in a Form inherit their `size` attribute from that Form. Similarl
 | 
			
		|||
| rules | validation rules of form | object | — | — |
 | 
			
		||||
| inline | whether the form is inline | boolean | — | false |
 | 
			
		||||
| label-position | position of label. If set to 'left' or 'right', `label-width` prop is also required | string | left / right / top | right |
 | 
			
		||||
| label-width | width of label, and all its direct child form items will inherit this value | string | — | — |
 | 
			
		||||
| label-width    | width of label, e.g. '50px'. All its direct child form items will inherit this value. Width `auto` is supported.        | string | — | — |
 | 
			
		||||
| label-suffix | suffix of the label | string | — | — |
 | 
			
		||||
| hide-required-asterisk | whether required fields should have a red asterisk (star) beside their labels | boolean | — | false |
 | 
			
		||||
| show-message  | whether to show the error message | boolean | — | true |
 | 
			
		||||
| 
						 | 
				
			
			@ -623,7 +623,7 @@ All components in a Form inherit their `size` attribute from that Form. Similarl
 | 
			
		|||
| ---- | ----| ---- | ---- | ---- |
 | 
			
		||||
| prop | a key of `model`. In the use of validate and resetFields method, the attribute is required | string | keys of model that passed to `form` |
 | 
			
		||||
| label | label | string | — | — |
 | 
			
		||||
| label-width | width of label, e.g. '50px' | string | — | — |
 | 
			
		||||
| label-width | width of label, e.g. '50px'. Width `auto` is supported. | string | — | — |
 | 
			
		||||
| required | whether the field is required or not, will be determined by validation rules if omitted | boolean |  — | false |
 | 
			
		||||
| rules | validation rules of form | object | — | — |
 | 
			
		||||
| error | field error message, set its value and the field will validate error and show this message immediately | string | — | — |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -607,7 +607,7 @@ Todos los componentes de un formulario heredan su atributo `size`. De manera sim
 | 
			
		|||
| rules                   | Reglas de validación                     | object  | —                     | —           |
 | 
			
		||||
| inline                  | Si el form es inline                     | boolean | —                     | false       |
 | 
			
		||||
| label-position          | Posicion de la etiqueta                  | string  | left / right / top    | right       |
 | 
			
		||||
| label-width             | ancho de la etiqueta, y todos los form items directos descendientes heredarán este valor | string  | —                     | —           |
 | 
			
		||||
| label-width             | width of label, e.g. '50px'. All its direct child form items will inherit this value. Width `auto` is supported.        | string | — | — |
 | 
			
		||||
| label-suffix            | sufijo de la etiqueta                    | string  | —                     | —           |
 | 
			
		||||
| hide-required-asterisk       | si los campos obligatorios deben tener un asterisco rojo (estrella) al lado de sus etiquetas | boolean | — | false |
 | 
			
		||||
| show-message            | si mostrar o no el mensaje de error      | boolean | —                     | true        |
 | 
			
		||||
| 
						 | 
				
			
			@ -638,7 +638,7 @@ Todos los componentes de un formulario heredan su atributo `size`. De manera sim
 | 
			
		|||
| -------------- | ------------------------------------------------------------ | ------- | ------------------------------------------- | ----------- |
 | 
			
		||||
| prop           | un clave del modelo. En el uso del método validate and resetFields, el atributo es obligatorio. | string  | Clave del modelo que se ha pasado a  `form` |             |
 | 
			
		||||
| label          | etiqueta                                                     | string  | —                                           | —           |
 | 
			
		||||
| label-width    | ancho de la etiqueta, e.g. '50px'                            | string  | —                                           | —           |
 | 
			
		||||
| label-width    | ancho de la etiqueta, e.g. '50px'. Width `auto` is supported | string  | —                                           | —           |
 | 
			
		||||
| required       | si el campo es obligatorio o no, estará determinado por las reglas de validación si se omite. | boolean | —                                           | false       |
 | 
			
		||||
| rules          | reglas de validacion del form                                | object  | —                                           | —           |
 | 
			
		||||
| error          | mensaje de error de campo, establezca su valor y el campo validará el error y mostrará este mensaje inmediatamente. | string  | —                                           | —           |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -592,7 +592,7 @@ Tout les composants d'un formulaire héritent leur attribut `size` de ce formula
 | 
			
		|||
| rules | Règles de validation du formulaire. | object | — | — |
 | 
			
		||||
| inline | Si le formulaire est horizontal. | boolean | — | false |
 | 
			
		||||
| label-position | Position des labels. Si 'left' ou 'right', `label-width` est aussi requis. | string | left / right / top | right |
 | 
			
		||||
| label-width | Largeur des labels, tout les enfants directs hériteront de cette valeur. | string | — | — |
 | 
			
		||||
| label-width | Largeur des labels, tout les enfants directs hériteront de cette valeur. Width `auto` is supported. | string | — | — |
 | 
			
		||||
| label-suffix | Suffixe de labels. | string | — | — |
 | 
			
		||||
| hide-required-asterisk | Si les champs obligatoires doivent avoir une astérisque rouge (étoile) à coté de leurs labels. | boolean | — | false |
 | 
			
		||||
| show-message  | Si le message d'erreur doit apparaître. | boolean | — | true |
 | 
			
		||||
| 
						 | 
				
			
			@ -623,7 +623,7 @@ Tout les composants d'un formulaire héritent leur attribut `size` de ce formula
 | 
			
		|||
| ---- | ----| ---- | ---- | ---- |
 | 
			
		||||
| prop | Une des clés de `model`. Utilisés par les méthodes validate et resetFields. Requis. | string | Clés du model passé à `form`. |
 | 
			
		||||
| label | Le label. | string | — | — |
 | 
			
		||||
| label-width | Largeur du label, e.g. '50px'. | string | — | — |
 | 
			
		||||
| label-width | Largeur du label, e.g. '50px'. Width `auto` is supported. | string | — | — |
 | 
			
		||||
| required | Si le champ est requis ou non. Si omis, sera déterminé par les règles de validation. | boolean |  — | false |
 | 
			
		||||
| rules | Règles de validation du formulaire. | object | — | — |
 | 
			
		||||
| error | Message d'erreur du champ. Si il est modifié, le champ l'affichera immédiatement. | string | — | — |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -588,7 +588,7 @@ W3C 标准中有如下[规定](https://www.w3.org/MarkUp/html-spec/html-spec_8.h
 | 
			
		|||
| rules    | 表单验证规则 | object | — | — |
 | 
			
		||||
| inline    | 行内表单模式 | boolean | — | false |
 | 
			
		||||
| label-position | 表单域标签的位置,如果值为 left 或者 right 时,则需要设置 `label-width` | string |  right/left/top            | right |
 | 
			
		||||
| label-width | 表单域标签的宽度,作为 Form 直接子元素的 form-item 会继承该值 | string | — | — |
 | 
			
		||||
| label-width | 表单域标签的宽度,例如 '50px'。作为 Form 直接子元素的 form-item 会继承该值。支持 `auto`。 | string | — | — |
 | 
			
		||||
| label-suffix | 表单域标签的后缀 | string | — | — |
 | 
			
		||||
| hide-required-asterisk | 是否显示必填字段的标签旁边的红色星号 | boolean | — | false |
 | 
			
		||||
| show-message  | 是否显示校验错误信息 | boolean | — | true |
 | 
			
		||||
| 
						 | 
				
			
			@ -618,7 +618,7 @@ W3C 标准中有如下[规定](https://www.w3.org/MarkUp/html-spec/html-spec_8.h
 | 
			
		|||
|---------- |-------------- |---------- |--------------------------------  |-------- |
 | 
			
		||||
| prop    | 表单域 model 字段,在使用 validate、resetFields 方法的情况下,该属性是必填的 | string    | 传入 Form 组件的 `model` 中的字段 | — |
 | 
			
		||||
| label | 标签文本 | string | — | — |
 | 
			
		||||
| label-width | 表单域标签的的宽度,例如 '50px' | string |       —       | — |
 | 
			
		||||
| label-width | 表单域标签的的宽度,例如 '50px'。支持 `auto`。 | string |       —       | — |
 | 
			
		||||
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | — | false |
 | 
			
		||||
| rules    | 表单验证规则 | object | — | — |
 | 
			
		||||
| error    | 表单域验证错误信息, 设置该值会使表单验证状态变为`error`,并显示该错误信息 | string | — | — |
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,9 +9,13 @@
 | 
			
		|||
    },
 | 
			
		||||
    sizeClass ? 'el-form-item--' + sizeClass : ''
 | 
			
		||||
  ]">
 | 
			
		||||
    <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
 | 
			
		||||
      <slot name="label">{{label + form.labelSuffix}}</slot>
 | 
			
		||||
    </label>
 | 
			
		||||
    <label-wrap
 | 
			
		||||
      :is-auto-width="labelStyle && labelStyle.width === 'auto'"
 | 
			
		||||
      :update-all="form.labelWidth === 'auto'">
 | 
			
		||||
      <label :for="labelFor" class="el-form-item__label" :style="labelStyle" v-if="label || $slots.label">
 | 
			
		||||
        <slot name="label">{{label + form.labelSuffix}}</slot>
 | 
			
		||||
      </label>
 | 
			
		||||
    </label-wrap>
 | 
			
		||||
    <div class="el-form-item__content" :style="contentStyle">
 | 
			
		||||
      <slot></slot>
 | 
			
		||||
      <transition name="el-zoom-in-top">
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +43,7 @@
 | 
			
		|||
  import emitter from 'element-ui/src/mixins/emitter';
 | 
			
		||||
  import objectAssign from 'element-ui/src/utils/merge';
 | 
			
		||||
  import { noop, getPropByPath } from 'element-ui/src/utils/util';
 | 
			
		||||
 | 
			
		||||
  import LabelWrap from './label-wrap';
 | 
			
		||||
  export default {
 | 
			
		||||
    name: 'ElFormItem',
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +81,10 @@
 | 
			
		|||
      },
 | 
			
		||||
      size: String
 | 
			
		||||
    },
 | 
			
		||||
    components: {
 | 
			
		||||
      // use this component to calculate auto width
 | 
			
		||||
      LabelWrap
 | 
			
		||||
    },
 | 
			
		||||
    watch: {
 | 
			
		||||
      error: {
 | 
			
		||||
        immediate: true,
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +116,13 @@
 | 
			
		|||
        if (this.form.labelPosition === 'top' || this.form.inline) return ret;
 | 
			
		||||
        if (!label && !this.labelWidth && this.isNested) return ret;
 | 
			
		||||
        const labelWidth = this.labelWidth || this.form.labelWidth;
 | 
			
		||||
        if (labelWidth) {
 | 
			
		||||
        if (labelWidth === 'auto') {
 | 
			
		||||
          if (this.labelWidth === 'auto') {
 | 
			
		||||
            ret.marginLeft = this.computedLabelWidth;
 | 
			
		||||
          } else if (this.form.labelWidth === 'auto') {
 | 
			
		||||
            ret.marginLeft = this.elForm.autoLabelWidth;
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          ret.marginLeft = labelWidth;
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -167,7 +181,8 @@
 | 
			
		|||
        validateMessage: '',
 | 
			
		||||
        validateDisabled: false,
 | 
			
		||||
        validator: {},
 | 
			
		||||
        isNested: false
 | 
			
		||||
        isNested: false,
 | 
			
		||||
        computedLabelWidth: ''
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    methods: {
 | 
			
		||||
| 
						 | 
				
			
			@ -261,6 +276,9 @@
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        this.validate('change');
 | 
			
		||||
      },
 | 
			
		||||
      updateComputedLabelWidth(width) {
 | 
			
		||||
        this.computedLabelWidth = width ? `${width}px` : '';
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    mounted() {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,9 +54,16 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    computed: {
 | 
			
		||||
      autoLabelWidth() {
 | 
			
		||||
        const max = Math.max(...this.potentialLabelWidthArr);
 | 
			
		||||
        return max ? `${max}px` : '';
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    data() {
 | 
			
		||||
      return {
 | 
			
		||||
        fields: []
 | 
			
		||||
        fields: [],
 | 
			
		||||
        potentialLabelWidthArr: [] // use this array to calculate auto width
 | 
			
		||||
      };
 | 
			
		||||
    },
 | 
			
		||||
    created() {
 | 
			
		||||
| 
						 | 
				
			
			@ -142,6 +149,26 @@
 | 
			
		|||
        fields.forEach(field => {
 | 
			
		||||
          field.validate('', cb);
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      getLabelWidthIndex(width) {
 | 
			
		||||
        const index = this.potentialLabelWidthArr.indexOf(width);
 | 
			
		||||
        // it's impossible
 | 
			
		||||
        if (index === -1) {
 | 
			
		||||
          throw new Error('[ElementForm]unpected width ', width);
 | 
			
		||||
        }
 | 
			
		||||
        return index;
 | 
			
		||||
      },
 | 
			
		||||
      registerLabelWidth(val, oldVal) {
 | 
			
		||||
        if (val && oldVal) {
 | 
			
		||||
          const index = this.getLabelWidthIndex(oldVal);
 | 
			
		||||
          this.potentialLabelWidthArr.splice(index, 1, val);
 | 
			
		||||
        } else if (val) {
 | 
			
		||||
          this.potentialLabelWidthArr.push(val);
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      deregisterLabelWidth(val) {
 | 
			
		||||
        const index = this.getLabelWidthIndex(val);
 | 
			
		||||
        this.potentialLabelWidthArr.splice(index, 1);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
<script>
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  props: {
 | 
			
		||||
    isAutoWidth: Boolean,
 | 
			
		||||
    updateAll: Boolean
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  inject: ['elForm', 'elFormItem'],
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const slots = this.$slots.default;
 | 
			
		||||
    if (!slots) return null;
 | 
			
		||||
    if (this.isAutoWidth) {
 | 
			
		||||
      return (<div class="el-form-item__label-wrap">
 | 
			
		||||
        { slots }
 | 
			
		||||
      </div>);
 | 
			
		||||
    } else {
 | 
			
		||||
      return slots[0];
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  methods: {
 | 
			
		||||
    getLabelWidth() {
 | 
			
		||||
      if (this.$el && this.$el.firstElementChild) {
 | 
			
		||||
        const computedWidth = window.getComputedStyle(this.$el.firstElementChild).width;
 | 
			
		||||
        return Math.ceil(parseFloat(computedWidth));
 | 
			
		||||
      } else {
 | 
			
		||||
        return 0;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    updateLabelWidth(action = 'update') {
 | 
			
		||||
      if (this.$slots.default && this.isAutoWidth && this.$el.firstElementChild) {
 | 
			
		||||
        if (action === 'update') {
 | 
			
		||||
          this.computedWidth = this.getLabelWidth();
 | 
			
		||||
        } else if (action === 'remove') {
 | 
			
		||||
          this.elForm.deregisterLabelWidth(this.computedWidth);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  watch: {
 | 
			
		||||
    computedWidth(val, oldVal) {
 | 
			
		||||
      if (this.updateAll) {
 | 
			
		||||
        this.elForm.registerLabelWidth(val, oldVal);
 | 
			
		||||
        this.elFormItem.updateComputedLabelWidth(val);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      computedWidth: 0
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  mounted() {
 | 
			
		||||
    this.updateLabelWidth('update');
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Is this necessary?
 | 
			
		||||
  // updated() {
 | 
			
		||||
  //   this.updateLabelWidth('update');
 | 
			
		||||
  // },
 | 
			
		||||
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    this.updateLabelWidth('remove');
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -84,6 +84,14 @@
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @include e(label-wrap) {
 | 
			
		||||
    float: left;
 | 
			
		||||
    .el-form-item__label {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      float: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @include e(label) {
 | 
			
		||||
    text-align: right;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { createVue, destroyVM } from '../util';
 | 
			
		||||
import { createVue, destroyVM, waitImmediate } from '../util';
 | 
			
		||||
 | 
			
		||||
const DELAY = 50;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -43,6 +43,43 @@ describe('Form', () => {
 | 
			
		|||
    expect(vm.$el.querySelector('.el-form-item__content').style.marginLeft).to.equal('80px');
 | 
			
		||||
    done();
 | 
			
		||||
  });
 | 
			
		||||
  it('auto label width', async() => {
 | 
			
		||||
    vm = createVue({
 | 
			
		||||
      template: `
 | 
			
		||||
        <el-form ref="form" :model="form" label-width="auto">
 | 
			
		||||
          <el-form-item label="活动名称">
 | 
			
		||||
            <el-input v-model="form.name"></el-input>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
          <el-form-item label="活动备注信息" v-if="display">
 | 
			
		||||
            <el-input v-model="form.name"></el-input>
 | 
			
		||||
          </el-form-item>
 | 
			
		||||
        </el-form>
 | 
			
		||||
      `,
 | 
			
		||||
      data() {
 | 
			
		||||
        return {
 | 
			
		||||
          display: true,
 | 
			
		||||
          form: {
 | 
			
		||||
            name: '',
 | 
			
		||||
            intro: ''
 | 
			
		||||
          }
 | 
			
		||||
        };
 | 
			
		||||
      }
 | 
			
		||||
    }, true);
 | 
			
		||||
 | 
			
		||||
    await waitImmediate();
 | 
			
		||||
 | 
			
		||||
    const formItems = vm.$el.querySelectorAll('.el-form-item__content');
 | 
			
		||||
    const marginLeft = parseInt(formItems[0].style.marginLeft, 10);
 | 
			
		||||
    const marginLeft1 = parseInt(formItems[1].style.marginLeft, 10);
 | 
			
		||||
    expect(marginLeft === marginLeft1).to.be.true;
 | 
			
		||||
 | 
			
		||||
    vm.display = false;
 | 
			
		||||
    await waitImmediate();
 | 
			
		||||
 | 
			
		||||
    const formItem = vm.$el.querySelector('.el-form-item__content');
 | 
			
		||||
    const newMarginLeft = parseInt(formItem.style.marginLeft, 10);
 | 
			
		||||
    expect(newMarginLeft < marginLeft).to.be.true;
 | 
			
		||||
  });
 | 
			
		||||
  it('inline form', done => {
 | 
			
		||||
    vm = createVue({
 | 
			
		||||
      template: `
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue