<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 && !disabled" @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>            <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="type"                :class="inputClasses"                :placeholder="placeholder"                :disabled="disabled"                :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">            <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>        <textarea            v-else            :id="elementId"            :wrap="wrap"            :autocomplete="autocomplete"            :spellcheck="spellcheck"            ref="textarea"            :class="textareaClasses"            :style="textareaStyles"            :placeholder="placeholder"            :disabled="disabled"            :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">        </textarea>    </div></template><script>    import { oneOf, findComponentUpward } from '../../utils/assist';    import calcTextareaHeight from '../../utils/calcTextareaHeight';    import Emitter from '../../mixins/emitter';    const prefixCls = 'ivu-input';    export default {        name: 'Input',        mixins: [ Emitter ],        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: 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            }        },        data () {            return {                currentValue: this.value,                prefixCls: prefixCls,                prepend: true,                append: true,                slotReady: false,                textareaStyles: {},                showPrefix: false,                showSuffix: false,                isOnComposition: false            };        },        computed: {            wrapClasses () {                return [                    `${prefixCls}-wrapper`,                    {                        [`${prefixCls}-wrapper-${this.size}`]: !!this.size,                        [`${prefixCls}-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.disabled,                        [`${prefixCls}-with-prefix`]: this.showPrefix,                        [`${prefixCls}-with-suffix`]: this.showSuffix || (this.search && this.enterButton === false)                    }                ];            },            textareaClasses () {                return [                    `${prefixCls}`,                    {                        [`${prefixCls}-disabled`]: this.disabled                    }                ];            }        },        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);            },            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.disabled) return false;                this.$refs.input.focus();                this.$emit('on-search', this.currentValue);            }        },        watch: {            value (val) {                this.setCurrentValue(val);            }        },        mounted () {            if (this.type !== 'textarea') {                this.prepend = this.$slots.prepend !== undefined;                this.append = this.$slots.append !== undefined;                this.showPrefix = this.prefix !== '' || this.$slots.prefix !== undefined;                this.showSuffix = this.suffix !== '' || this.$slots.suffix !== undefined;            } else {                this.prepend = false;                this.append = false;            }            this.slotReady = true;            this.resizeTextarea();        }    };</script>