All files / src/components/u-cascader.vue item.vue

60% Statements 12/20
16.66% Branches 2/12
20% Functions 1/5
63.15% Lines 12/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142      7x     7x                                                                                                                                                                                                                                                                              
<template>
    <f-scroll-view color="light" style="display: inline-block"
        :class="isInput? $style.searchShape : $style.scrollShape">
            <u-menu :class="$style.umenuShape">
                <u-menu-item v-for="(item, index) in data" :key="index" :ref="index"
                    :has-sub="hasSub(item)"
                    :disabled="item.disabled"
                    :class="$style.select_item"
                    :select="index === umenuIndex"
                    @click="clickMenuitem(item, index)">
                    <span v-if="item.highlighterHtml" v-html="item.highlighterHtml"></span>
                    <template v-else>
                        {{ $at(item, field) }}
                    </template>
                    <span :class="$style.spinner" v-if="item.loading"></span>
                </u-menu-item>
            </u-menu>
    </f-scroll-view>
</template>
 
<script>
import { findScrollParent } from '../../utils/dom';
 
export default {
    name: 'u-cascader-item',
    props: {
        data: { type: Array, default: () => [] },
        field: { type: String, default: 'text' },
        trigger: { type: String, default: 'click' },
        lazy: { type: Boolean, default: false },
        componentIndex: Number, // 第几个cascaderitem组件
        selectSubIdnex: Number, // parent选择了第几个cascaderitem组件
        isInput: Boolean,
        menuIndex: Number,
 
        changeOnSelect: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            umenuIndex: this.menuIndex !== undefined ? this.menuIndex : -1,
        };
    },
    watch: {
        selectSubIdnex(newValue) {
            if (this.componentIndex > newValue)
                this.umenuIndex = -1;
        },
        data(newdata, predata) {
            if (newdata.length > predata.length)
                this.$nextTick(() => {
                    this.addMouseenter(newdata.slice(predata.length), predata.length);
                });
        },
        menuIndex(value) {
            this.selectMenuitem(value);
        },
    },
    mounted() {
        this.addMouseenter(this.data, 0);
    },
    methods: {
        clickMenuitem(selectItem, index) {
            this.selectMenuitem(index);
            this.$emit('select-umenuitem', selectItem, this.componentIndex);
            if (this.lazy) {
                if (selectItem.leaf || this.changeOnSelect)
                    this.$emit('select-lastvalue');
            } else if (!selectItem.children || this.changeOnSelect) {
                this.$emit('select-lastvalue');
            }
        },
        hoverSelect(selectItem, level) {
            this.selectMenuitem(level);
            this.$emit('select-umenuitem', selectItem, this.componentIndex);
        },
        addMouseenter(newDatas, length) {
            if (this.trigger.toLowerCase() === 'hover') {
                newDatas.forEach((_, index) => {
                    const currentIndex = length + index;
                    // v-for中使用ref,vue的内部逻辑会自动将ref生成数组,所以要添一个xxx[0]
                    this.$refs[currentIndex][0].$el.addEventListener('mouseenter', () => {
                        if (!newDatas[index].disabled)
                            this.hoverSelect(newDatas[index], currentIndex);
                    });
                });
            }
        },
        selectMenuitem(level) {
            if (level === -1)
                return;
 
            this.umenuIndex = level;
            this.ensureFocusedInView();
        },
        ensureFocusedInView() {
            if (!this.$refs[this.umenuIndex]) {
                return;
            }
            const focusedEl = this.$refs[this.umenuIndex][0].$el;
            let parentEl = focusedEl.parentElement;
            parentEl = findScrollParent(focusedEl);
 
            if (parentEl) {
                if (parentEl.scrollTop < focusedEl.offsetTop + focusedEl.offsetHeight - parentEl.clientHeight) {
                    parentEl.scrollTop = focusedEl.offsetTop
                        + focusedEl.offsetHeight
                        - parentEl.clientHeight;
                }
                if (parentEl.scrollTop > focusedEl.offsetTop)
                    parentEl.scrollTop = focusedEl.offsetTop;
            }
        },
        keyboardShift(count, enter) {
            let newUmenuIndex = this.umenuIndex + count;
            while (this.data[newUmenuIndex] && this.data[newUmenuIndex].disabled) {
                newUmenuIndex += count;
            }
            if (newUmenuIndex < 0 || newUmenuIndex >= this.data.length)
                return;
            const selectItem = this.data[newUmenuIndex];
            this.selectMenuitem(newUmenuIndex);
 
            this.$emit('select-umenuitem', selectItem, this.componentIndex);
            if (enter && (!selectItem.children || this.changeOnSelect))
                this.$emit('select-lastvalue');
        },
        hasSub(item) {
            let show = false;
            if (item.children || ('leaf' in item && !item.leaf))
                if (!item.loading)
                    show = true;
            return show;
        },
    },
};
</script>
 
<style module src="./item.css"> </style>