UNPKG

magiccube-vue3

Version:

vue3-js版组件库

251 lines (216 loc) 8.5 kB
import Dropdown from '../../utils/dropdown' import { jobFuncCodeToData } from '../../utils/common' import { ref, reactive, computed, getCurrentInstance, nextTick } from 'vue' import getFormValidMethod from '../../utils/form-valid' import Cascader from './cascader' import JOB_FUNC_DATA from '../../data/job-func.json' import CLOSE_ICON from '../../img/icon_remove.svg' const JobFuncPicker = { name: 'McJobFuncPicker', props: { modelValue: { type: [Array, String, Number], default: () => [] }, options: { type: [Array, Object], default: () => JOB_FUNC_DATA }, // 选择器类型:cascade、singleStage type: { type: String, default: 'cascader' }, placeholder: { type: String, default: '请选择职能' }, // 选择数量 max: { type: [String, Number], default: 1 }, disabled: Boolean, downMenuHeight: { type: Number, default: 430 }, enabledSelectSecondLevel: { type: Boolean, default: true }, unchecked: Boolean, }, emits: ['change', 'update:modelValue'], setup(props, { emit }) { const dropdownEl = ref(null) const innerEl = ref(null) const pickerEl = ref(null) const displayInputSearch = ref(false) const keywordEl = ref(false) const state = reactive({ keyword: '', list: [], slide: false, }) const instance = getCurrentInstance() const { fieldName, validator, errorMessage } = getFormValidMethod(instance) const fieldError = computed(() => fieldName && errorMessage?.value && !props.unchecked ? errorMessage.value[fieldName] : '') const model = computed({ get() { if (Array.isArray(props.modelValue)) { return props.modelValue.every(n => typeof n === 'string') ? jobFuncCodeToData(props.modelValue, props.options, 'propertyCode') : props.modelValue } else if (props.modelValue) { return jobFuncCodeToData(props.modelValue, props.options, 'propertyCode') } else { return [] } }, set(value) { emit('update:modelValue', value) validator && validator('change', value) } }) const handleVisible = () => { if (props.disabled) return false dropdownEl.value.visible() } const handleChange = (array) => { model.value = array emit('change', array) if(props.max === array.length) setSlideUp() } const handleRemove = (e) => { e && e.stopPropagation() const list = model.value model.value = list.slice(1, list.length) emit('change', { key: props.keyName, data: model.value }) } const setSlideDown = (event) => { const options = { event, pickerHeight: pickerEl.value.offsetHeight, pickerWidth: pickerEl.value.offsetWidth, dropdownWidth: 668, dropdownHeight: innerEl.value.offsetHeight || props.downMenuHeight } innerEl.value.init() dropdownEl.value.visible(options) displayInputSearch.value = true state.slide = true // 让模糊搜索框自动聚焦 nextTick(() => { keywordEl.value && keywordEl.value.focus() }) } const setSlideUp = () => { state.keyword = '' dropdownEl.value.invisible() displayInputSearch.value = false state.slide = false } const handleShowDropdown = (e) => { if (props.disabled || e.target.nodeName.toLowerCase() === 'input') return false if (state.slide) { /** * 隐藏下拉 */ setSlideUp(e) return false } /** * 打开下拉 */ setSlideDown(e) } const handleKeywordChange = () => { // innerEl.value.init() } const emptyNode = () => ( <span class="mc-job-func-picker__result--placeholder">{props.placeholder}</span> ) const displayName = computed(() => model.value?.length ? model.value[0].defaultName : '') const multiReviewNode = () => { const len = model.value.length return ( <> <div class="mc-job-func-picker__result--wrap"> <span class="mc-job-func-picker__result--name">{displayName.value}</span> <span class="mc-job-func-picker__result--close"> <img onClick={handleRemove} src={CLOSE_ICON} /> </span> </div> { len > 1 ? ( <div class="mc-job-func-picker__result--amount">+{len}</div> ) : '' } </> ) } const keywordPlaceholder = computed(() => { if(props.max > 1){ return '请输入关键词' } else { return displayName.value || '请输入关键词' } }) const singleReviewNode = () => <span class="mc-job-func-picker__result--single" v-ellipsis={displayName.value}>{displayName.value}</span> const getReview = () => { if(props.max === 1){ if(Array.isArray(model.value)){ return displayInputSearch.value ? inputKeywordNode() : (model.value.length === 1? singleReviewNode() : emptyNode()) } else { return displayInputSearch.value ? inputKeywordNode() : (model.value !== ''? singleReviewNode() : emptyNode()) } } else { return displayInputSearch.value ? inputKeywordNode() : (model.value?.length? multiReviewNode() : emptyNode()) } } // 关键词搜索输入框dom const inputKeywordNode = () => ( <div class="mc-job-func-picker__result--keyword"> <input ref={keywordEl} class="mc-job-func-picker__result--keyword__input" autocomplete="off" placeholder={keywordPlaceholder.value} v-model={state.keyword} onInput={handleKeywordChange} /> </div> ) return () => ( <div ref={pickerEl} class={{ 'mc-job-func-picker': true, disabled: props.disabled }}> <div class={{ 'mc-job-func-picker__result': true, error: Boolean(fieldError.value) }} onClick={handleShowDropdown}> { getReview() } {/* 输入查找 在下拉菜单打开时显示 */ displayInputSearch.value ? inputKeywordNode() : '' } <span class={[ 'mc-job-func-picker__result--arrow', { 'mc-rotate': displayInputSearch.value } ]}> <img src={require('../../img/icon_picker_arrow.svg')} /> </span> </div> <Dropdown ref={dropdownEl} picker={pickerEl.value} onClose={setSlideUp}> { props.type === 'cascader' ? <Cascader ref={innerEl} selected={model.value} options={props.options} max={props.max} dropdownHeight={props.downMenuHeight} keyword={state.keyword} enabledSelectSecondLevel={props.enabledSelectSecondLevel} onChange={handleChange} /> : '' } </Dropdown> </div> ) } } JobFuncPicker.install = Vue => { Vue.component(JobFuncPicker.name, JobFuncPicker) } const McJobFuncPicker = JobFuncPicker export { McJobFuncPicker, McJobFuncPicker as default }