element-plus
Version:
A Component Library for Vue 3
166 lines (143 loc) • 4.16 kB
text/typescript
import { computed, getCurrentInstance, watch } from 'vue'
import type { ExtractPropTypes } from 'vue'
import type { TransferPanelState, Key } from './transfer'
export const CHECKED_CHANGE_EVENT = 'checked-change'
export const useCheckProps = {
data: {
type: Array,
default() {
return []
},
},
optionRender: Function,
placeholder: String,
title: String,
filterable: Boolean,
format: Object,
filterMethod: Function,
defaultChecked: Array,
props: Object,
}
export const useCheck = (
props: ExtractPropTypes<typeof useCheckProps>,
panelState: TransferPanelState
) => {
const { emit } = getCurrentInstance()
const labelProp = computed(() => props.props.label || 'label')
const keyProp = computed(() => props.props.key || 'key')
const disabledProp = computed(() => props.props.disabled || 'disabled')
const filteredData = computed(() => {
return props.data.filter((item) => {
if (typeof props.filterMethod === 'function') {
return props.filterMethod(panelState.query, item)
} else {
const label = item[labelProp.value] || item[keyProp.value].toString()
return label.toLowerCase().includes(panelState.query.toLowerCase())
}
})
})
const checkableData = computed(() => {
return filteredData.value.filter((item) => !item[disabledProp.value])
})
const checkedSummary = computed(() => {
const checkedLength = panelState.checked.length
const dataLength = props.data.length
const { noChecked, hasChecked } = props.format
if (noChecked && hasChecked) {
return checkedLength > 0
? hasChecked
.replace(/\${checked}/g, checkedLength.toString())
.replace(/\${total}/g, dataLength.toString())
: noChecked.replace(/\${total}/g, dataLength.toString())
} else {
return `${checkedLength}/${dataLength}`
}
})
const isIndeterminate = computed(() => {
const checkedLength = panelState.checked.length
return checkedLength > 0 && checkedLength < checkableData.value.length
})
const updateAllChecked = () => {
const checkableDataKeys = checkableData.value.map(
(item) => item[keyProp.value]
)
panelState.allChecked =
checkableDataKeys.length > 0 &&
checkableDataKeys.every((item) => panelState.checked.includes(item))
}
const handleAllCheckedChange = (value: Key[]) => {
panelState.checked = value
? checkableData.value.map((item) => item[keyProp.value])
: []
}
watch(
() => panelState.checked,
(val, oldVal) => {
updateAllChecked()
if (panelState.checkChangeByUser) {
const movedKeys = val
.concat(oldVal)
.filter((v) => !val.includes(v) || !oldVal.includes(v))
emit(CHECKED_CHANGE_EVENT, val, movedKeys)
} else {
emit(CHECKED_CHANGE_EVENT, val)
panelState.checkChangeByUser = true
}
}
)
watch(checkableData, () => {
updateAllChecked()
})
watch(
() => props.data,
() => {
const checked = []
const filteredDataKeys = filteredData.value.map(
(item) => item[keyProp.value]
)
panelState.checked.forEach((item) => {
if (filteredDataKeys.includes(item)) {
checked.push(item)
}
})
panelState.checkChangeByUser = false
panelState.checked = checked
}
)
watch(
() => props.defaultChecked,
(val, oldVal) => {
if (
oldVal &&
val.length === oldVal.length &&
val.every((item) => oldVal.includes(item))
)
return
const checked = []
const checkableDataKeys = checkableData.value.map(
(item) => item[keyProp.value]
)
val.forEach((item) => {
if (checkableDataKeys.includes(item)) {
checked.push(item)
}
})
panelState.checkChangeByUser = false
panelState.checked = checked
},
{
immediate: true,
}
)
return {
labelProp,
keyProp,
disabledProp,
filteredData,
checkableData,
checkedSummary,
isIndeterminate,
updateAllChecked,
handleAllCheckedChange,
}
}