Form: label-width supports width auto (#14944)

pull/14950/head
hetech 2019-04-03 11:56:49 +08:00 committed by GitHub
parent e7fdd3dc50
commit a408b3dd3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 177 additions and 16 deletions

View File

@ -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 | — | — |

View File

@ -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 | — | — |

View File

@ -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 | — | — |

View File

@ -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 | — | — |

View File

@ -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() {

View File

@ -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);
}
}
};

View File

@ -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>

View File

@ -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;

View File

@ -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: `