<template> 
 | 
  <view class="nut-menu-item" v-show="state.showWrapper" :style="style"> 
 | 
    <view 
 | 
      v-show="state.showPopup" 
 | 
      @click="handleClickOutside" 
 | 
      class="nut-menu-item-placeholder-element" 
 | 
      :style="placeholderElementStyle" 
 | 
      :catch-move="parent.props.lockScroll" 
 | 
    > 
 | 
    </view> 
 | 
    <nut-popup 
 | 
      :style="{ position: 'absolute' }" 
 | 
      :overlayStyle="{ position: 'absolute' }" 
 | 
      v-bind="$attrs" 
 | 
      v-model:visible="state.showPopup" 
 | 
      :position="parent.props.direction === 'down' ? 'top' : 'bottom'" 
 | 
      :duration="parent.props.duration" 
 | 
      :destroy-on-close="false" 
 | 
      :overlay="parent.props.overlay" 
 | 
      :lockScroll="parent.props.lockScroll" 
 | 
      @closed="handleClose" 
 | 
      :close-on-click-overlay="parent.props.closeOnClickOverlay" 
 | 
    > 
 | 
      <scroll-view :scroll-y="true"> 
 | 
        <view class="nut-menu-item__content" :class="{ noPadding: !options?.length }"> 
 | 
          <view 
 | 
            v-for="(option, index) in options" 
 | 
            :key="index" 
 | 
            class="nut-menu-item__option" 
 | 
            :class="[{ active: optionIsActive(option) }]" 
 | 
            :style="{ 'flex-basis': 100 / cols + '%' }" 
 | 
            @click="onClick(option)" 
 | 
          > 
 | 
            <span 
 | 
              class="nut-menu-item__span" 
 | 
              v-if="optionIsActive(option)" 
 | 
              :class="[optionIsActive(option) ? activeTitleClass : inactiveTitleClass]" 
 | 
            > 
 | 
              <slot name="icon"> 
 | 
                <Check v-bind="$attrs" :color="parent.props.activeColor"></Check> 
 | 
              </slot> 
 | 
            </span> 
 | 
            <view 
 | 
              :class="[optionIsActive(option) ? activeTitleClass : inactiveTitleClass]" 
 | 
              :style="{ color: optionIsActive(option) ? parent.props.activeColor : '' }" 
 | 
              >{{ option.text }}</view 
 | 
            > 
 | 
          </view> 
 | 
        </view> 
 | 
        <slot></slot> 
 | 
      </scroll-view> 
 | 
    </nut-popup> 
 | 
  </view> 
 | 
</template> 
 | 
<script lang="ts"> 
 | 
import { MenuItemOption } from '@nutui/nutui-taro/dist/types/__VUE/menuitem/type'; 
 | 
import { Check } from '@nutui/icons-vue-taro'; 
 | 
import { isArray } from 'lodash'; 
 | 
  
 | 
export default defineComponent({ 
 | 
  name: 'bl-menu-item', 
 | 
  props: { 
 | 
    title: String, 
 | 
    options: { 
 | 
      type: Array as PropType<MenuItemOption[]>, 
 | 
      default: () => [] as MenuItemOption[], 
 | 
    }, 
 | 
    disabled: { 
 | 
      type: Boolean, 
 | 
      default: false, 
 | 
    }, 
 | 
    modelValue: { 
 | 
      type: [Array, String, Number], 
 | 
    }, 
 | 
    cols: { 
 | 
      type: Number, 
 | 
      default: 1, 
 | 
    }, 
 | 
    activeTitleClass: String, 
 | 
    inactiveTitleClass: String, 
 | 
    emptyValue: { 
 | 
      type: [String, Number], 
 | 
      default: null, 
 | 
    }, 
 | 
    emptyTitle: { 
 | 
      type: String, 
 | 
      default: '', 
 | 
    }, 
 | 
    enableCancelSelect: { 
 | 
      type: Boolean, 
 | 
      default: true, 
 | 
    }, 
 | 
    multiple: { 
 | 
      type: Boolean, 
 | 
      default: false, 
 | 
    }, 
 | 
  }, 
 | 
  components: { 
 | 
    Check, 
 | 
  }, 
 | 
  emits: ['update:modelValue', 'change', 'closePopup'], 
 | 
  setup(props, { emit }) { 
 | 
    const state = reactive({ 
 | 
      showPopup: false, 
 | 
      showWrapper: false, 
 | 
    }); 
 | 
  
 | 
    const useParent: any = () => { 
 | 
      const parent = inject('menuParent', null); 
 | 
      if (parent) { 
 | 
        // 获取子组件自己的实例 
 | 
        const instance = getCurrentInstance()!; 
 | 
        const { link, removeLink } = parent; 
 | 
        // @ts-ignore 
 | 
        link(instance); 
 | 
        onUnmounted(() => { 
 | 
          // @ts-ignore 
 | 
          removeLink(instance); 
 | 
        }); 
 | 
        return { parent }; 
 | 
      } 
 | 
    }; 
 | 
  
 | 
    const { parent } = useParent(); 
 | 
  
 | 
    const style = computed(() => { 
 | 
      return parent.props.direction === 'down' 
 | 
        ? { top: parent.offset.value + 'px', zIndex: 222222222 } 
 | 
        : { bottom: parent.offset.value + 'px' }; 
 | 
    }); 
 | 
  
 | 
    const placeholderElementStyle = computed(() => { 
 | 
      const heightStyle = { height: parent.offset.value + 'px' }; 
 | 
      if (parent.props.direction === 'down') { 
 | 
        return { ...heightStyle, top: '0px' }; 
 | 
      } else { 
 | 
        return { ...heightStyle, bottom: '0px' }; 
 | 
      } 
 | 
    }); 
 | 
  
 | 
    const toggle = (show = !state.showPopup) => { 
 | 
      if (show === state.showPopup) { 
 | 
        return; 
 | 
      } 
 | 
      state.showPopup = show; 
 | 
      if (show) { 
 | 
        state.showWrapper = true; 
 | 
      } 
 | 
    }; 
 | 
  
 | 
    const renderTitle = () => { 
 | 
      if (props.title) { 
 | 
        return props.title; 
 | 
      } 
 | 
      if (isArray(props.modelValue)) { 
 | 
        const selectedOptions = (props.options ?? []) 
 | 
          .filter((option) => (props.modelValue as any).includes(option.value)) 
 | 
          .map((x) => x.text); 
 | 
        return selectedOptions.length > 0 ? selectedOptions.join(',') : props.emptyTitle; 
 | 
      } 
 | 
      const match: any = props.options?.find((option: any) => option.value === props.modelValue); 
 | 
      return match ? match.text : props.emptyTitle; 
 | 
    }; 
 | 
  
 | 
    const onClick = (option: MenuItemOption) => { 
 | 
      console.log(1); 
 | 
  
 | 
      state.showPopup = false; 
 | 
      if (props.multiple) { 
 | 
        const modelValue = props.modelValue as Array<any>; 
 | 
        const val = modelValue.includes(option.value) 
 | 
          ? modelValue.filter((x) => x !== option.value) 
 | 
          : [...modelValue, option.text]; 
 | 
        console.log('val: ', val); 
 | 
  
 | 
        emit('update:modelValue', val); 
 | 
        emit('change', val); 
 | 
      } else { 
 | 
        if (option.value !== props.modelValue) { 
 | 
          emit('update:modelValue', option.value); 
 | 
          emit('change', option.value); 
 | 
        } else { 
 | 
          if (props.enableCancelSelect) { 
 | 
            emit('update:modelValue', props.emptyValue); 
 | 
            emit('change', props.emptyValue); 
 | 
          } 
 | 
        } 
 | 
      } 
 | 
    }; 
 | 
  
 | 
    const handleClose = () => { 
 | 
      state.showWrapper = false; 
 | 
    }; 
 | 
  
 | 
    const handleClickOutside = () => { 
 | 
      state.showPopup = false; 
 | 
      emit('closePopup'); 
 | 
    }; 
 | 
  
 | 
    function optionIsActive(option: MenuItemOption) { 
 | 
      return isArray(props.modelValue) 
 | 
        ? props.modelValue.includes(option.value) 
 | 
        : option.value === props.modelValue; 
 | 
    } 
 | 
  
 | 
    return { 
 | 
      style, 
 | 
      placeholderElementStyle, 
 | 
      renderTitle, 
 | 
      state, 
 | 
      parent, 
 | 
      toggle, 
 | 
      onClick, 
 | 
      handleClose, 
 | 
      handleClickOutside, 
 | 
      optionIsActive, 
 | 
    }; 
 | 
  }, 
 | 
}); 
 | 
</script> 
 |