select-head.vue 9.33 KB
<template>
    <div @click="onHeaderClick" :class="headCls">
        <span :class="[prefixCls + '-prefix']" v-if="$slots.prefix || prefix">
            <slot name="prefix">
                <Icon :type="prefix" v-if="prefix" />
            </slot>
        </span>
        <div
            class="ivu-tag ivu-tag-checked"
            v-for="(item, index) in selectedMultiple"
            v-if="maxTagCount === undefined || index < maxTagCount">
            <span class="ivu-tag-text">{{ item.label }}</span>
            <Icon type="ios-close" @click.native.stop="removeTag(item)"></Icon>
        </div><div class="ivu-tag ivu-tag-checked" v-if="maxTagCount !== undefined && selectedMultiple.length > maxTagCount">
            <span class="ivu-tag-text ivu-select-max-tag">
                <template v-if="maxTagPlaceholder">{{ maxTagPlaceholder(selectedMultiple.length - maxTagCount) }}</template>
                <template v-else>+ {{ selectedMultiple.length - maxTagCount }}...</template>
            </span>
        </div>
        <span
            :class="singleDisplayClasses"
            v-show="singleDisplayValue"
        >{{ singleDisplayValue }}</span>
        <input
            :id="inputElementId"
            type="text"
            v-if="filterable"
            v-model="query"
            :disabled="disabled"
            :class="[prefixCls + '-input']"
            :placeholder="showPlaceholder ? localePlaceholder : ''"
            :style="inputStyle"
            autocomplete="off"
            spellcheck="false"
            @keydown="resetInputState"
            @keydown.delete="handleInputDelete"
            @focus="onInputFocus"
            @blur="onInputBlur"

            ref="input">
        <Icon type="ios-close-circle" :class="[prefixCls + '-arrow']" v-if="resetSelect" @click.native.stop="onClear"></Icon>
        <Icon :type="arrowType" :custom="customArrowType" :size="arrowSize" :class="[prefixCls + '-arrow']" v-if="!resetSelect && !remote"></Icon>
    </div>
</template>
<script>
    import Icon from '../icon';
    import Emitter from '../../mixins/emitter';
    import Locale from '../../mixins/locale';

    const prefixCls = 'ivu-select';

    export default {
        name: 'iSelectHead',
        mixins: [ Emitter, Locale ],
        components: { Icon },
        props: {
            disabled: {
                type: Boolean,
                default: false
            },
            filterable: {
                type: Boolean,
                default: false
            },
            multiple: {
                type: Boolean,
                default: false
            },
            remote: {
                type: Boolean,
                default: false
            },
            initialLabel: {
                type: [String, Number, Array],
            },
            values: {
                type: Array,
                default: () => []
            },
            clearable: {
                type: [Function, Boolean],
                default: false,
            },
            inputElementId: {
                type: String
            },
            placeholder: {
                type: String
            },
            queryProp: {
                type: String,
                default: ''
            },
            prefix: {
                type: String
            },
            // 3.4.0
            maxTagCount: {
                type: Number
            },
            // 3.4.0
            maxTagPlaceholder: {
                type: Function
            }
        },
        data () {
            return {
                prefixCls: prefixCls,
                query: '',
                inputLength: 20,
                remoteInitialLabel: this.initialLabel,
                preventRemoteCall: false,
            };
        },
        computed: {
            singleDisplayClasses(){
                const {filterable, multiple, showPlaceholder} = this;
                return [{
                    [prefixCls + '-head-with-prefix']: this.$slots.prefix || this.prefix,
                    [prefixCls + '-placeholder']: showPlaceholder && !filterable,
                    [prefixCls + '-selected-value']: !showPlaceholder && !multiple && !filterable,
                }];
            },
            singleDisplayValue(){
                if ((this.multiple && this.values.length > 0) || this.filterable) return '';
                return `${this.selectedSingle}` || this.localePlaceholder;
            },
            showPlaceholder () {
                let status = false;
                if (!this.multiple) {
                    const value = this.values[0];
                    if (typeof value === 'undefined' || String(value).trim() === ''){
                        status = !this.remoteInitialLabel;
                    }
                } else {
                    if (!this.values.length > 0) {
                        status = true;
                    }
                }
                return status;
            },
            resetSelect(){
                return !this.showPlaceholder && this.clearable;
            },
            inputStyle () {
                let style = {};

                if (this.multiple) {
                    if (this.showPlaceholder) {
                        style.width = '100%';
                    } else {
                        style.width = `${this.inputLength}px`;
                    }
                }

                return style;
            },
            localePlaceholder () {
                if (this.placeholder === undefined) {
                    return this.t('i.select.placeholder');
                } else {
                    return this.placeholder;
                }
            },
            selectedSingle(){
                const selected = this.values[0];
                return selected ? selected.label : (this.remoteInitialLabel || '');
            },
            selectedMultiple(){
                return this.multiple ? this.values : [];
            },
            // 使用 prefix 时,在 filterable
            headCls () {
                return {
                    [`${prefixCls}-head-flex`]: this.filterable && (this.$slots.prefix || this.prefix)
                };
            },
            // 3.4.0, global setting customArrow 有值时,arrow 赋值空
            arrowType () {
                let type = 'ios-arrow-down';

                if (this.$IVIEW) {
                    if (this.$IVIEW.select.customArrow) {
                        type = '';
                    } else if (this.$IVIEW.select.arrow) {
                        type = this.$IVIEW.select.arrow;
                    }
                }
                return type;
            },
            // 3.4.0, global setting
            customArrowType () {
                let type = '';

                if (this.$IVIEW) {
                    if (this.$IVIEW.select.customArrow) {
                        type = this.$IVIEW.select.customArrow;
                    }
                }
                return type;
            },
            // 3.4.0, global setting
            arrowSize () {
                let size = '';

                if (this.$IVIEW) {
                    if (this.$IVIEW.select.arrowSize) {
                        size = this.$IVIEW.select.arrowSize;
                    }
                }
                return size;
            }
        },
        methods: {
            onInputFocus(){
                this.$emit('on-input-focus');
            },
            onInputBlur () {
                if (!this.values.length) this.query = '';  // #5155
                this.$emit('on-input-blur');
            },
            removeTag (value) {
                if (this.disabled) return false;
                this.dispatch('iSelect', 'on-select-selected', value);
            },
            resetInputState () {
                this.inputLength = this.$refs.input.value.length * 12 + 20;
                this.$emit('on-keydown');
            },
            handleInputDelete () {
                if (this.multiple && this.selectedMultiple.length && this.query === '') {
                    this.removeTag(this.selectedMultiple[this.selectedMultiple.length - 1]);
                }
            },
            onHeaderClick(e){
                if (this.filterable && e.target === this.$el){
                    this.$refs.input.focus();
                }
            },
            onClear(){
                this.$emit('on-clear');
            }
        },
        watch: {
            values ([value]) {
                if (!this.filterable) return;
                this.preventRemoteCall = true;
                if (this.multiple){
                    this.query = '';
                    this.preventRemoteCall = false; // this should be after the query change setter above
                    return;
                }
                // #982
                if (typeof value === 'undefined' || value === '' || value === null) this.query = '';
                else this.query = value.label;
                this.$nextTick(() => this.preventRemoteCall = false); // this should be after the query change setter above
            },
            query (val) {
                if (this.preventRemoteCall) {
                    this.preventRemoteCall = false;
                    return;
                }

                this.$emit('on-query-change', val);
            },
            queryProp(query){
                if (query !== this.query) this.query = query;
            },
        }
    };
</script>