Commit 75460ce6bd017f5243cb72b4ffb586bf1b325f4f

Authored by FEI
1 parent 1af66c20

input upgrade

Showing 2 changed files with 164 additions and 57 deletions   Show diff stats
src/components/input/input.vue
... ... @@ -2,10 +2,15 @@
2 2 <div :class="wrapClasses">
3 3 <template v-if="type !== 'textarea'">
4 4 <div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
5   - <i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue && !disabled" @click="handleClear"></i>
  5 + <i class="ivu-icon" :class="['ivu-icon-ios-close-circle', prefixCls + '-icon', prefixCls + '-icon-clear' , prefixCls + '-icon-normal']" v-if="clearable && currentValue && !itemDisabled" @click="handleClear" :style="clearableStyles"></i>
6 6 <i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
7 7 <i class="ivu-icon ivu-icon-ios-search" :class="[prefixCls + '-icon', prefixCls + '-icon-normal', prefixCls + '-search-icon']" v-else-if="search && enterButton === false" @click="handleSearch"></i>
8 8 <span class="ivu-input-suffix" v-else-if="showSuffix"><slot name="suffix"><i class="ivu-icon" :class="['ivu-icon-' + suffix]" v-if="suffix"></i></slot></span>
  9 + <span class="ivu-input-word-count" v-else-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
  10 + <span class="ivu-input-suffix" v-else-if="password" @click="handleToggleShowPassword">
  11 + <i class="ivu-icon ivu-icon-ios-eye-outline" v-if="showPassword"></i>
  12 + <i class="ivu-icon ivu-icon-ios-eye-off-outline" v-else></i>
  13 + </span>
9 14 <transition name="fade">
10 15 <i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
11 16 </transition>
... ... @@ -14,10 +19,10 @@
14 19 :autocomplete="autocomplete"
15 20 :spellcheck="spellcheck"
16 21 ref="input"
17   - :type="type"
  22 + :type="currentType"
18 23 :class="inputClasses"
19 24 :placeholder="placeholder"
20   - :disabled="disabled"
  25 + :disabled="itemDisabled"
21 26 :maxlength="maxlength"
22 27 :readonly="readonly"
23 28 :name="name"
... ... @@ -42,46 +47,49 @@
42 47 </div>
43 48 <span class="ivu-input-prefix" v-else-if="showPrefix"><slot name="prefix"><i class="ivu-icon" :class="['ivu-icon-' + prefix]" v-if="prefix"></i></slot></span>
44 49 </template>
45   - <textarea
46   - v-else
47   - :id="elementId"
48   - :wrap="wrap"
49   - :autocomplete="autocomplete"
50   - :spellcheck="spellcheck"
51   - ref="textarea"
52   - :class="textareaClasses"
53   - :style="textareaStyles"
54   - :placeholder="placeholder"
55   - :disabled="disabled"
56   - :rows="rows"
57   - :maxlength="maxlength"
58   - :readonly="readonly"
59   - :name="name"
60   - :value="currentValue"
61   - :autofocus="autofocus"
62   - @keyup.enter="handleEnter"
63   - @keyup="handleKeyup"
64   - @keypress="handleKeypress"
65   - @keydown="handleKeydown"
66   - @focus="handleFocus"
67   - @blur="handleBlur"
68   - @compositionstart="handleComposition"
69   - @compositionupdate="handleComposition"
70   - @compositionend="handleComposition"
71   - @input="handleInput">
72   - </textarea>
  50 + <template v-else>
  51 + <textarea
  52 + :id="elementId"
  53 + :wrap="wrap"
  54 + :autocomplete="autocomplete"
  55 + :spellcheck="spellcheck"
  56 + ref="textarea"
  57 + :class="textareaClasses"
  58 + :style="textareaStyles"
  59 + :placeholder="placeholder"
  60 + :disabled="itemDisabled"
  61 + :rows="rows"
  62 + :maxlength="maxlength"
  63 + :readonly="readonly"
  64 + :name="name"
  65 + :value="currentValue"
  66 + :autofocus="autofocus"
  67 + @keyup.enter="handleEnter"
  68 + @keyup="handleKeyup"
  69 + @keypress="handleKeypress"
  70 + @keydown="handleKeydown"
  71 + @focus="handleFocus"
  72 + @blur="handleBlur"
  73 + @compositionstart="handleComposition"
  74 + @compositionupdate="handleComposition"
  75 + @compositionend="handleComposition"
  76 + @input="handleInput">
  77 + </textarea>
  78 + <span class="ivu-input-word-count" v-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
  79 + </template>
73 80 </div>
74 81 </template>
75 82 <script>
76 83 import { oneOf, findComponentUpward } from '../../utils/assist';
77 84 import calcTextareaHeight from '../../utils/calcTextareaHeight';
78 85 import Emitter from '../../mixins/emitter';
  86 + import mixinsForm from '../../mixins/form';
79 87  
80 88 const prefixCls = 'ivu-input';
81 89  
82 90 export default {
83 91 name: 'Input',
84   - mixins: [ Emitter ],
  92 + mixins: [ Emitter, mixinsForm ],
85 93 props: {
86 94 type: {
87 95 validator (value) {
... ... @@ -106,7 +114,7 @@
106 114 default: ''
107 115 },
108 116 maxlength: {
109   - type: Number
  117 + type: [String, Number]
110 118 },
111 119 disabled: {
112 120 type: Boolean,
... ... @@ -172,34 +180,73 @@
172 180 enterButton: {
173 181 type: [Boolean, String],
174 182 default: false
  183 + },
  184 + // 4.0.0
  185 + showWordLimit: {
  186 + type: Boolean,
  187 + default: false
  188 + },
  189 + // 4.0.0
  190 + password: {
  191 + type: Boolean,
  192 + default: false
  193 + },
  194 + // 4.5.0
  195 + border: {
  196 + type: Boolean,
  197 + default: true
175 198 }
176 199 },
177 200 data () {
178 201 return {
179 202 currentValue: this.value,
180 203 prefixCls: prefixCls,
181   - prepend: true,
182   - append: true,
183 204 slotReady: false,
184 205 textareaStyles: {},
185   - showPrefix: false,
186   - showSuffix: false,
187   - isOnComposition: false
  206 + isOnComposition: false,
  207 + showPassword: false,
  208 + clearableIconOffset: 0
188 209 };
189 210 },
190 211 computed: {
  212 + currentType () {
  213 + let type = this.type;
  214 + if (type === 'password' && this.password && this.showPassword) type = 'text';
  215 + return type;
  216 + },
  217 + prepend () {
  218 + let state = false;
  219 + if (this.type !== 'textarea') state = this.$slots.prepend !== undefined;
  220 + return state;
  221 + },
  222 + append () {
  223 + let state = false;
  224 + if (this.type !== 'textarea') state = this.$slots.append !== undefined;
  225 + return state;
  226 + },
  227 + showPrefix () {
  228 + let state = false;
  229 + if (this.type !== 'textarea') state = this.prefix !== '' || this.$slots.prefix !== undefined;
  230 + return state;
  231 + },
  232 + showSuffix () {
  233 + let state = false;
  234 + if (this.type !== 'textarea') state = this.suffix !== '' || this.$slots.suffix !== undefined;
  235 + return state;
  236 + },
191 237 wrapClasses () {
192 238 return [
193 239 `${prefixCls}-wrapper`,
194 240 {
195 241 [`${prefixCls}-wrapper-${this.size}`]: !!this.size,
196   - [`${prefixCls}-type`]: this.type,
  242 + [`${prefixCls}-type-${this.type}`]: this.type,
197 243 [`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton),
198 244 [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size,
199 245 [`${prefixCls}-group-with-prepend`]: this.prepend,
200 246 [`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton),
201 247 [`${prefixCls}-hide-icon`]: this.append, // #554
202   - [`${prefixCls}-with-search`]: (this.search && this.enterButton)
  248 + [`${prefixCls}-with-search`]: (this.search && this.enterButton),
  249 + [`${prefixCls}-wrapper-disabled`]: this.itemDisabled // #685
203 250 }
204 251 ];
205 252 },
... ... @@ -208,7 +255,8 @@
208 255 `${prefixCls}`,
209 256 {
210 257 [`${prefixCls}-${this.size}`]: !!this.size,
211   - [`${prefixCls}-disabled`]: this.disabled,
  258 + [`${prefixCls}-disabled`]: this.itemDisabled,
  259 + [`${prefixCls}-no-border`]: !this.border,
212 260 [`${prefixCls}-with-prefix`]: this.showPrefix,
213 261 [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false)
214 262 }
... ... @@ -218,9 +266,26 @@
218 266 return [
219 267 `${prefixCls}`,
220 268 {
221   - [`${prefixCls}-disabled`]: this.disabled
  269 + [`${prefixCls}-disabled`]: this.itemDisabled,
  270 + [`${prefixCls}-no-border`]: !this.border
222 271 }
223 272 ];
  273 + },
  274 + upperLimit () {
  275 + return this.maxlength;
  276 + },
  277 + textLength () {
  278 + if (typeof this.value === 'number') {
  279 + return String(this.value).length;
  280 + }
  281 +
  282 + return (this.value || '').length;
  283 + },
  284 + clearableStyles () {
  285 + const style = {};
  286 + let offset = this.clearableIconOffset;
  287 + if (offset) style.transform = `translateX(-${offset}px)`;
  288 + return style;
224 289 }
225 290 },
226 291 methods: {
... ... @@ -291,11 +356,24 @@
291 356  
292 357 this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
293 358 },
294   - focus () {
295   - if (this.type === 'textarea') {
296   - this.$refs.textarea.focus();
297   - } else {
298   - this.$refs.input.focus();
  359 + focus (option) {
  360 + const $el = this.type === 'textarea' ? this.$refs.textarea : this.$refs.input;
  361 + $el.focus(option);
  362 + // Selection content
  363 + const { cursor } = option || {};
  364 + if (cursor) {
  365 + const len = $el.value.length;
  366 +
  367 + switch (cursor) {
  368 + case 'start':
  369 + $el.setSelectionRange(0, 0);
  370 + break;
  371 + case 'end':
  372 + $el.setSelectionRange(len, len);
  373 + break;
  374 + default:
  375 + $el.setSelectionRange(0, len);
  376 + }
299 377 }
300 378 },
301 379 blur () {
... ... @@ -313,28 +391,43 @@
313 391 this.$emit('on-clear');
314 392 },
315 393 handleSearch () {
316   - if (this.disabled) return false;
  394 + if (this.itemDisabled) return false;
317 395 this.$refs.input.focus();
318 396 this.$emit('on-search', this.currentValue);
  397 + },
  398 + handleToggleShowPassword () {
  399 + if (this.itemDisabled) return false;
  400 + this.showPassword = !this.showPassword;
  401 + this.focus();
  402 + const len = this.currentValue.length;
  403 + setTimeout(() => {
  404 + this.$refs.input.setSelectionRange(len, len);
  405 + }, 0);
  406 + },
  407 + handleCalcIconOffset () {
  408 + const $el = this.$el.querySelectorAll('.ivu-input-group-append')[0];
  409 + if ($el) {
  410 + this.clearableIconOffset = $el.offsetWidth;
  411 + } else {
  412 + this.clearableIconOffset = 0;
  413 + }
319 414 }
320 415 },
321 416 watch: {
322 417 value (val) {
323 418 this.setCurrentValue(val);
  419 + },
  420 + type () {
  421 + this.$nextTick(this.handleCalcIconOffset);
324 422 }
325 423 },
326 424 mounted () {
327   - if (this.type !== 'textarea') {
328   - this.prepend = this.$slots.prepend !== undefined;
329   - this.append = this.$slots.append !== undefined;
330   - this.showPrefix = this.prefix !== '' || this.$slots.prefix !== undefined;
331   - this.showSuffix = this.suffix !== '' || this.$slots.suffix !== undefined;
332   - } else {
333   - this.prepend = false;
334   - this.append = false;
335   - }
336 425 this.slotReady = true;
337 426 this.resizeTextarea();
  427 + this.handleCalcIconOffset();
  428 + },
  429 + updated () {
  430 + this.$nextTick(this.handleCalcIconOffset);
338 431 }
339 432 };
340 433 </script>
... ...
src/mixins/form.js 0 → 100644
  1 +export default {
  2 + inject: {
  3 + FormInstance: {
  4 + default: ''
  5 + }
  6 + },
  7 + computed: {
  8 + itemDisabled () {
  9 + let state = this.disabled;
  10 + if (!state && this.FormInstance) state = this.FormInstance.disabled;
  11 + return state;
  12 + }
  13 + }
  14 +};
... ...