magiccube-vue3
Version:
vue3-js版组件库
251 lines (216 loc) • 8.5 kB
JavaScript
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 }