diff --git a/examples/docs/en-US/form.md b/examples/docs/en-US/form.md index 036c8614c..ffd7b4ddd 100644 --- a/examples/docs/en-US/form.md +++ b/examples/docs/en-US/form.md @@ -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 | — | — | diff --git a/examples/docs/es/form.md b/examples/docs/es/form.md index ba23d6d70..c1adeb8aa 100644 --- a/examples/docs/es/form.md +++ b/examples/docs/es/form.md @@ -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 | — | — | diff --git a/examples/docs/fr-FR/form.md b/examples/docs/fr-FR/form.md index 1a50f0d67..1342c6113 100644 --- a/examples/docs/fr-FR/form.md +++ b/examples/docs/fr-FR/form.md @@ -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 | — | — | diff --git a/examples/docs/zh-CN/form.md b/examples/docs/zh-CN/form.md index e3c0f539f..3bf150f0e 100644 --- a/examples/docs/zh-CN/form.md +++ b/examples/docs/zh-CN/form.md @@ -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 | — | — | diff --git a/packages/form/src/form-item.vue b/packages/form/src/form-item.vue index e55967d2c..800dfc330 100644 --- a/packages/form/src/form-item.vue +++ b/packages/form/src/form-item.vue @@ -9,9 +9,13 @@ }, sizeClass ? 'el-form-item--' + sizeClass : '' ]"> - + + +
@@ -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() { diff --git a/packages/form/src/form.vue b/packages/form/src/form.vue index f6dc0e94e..23a6d24b2 100644 --- a/packages/form/src/form.vue +++ b/packages/form/src/form.vue @@ -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); } } }; diff --git a/packages/form/src/label-wrap.vue b/packages/form/src/label-wrap.vue new file mode 100644 index 000000000..36d0d008f --- /dev/null +++ b/packages/form/src/label-wrap.vue @@ -0,0 +1,71 @@ + diff --git a/packages/theme-chalk/src/form.scss b/packages/theme-chalk/src/form.scss index 786f1e54b..802a1178e 100644 --- a/packages/theme-chalk/src/form.scss +++ b/packages/theme-chalk/src/form.scss @@ -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; diff --git a/test/unit/specs/form.spec.js b/test/unit/specs/form.spec.js index a719e291e..c3f6edd0b 100644 --- a/test/unit/specs/form.spec.js +++ b/test/unit/specs/form.spec.js @@ -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: ` + + + + + + + + + `, + 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: `