123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395 |
- <template>
- <div :class="wrapClasses">
- <template v-if="type !== 'textarea'">
- <div :class="[prefixCls + '-group-prepend']" v-if="prepend" v-show="slotReady"><slot name="prepend"></slot></div>
- <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"></i>
- <i class="ivu-icon" :class="['ivu-icon-' + icon, prefixCls + '-icon', prefixCls + '-icon-normal']" v-else-if="icon" @click="handleIconClick"></i>
- <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>
- <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>
- <span class="ivu-input-word-count" v-else-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
- <span class="ivu-input-suffix" v-else-if="password" @click="handleToggleShowPassword">
- <i class="ivu-icon ivu-icon-ios-eye-off-outline" v-if="showPassword"></i>
- <i class="ivu-icon ivu-icon-ios-eye-outline" v-else></i>
- </span>
- <transition name="fade">
- <i class="ivu-icon ivu-icon-ios-loading ivu-load-loop" :class="[prefixCls + '-icon', prefixCls + '-icon-validate']" v-if="!icon"></i>
- </transition>
- <input
- :id="elementId"
- :autocomplete="autocomplete"
- :spellcheck="spellcheck"
- ref="input"
- :type="currentType"
- :class="inputClasses"
- :placeholder="placeholder"
- :disabled="itemDisabled"
- :maxlength="maxlength"
- :readonly="readonly"
- :name="name"
- :value="currentValue"
- :number="number"
- :autofocus="autofocus"
- @keyup.enter="handleEnter"
- @keyup="handleKeyup"
- @keypress="handleKeypress"
- @keydown="handleKeydown"
- @focus="handleFocus"
- @blur="handleBlur"
- @compositionstart="handleComposition"
- @compositionupdate="handleComposition"
- @compositionend="handleComposition"
- @input="handleInput"
- @change="handleChange"
- @paste="handlePaste">
- <div :class="[prefixCls + '-group-append']" v-if="append" v-show="slotReady"><slot name="append"></slot></div>
- <div :class="[prefixCls + '-group-append', prefixCls + '-search']" v-else-if="search && enterButton" @click="handleSearch">
- <i class="ivu-icon ivu-icon-ios-search" v-if="enterButton === true"></i>
- <template v-else>{{ enterButton }}</template>
- </div>
- <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>
- </template>
- <template v-else>
- <textarea
- :id="elementId"
- :wrap="wrap"
- :autocomplete="autocomplete"
- :spellcheck="spellcheck"
- ref="textarea"
- :class="textareaClasses"
- :style="textareaStyles"
- :placeholder="placeholder"
- :disabled="itemDisabled"
- :rows="rows"
- :maxlength="maxlength"
- :readonly="readonly"
- :name="name"
- :value="currentValue"
- :autofocus="autofocus"
- @keyup.enter="handleEnter"
- @keyup="handleKeyup"
- @keypress="handleKeypress"
- @keydown="handleKeydown"
- @focus="handleFocus"
- @blur="handleBlur"
- @compositionstart="handleComposition"
- @compositionupdate="handleComposition"
- @compositionend="handleComposition"
- @input="handleInput"
- @paste="handlePaste">
- </textarea>
- <span class="ivu-input-word-count" v-if="showWordLimit">{{ textLength }}/{{ upperLimit }}</span>
- </template>
- </div>
- </template>
- <script>
- import { oneOf, findComponentUpward } from 'view-design/src/utils/assist';
- import calcTextareaHeight from 'view-design/src/utils/calcTextareaHeight';
- import Emitter from 'view-design/src/mixins/emitter';
- import mixinsForm from 'view-design/src/mixins/form';
- const prefixCls = 'ivu-input';
- export default {
- name: 'WInput',
- mixins: [ Emitter, mixinsForm ],
- props: {
- type: {
- validator (value) {
- return oneOf(value, ['text', 'textarea', 'password', 'url', 'email', 'date', 'number', 'tel']);
- },
- default: 'text'
- },
- value: {
- type: [String, Number],
- default: ''
- },
- size: {
- validator (value) {
- return oneOf(value, ['small', 'large', 'default']);
- },
- default () {
- return !this.$IVIEW || this.$IVIEW.size === '' ? 'default' : this.$IVIEW.size;
- }
- },
- placeholder: {
- type: String,
- default: ''
- },
- maxlength: {
- type: [String, Number]
- },
- disabled: {
- type: Boolean,
- default: false
- },
- icon: String,
- autosize: {
- type: [Boolean, Object],
- default: false
- },
- rows: {
- type: Number,
- default: 2
- },
- readonly: {
- type: Boolean,
- default: false
- },
- name: {
- type: String
- },
- number: {
- type: Boolean,
- default: false
- },
- autofocus: {
- type: Boolean,
- default: false
- },
- spellcheck: {
- type: Boolean,
- default: false
- },
- autocomplete: {
- type: String,
- default: 'off'
- },
- clearable: {
- type: Boolean,
- default: false
- },
- elementId: {
- type: String
- },
- wrap: {
- validator (value) {
- return oneOf(value, ['hard', 'soft']);
- },
- default: 'soft'
- },
- prefix: {
- type: String,
- default: ''
- },
- suffix: {
- type: String,
- default: ''
- },
- search: {
- type: Boolean,
- default: false
- },
- enterButton: {
- type: [Boolean, String],
- default: false
- },
- // 4.0.0
- showWordLimit: {
- type: Boolean,
- default: false
- },
- // 4.0.0
- password: {
- type: Boolean,
- default: false
- }
- },
- data () {
- return {
- currentValue: this.value,
- prefixCls: prefixCls,
- slotReady: false,
- textareaStyles: {},
- isOnComposition: false,
- showPassword: false
- };
- },
- computed: {
- currentType () {
- let type = this.type;
- if (type === 'password' && this.password && this.showPassword) type = 'text';
- return type;
- },
- prepend () {
- let state = false;
- if (this.type !== 'textarea') state = this.$slots.prepend !== undefined;
- return state;
- },
- append () {
- let state = false;
- if (this.type !== 'textarea') state = this.$slots.append !== undefined;
- return state;
- },
- showPrefix () {
- let state = false;
- if (this.type !== 'textarea') state = this.prefix !== '' || this.$slots.prefix !== undefined;
- return state;
- },
- showSuffix () {
- let state = false;
- if (this.type !== 'textarea') state = this.suffix !== '' || this.$slots.suffix !== undefined;
- return state;
- },
- wrapClasses () {
- return [
- `${prefixCls}-wrapper`,
- {
- [`${prefixCls}-wrapper-${this.size}`]: !!this.size,
- [`${prefixCls}-type-${this.type}`]: this.type,
- [`${prefixCls}-group`]: this.prepend || this.append || (this.search && this.enterButton),
- [`${prefixCls}-group-${this.size}`]: (this.prepend || this.append || (this.search && this.enterButton)) && !!this.size,
- [`${prefixCls}-group-with-prepend`]: this.prepend,
- [`${prefixCls}-group-with-append`]: this.append || (this.search && this.enterButton),
- [`${prefixCls}-hide-icon`]: this.append, // #554
- [`${prefixCls}-with-search`]: (this.search && this.enterButton)
- }
- ];
- },
- inputClasses () {
- return [
- `${prefixCls}`,
- {
- [`${prefixCls}-${this.size}`]: !!this.size,
- [`${prefixCls}-disabled`]: this.itemDisabled,
- [`${prefixCls}-with-prefix`]: this.showPrefix,
- [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false)
- }
- ];
- },
- textareaClasses () {
- return [
- `${prefixCls}`,
- {
- [`${prefixCls}-disabled`]: this.itemDisabled
- }
- ];
- },
- upperLimit () {
- return this.maxlength;
- },
- textLength () {
- if (typeof this.value === 'number') {
- return String(this.value).length;
- }
- return (this.value || '').length;
- }
- },
- methods: {
- handleEnter (event) {
- this.$emit('on-enter', event);
- if (this.search) this.$emit('on-search', this.currentValue);
- },
- handleKeydown (event) {
- this.$emit('on-keydown', event);
- },
- handleKeypress(event) {
- this.$emit('on-keypress', event);
- },
- handleKeyup (event) {
- this.$emit('on-keyup', event);
- },
- handleIconClick (event) {
- this.$emit('on-click', event);
- },
- handleFocus (event) {
- this.$emit('on-focus', event);
- },
- handleBlur (event) {
- this.$emit('on-blur', event);
- if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
- this.dispatch('FormItem', 'on-form-blur', this.currentValue);
- }
- },
- handleComposition(event) {
- if (event.type === 'compositionstart') {
- this.isOnComposition = true;
- }
- if (event.type === 'compositionend') {
- this.isOnComposition = false;
- this.handleInput(event);
- }
- },
- handleInput (event) {
- if (this.isOnComposition) return;
- let value = event.target.value;
- if (this.number && value !== '') value = Number.isNaN(Number(value)) ? value : Number(value);
- this.$emit('input', value);
- this.setCurrentValue(value);
- this.$emit('on-change', event);
- },
- handleChange (event) {
- this.$emit('on-input-change', event);
- },
- handlePaste (event) {
- this.$emit('on-input-paste', event);
- },
- setCurrentValue (value) {
- if (value === this.currentValue) return;
- this.$nextTick(() => {
- this.resizeTextarea();
- });
- this.currentValue = value;
- if (!findComponentUpward(this, ['DatePicker', 'TimePicker', 'Cascader', 'Search'])) {
- this.dispatch('FormItem', 'on-form-change', value);
- }
- },
- resizeTextarea () {
- const autosize = this.autosize;
- if (!autosize || this.type !== 'textarea') {
- return false;
- }
- const minRows = autosize.minRows;
- const maxRows = autosize.maxRows;
- this.textareaStyles = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
- },
- focus () {
- if (this.type === 'textarea') {
- this.$refs.textarea.focus();
- } else {
- this.$refs.input.focus();
- }
- },
- blur () {
- if (this.type === 'textarea') {
- this.$refs.textarea.blur();
- } else {
- this.$refs.input.blur();
- }
- },
- handleClear () {
- const e = { target: { value: '' } };
- this.$emit('input', '');
- this.setCurrentValue('');
- this.$emit('on-change', e);
- this.$emit('on-clear');
- },
- handleSearch () {
- if (this.itemDisabled) return false;
- this.$refs.input.focus();
- this.$emit('on-search', this.currentValue);
- },
- handleToggleShowPassword () {
- if (this.itemDisabled) return false;
- this.showPassword = !this.showPassword;
- this.focus();
- const len = this.currentValue.length;
- setTimeout(() => {
- this.$refs.input.setSelectionRange(len, len);
- }, 0);
- }
- },
- watch: {
- value (val) {
- this.setCurrentValue(val);
- }
- },
- mounted () {
- this.slotReady = true;
- this.resizeTextarea();
- }
- };
- </script>
|