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,10 +2,15 @@
2 <div :class="wrapClasses"> 2 <div :class="wrapClasses">
3 <template v-if="type !== 'textarea'"> 3 <template v-if="type !== 'textarea'">
4 <div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div> 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 <i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i> 6 <i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
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> 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 <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> 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 <transition name="fade"> 14 <transition name="fade">
10 <i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i> 15 <i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
11 </transition> 16 </transition>
@@ -14,10 +19,10 @@ @@ -14,10 +19,10 @@
14 :autocomplete="autocomplete" 19 :autocomplete="autocomplete"
15 :spellcheck="spellcheck" 20 :spellcheck="spellcheck"
16 ref="input" 21 ref="input"
17 - :type="type" 22 + :type="currentType"
18 :class="inputClasses" 23 :class="inputClasses"
19 :placeholder="placeholder" 24 :placeholder="placeholder"
20 - :disabled="disabled" 25 + :disabled="itemDisabled"
21 :maxlength="maxlength" 26 :maxlength="maxlength"
22 :readonly="readonly" 27 :readonly="readonly"
23 :name="name" 28 :name="name"
@@ -42,46 +47,49 @@ @@ -42,46 +47,49 @@
42 </div> 47 </div>
43 <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> 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 </template> 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 </div> 80 </div>
74 </template> 81 </template>
75 <script> 82 <script>
76 import { oneOf, findComponentUpward } from '../../utils/assist'; 83 import { oneOf, findComponentUpward } from '../../utils/assist';
77 import calcTextareaHeight from '../../utils/calcTextareaHeight'; 84 import calcTextareaHeight from '../../utils/calcTextareaHeight';
78 import Emitter from '../../mixins/emitter'; 85 import Emitter from '../../mixins/emitter';
  86 + import mixinsForm from '../../mixins/form';
79 87
80 const prefixCls = 'ivu-input'; 88 const prefixCls = 'ivu-input';
81 89
82 export default { 90 export default {
83 name: 'Input', 91 name: 'Input',
84 - mixins: [ Emitter ], 92 + mixins: [ Emitter, mixinsForm ],
85 props: { 93 props: {
86 type: { 94 type: {
87 validator (value) { 95 validator (value) {
@@ -106,7 +114,7 @@ @@ -106,7 +114,7 @@
106 default: '' 114 default: ''
107 }, 115 },
108 maxlength: { 116 maxlength: {
109 - type: Number 117 + type: [String, Number]
110 }, 118 },
111 disabled: { 119 disabled: {
112 type: Boolean, 120 type: Boolean,
@@ -172,34 +180,73 @@ @@ -172,34 +180,73 @@
172 enterButton: { 180 enterButton: {
173 type: [Boolean, String], 181 type: [Boolean, String],
174 default: false 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 data () { 200 data () {
178 return { 201 return {
179 currentValue: this.value, 202 currentValue: this.value,
180 prefixCls: prefixCls, 203 prefixCls: prefixCls,
181 - prepend: true,  
182 - append: true,  
183 slotReady: false, 204 slotReady: false,
184 textareaStyles: {}, 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 computed: { 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 wrapClasses () { 237 wrapClasses () {
192 return [ 238 return [
193 `${prefixCls}-wrapper`, 239 `${prefixCls}-wrapper`,
194 { 240 {
195 [`${prefixCls}-wrapper-${this.size}`]: !!this.size, 241 [`${prefixCls}-wrapper-${this.size}`]: !!this.size,
196 - [`${prefixCls}-type`]: this.type, 242 + [`${prefixCls}-type-${this.type}`]: this.type,
197 [`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton), 243 [`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton),
198 [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size, 244 [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size,
199 [`${prefixCls}-group-with-prepend`]: this.prepend, 245 [`${prefixCls}-group-with-prepend`]: this.prepend,
200 [`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton), 246 [`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton),
201 [`${prefixCls}-hide-icon`]: this.append, // #554 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,7 +255,8 @@
208 `${prefixCls}`, 255 `${prefixCls}`,
209 { 256 {
210 [`${prefixCls}-${this.size}`]: !!this.size, 257 [`${prefixCls}-${this.size}`]: !!this.size,
211 - [`${prefixCls}-disabled`]: this.disabled, 258 + [`${prefixCls}-disabled`]: this.itemDisabled,
  259 + [`${prefixCls}-no-border`]: !this.border,
212 [`${prefixCls}-with-prefix`]: this.showPrefix, 260 [`${prefixCls}-with-prefix`]: this.showPrefix,
213 [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false) 261 [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false)
214 } 262 }
@@ -218,9 +266,26 @@ @@ -218,9 +266,26 @@
218 return [ 266 return [
219 `${prefixCls}`, 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 methods: { 291 methods: {
@@ -291,11 +356,24 @@ @@ -291,11 +356,24 @@
291 356
292 this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows); 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 blur () { 379 blur () {
@@ -313,28 +391,43 @@ @@ -313,28 +391,43 @@
313 this.$emit('on-clear'); 391 this.$emit('on-clear');
314 }, 392 },
315 handleSearch () { 393 handleSearch () {
316 - if (this.disabled) return false; 394 + if (this.itemDisabled) return false;
317 this.$refs.input.focus(); 395 this.$refs.input.focus();
318 this.$emit('on-search', this.currentValue); 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 watch: { 416 watch: {
322 value (val) { 417 value (val) {
323 this.setCurrentValue(val); 418 this.setCurrentValue(val);
  419 + },
  420 + type () {
  421 + this.$nextTick(this.handleCalcIconOffset);
324 } 422 }
325 }, 423 },
326 mounted () { 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 this.slotReady = true; 425 this.slotReady = true;
337 this.resizeTextarea(); 426 this.resizeTextarea();
  427 + this.handleCalcIconOffset();
  428 + },
  429 + updated () {
  430 + this.$nextTick(this.handleCalcIconOffset);
338 } 431 }
339 }; 432 };
340 </script> 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 +};