magiccube-vue3
Version:
vue3-js版组件库
250 lines (236 loc) • 10.4 kB
JavaScript
import { ref, computed, toRaw, nextTick } from 'vue'
import ICON_REMOVE from '../../img/icon_close.svg'
const Cascade = {
props: {
selected: [Array, Number, String],
keyword: String,
options: {
type: Array,
default: () => []
},
max: {
type: Number,
default: 1
},
dropdownHeight: Number,
enabledSelectSecondLevel: Boolean
},
emits: ['change'],
setup(props, { emit, expose }){
const JOB_FUNC_DICT = computed(() => {
if(props.keyword && props.keyword.trim()){
const arr = props.options.filter(n => n.defaultName.indexOf(props.keyword) > -1)
const firstCodeList = [], secondCodeList = [], thirfCodeList = []
arr.forEach((n, i) => {
const c = n.propertyCode.toString()
firstCodeList.push(c.substring(0, 2))
if(c.substring(0, 4)) secondCodeList.push(c.substring(0, 4))
if(c.substring(0, 6)) thirfCodeList.push(c.substring(0, 6))
})
activeFirst.value = firstCodeList[0] || ''
activeSecond.value = secondCodeList[0] || ''
return props.options.filter(n => firstCodeList.includes(n.propertyCode) || secondCodeList.includes(n.propertyCode) || thirfCodeList.includes(n.propertyCode))
} else {
return props.options
}
})
const activeFirst = ref('')
const activeSecond = ref('')
const model = ref([])
const init = () => {
if(props.selected?.length){
const _def = props.selected[0]
activeFirst.value = _def.propertyCode.substring(0, 2)
activeSecond.value = _def.propertyCode.substring(0, 4)
} else {
activeFirst.value = firstColumn.value[0].propertyCode
activeSecond.value = secondColumn.value[0].propertyCode
}
model.value = props.selected
}
const firstColumn = computed(() => getData('first'))
const secondColumn = computed(() => getData('second'))
const thirdColumn = computed(() => getData('third'))
const getData = (level) => {
switch(level){
case 'first': {
return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'first')
}
case 'second': {
return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'second' && n.propertyCode.indexOf(activeFirst.value) === 0)
}
case 'third': {
return JOB_FUNC_DICT.value.filter(n => n.propertyName === 'third' && n.propertyCode.indexOf(activeFirst.value) === 0 && n.propertyCode.indexOf(activeSecond.value) === 0)
}
}
}
const handleClear = () => model.value = []
const handleClick = (level, data, event = {}) => {
event.stopPropagation()
switch(level){
case 'first': {
activeFirst.value = data.propertyCode
const _c = getData('second') || []
activeSecond.value = _c[0]?.propertyCode || data.propertyCode
break
}
case 'second': {
activeSecond.value = data.propertyCode
if(!thirdColumn.value.length) {
setSelectedData(data)
}
break
}
case 'third': {
setSelectedData(data)
break
}
}
}
const setSelectedData = (data) => {
let _selected = model.value
const _d = typeof data === 'string'? props.options.find(n => n.propertyCode === data) : data
const existIdx = model.value.findIndex(n => n.propertyCode === _d.propertyCode)
if(existIdx > -1){
_selected.splice(existIdx, 1)
} else if(props.max === 1){
_selected = [_d]
} else if(props.max === _selected.length){
return false
} else {
_selected.push(_d)
}
model.value = _selected
emit('change', toRaw(model.value))
}
const getBadge = code => {
let count = 0
model.value.forEach(n => {
if(n.propertyCode.indexOf(code) === 0) count++
})
return count
}
expose({
init
})
return () => (
<div class={[
'mc-cascader'
]}>
<div class={['mc-cascader__tip']}>
<span>最多选择 {props.max} 项</span>
</div>
{/* 一级 */}
<ul class={[
'mc-cascader__column',
'mc-cascader__column--first',
]} style={{
height: props.dropdownHeight + 'px'
}}>
{
firstColumn.value.map((p, idx) => (
<li class={[
'mc-cascader__column--item',
'view-full',
{
active: activeFirst.value === p.propertyCode
}
]} key={idx} v-ellipsis={p.simpleName} onClick={(e) => handleClick('first', p, e)}>
<span>{p.simpleName}</span>
{
getBadge(p.propertyCode)? <span class="mc-cascader__badge">{getBadge(p.propertyCode)}</span> : ''
}
</li>
))
}
</ul>
{/* 二级 */}
<ul class={[
'mc-cascader__column',
'mc-cascader__column--second',
]} style={{
height: props.dropdownHeight + 'px'
}}>
{
secondColumn.value.map((c, idx) => (
<li class={[
'mc-cascader__column--item',
'view-full',
{
active: activeSecond.value === c.propertyCode
}
]} key={idx} onClick={(e) => handleClick('second', c, e)}>
<span>{c.simpleName}</span>
{
getBadge(c.propertyCode)? <span class="mc-cascader__badge">{getBadge(c.propertyCode)}</span> : ''
}
</li>
))
}
</ul>
{/* 三级 */}
<ul class={[
'mc-cascader__column',
'mc-cascader__column--third',
]} style={{
height: props.dropdownHeight + 'px'
}}>
{
// 如果没有第三级 就不显示全部按钮
props.enabledSelectSecondLevel && !props.keyword && thirdColumn.value?.length? (
<li class={[
'mc-cascader__column--tag',
]}>
<span onClick={e => handleClick('third', activeSecond.value, e)}>全部</span>
</li>
) : ''
}
{
thirdColumn.value.map((d, idx) => (
<li class={[
'mc-cascader__column--tag',
{
active: model.value.some(n => n.propertyCode === d.propertyCode)
}
]} key={idx}>
<span onClick={(e) => handleClick('third', d, e)}>{d.simpleName}</span>
</li>
))
}
</ul>
{
model.value.length? (
<div class={[
'mc-cascader__selected'
]}>
<div class="mc-cascader__selected--title">
<span>已选</span>
<span style="flex:1;margin-left:16px;">{model.value.length || 0}个</span>
<i onClick={handleClear}>
<img src={require('../../img/icon_trash.svg')} />
</i>
</div>
<ul class="mc-cascader__selected--list">
{
model.value.map(n => (
<li class="mc-cascader__selected--list__item">
<div class="mc-cascader__selected--list__item--tag">
<div class="mc-cascader__selected--list__item--tag__inner">
<span class="mc-cascader__selected--list__item--tag--name">{n.defaultName}</span>
<i class="mc-cascader__selected--list__item--tag--close" onClick={(e) => handleClick('third', n, e)}>
<img src={ICON_REMOVE} />
</i>
</div>
</div>
</li>
))
}
</ul>
</div>
) : ''
}
</div>
)
}
}
export default Cascade