@fesjs/fes-design
Version:
fes-design for PC
227 lines (223 loc) • 7.43 kB
JavaScript
import { defineComponent, watch, computed, provide, createVNode } from 'vue';
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
import { cloneDeep } from 'lodash-es';
import getPrefixCls from '../_util/getPrefixCls';
import { useTheme } from '../_theme/useTheme';
import { useLocale } from '../config-provider/useLocale';
import CascaderMenu from './cascaderMenu';
import { COMPONENT_NAME, CHECK_STRATEGY } from './const';
import useData from './useData';
import useState from './useState';
import { CASCADER_PROVIDE_KEY, cascaderProps } from './props';
import { handleParent, handleChildren } from './helper';
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
const prefixCls = getPrefixCls('cascader');
var cascader = defineComponent({
name: COMPONENT_NAME.CASCADER,
props: _objectSpread({}, cascaderProps),
emits: ['update:expandedKeys', 'update:checkedKeys', 'update:selectedKeys', 'update:nodeList', 'check', 'expand', 'load', 'select'],
setup(props, _ref) {
let {
emit,
expose
} = _ref;
useTheme();
watch([() => props.multiple, () => props.cascade, () => props.checkStrictly], () => {
const multipleCheckStrictlyList = [CHECK_STRATEGY.ALL, CHECK_STRATEGY.PARENT, CHECK_STRATEGY.CHILD];
const singleCheckStrictlyList = [CHECK_STRATEGY.ALL, CHECK_STRATEGY.CHILD];
if (props.multiple && props.cascade && !multipleCheckStrictlyList.includes(props.checkStrictly)) {
console.warn(`[${COMPONENT_NAME.CASCADER}]: multiple 和 cascade 为 true 时, checkStrictly 仅支持 ${multipleCheckStrictlyList.join('、')}`);
}
if (!props.multiple && !singleCheckStrictlyList.includes(props.checkStrictly)) {
console.warn(`[${COMPONENT_NAME.CASCADER}]: multiple 为 false 时, checkStrictly 仅支持 ${singleCheckStrictlyList.join('、')}`);
}
}, {
immediate: true
});
const {
currentExpandedKeys,
updateExpandedKeys,
currentCheckedKeys,
updateCheckedKeys,
currentSelectedKeys,
updateSelectedKeys,
hasSelected,
hasChecked,
hasLoaded,
hasCheckLoaded,
hasActive
} = useState(props, {
emit
});
const {
transformData,
nodeList,
menuKeys,
initialLoaded
} = useData({
props,
currentExpandedKeys
});
// 清空 data 时,置空 expandedKeys、selectedKeys、checkedKeys
watch(() => props.data, nextData => {
if (nextData.length === 0) {
updateExpandedKeys([]);
updateCheckedKeys([]);
updateSelectedKeys([]);
}
});
watch(nodeList, () => {
emit('update:nodeList', nodeList);
}, {
immediate: true
});
const {
t
} = useLocale();
const listEmptyText = computed(() => props.emptyText || t('select.emptyText'));
const updateExpandedKeysBySelectOrCheck = (val, event) => {
const node = nodeList[val];
// 叶子节点也包含在内,以便操作反馈
const values = [...node.indexPath];
updateExpandedKeys(values);
emit('expand', {
expandedKeys: values,
event,
node,
expanded: values.includes(val)
});
};
const selectNode = (val, event) => {
if (!props.selectable) {
return;
}
updateExpandedKeysBySelectOrCheck(val, event);
const node = nodeList[val];
const values = cloneDeep(currentSelectedKeys.value);
const index = values.indexOf(val);
if (props.multiple) {
if (index !== -1) {
if (props.cancelable) {
values.splice(index, 1);
}
} else {
values.push(val);
}
} else if (index !== -1) {
if (props.cancelable) {
values.splice(index, 1);
}
} else {
values[0] = val;
}
updateSelectedKeys(values);
emit('select', {
selectedKeys: values,
event,
node,
selected: values.includes(val)
});
};
const expandNode = (val, event) => {
const node = nodeList[val];
const values = [...node.indexPath];
updateExpandedKeys(values);
emit('expand', {
expandedKeys: values,
event,
node,
expanded: values.includes(val)
});
};
function getCheckedKeys(arr) {
return props.cascade ? arr.filter(key => {
const node = nodeList[key];
// 兼容异步加载,未匹配到节点的情况
if (!node) {
return false; // 清除未匹配到的选中项
}
if (props.checkStrictly === CHECK_STRATEGY.ALL) {
return true;
}
if (props.checkStrictly === CHECK_STRATEGY.PARENT) {
return node.indexPath.filter(path => arr.includes(path)).length === 1;
}
if (props.checkStrictly === CHECK_STRATEGY.CHILD) {
return node.isLeaf;
}
return true;
}) : arr;
}
const checkNode = (val, event) => {
updateExpandedKeysBySelectOrCheck(val, event);
const node = nodeList[val];
const {
isLeaf,
children,
indexPath
} = node;
const values = cloneDeep(currentCheckedKeys.value);
const index = values.indexOf(val);
if (!props.cascade) {
if (index !== -1) {
values.splice(index, 1);
} else {
values.push(val);
}
} else if (index !== -1) {
values.splice(index, 1);
handleParent(values, indexPath, false, nodeList);
if (!isLeaf) {
handleChildren(values, children, false);
}
} else {
values.push(val);
handleParent(values, indexPath, true, nodeList);
if (!isLeaf) {
handleChildren(values, children, true);
}
}
updateCheckedKeys(values);
emit('check', {
checkedKeys: getCheckedKeys(values),
event,
node,
checked: values.includes(val)
});
};
if (expose) {
expose({
selectNode,
expandNode,
checkNode
});
}
provide(CASCADER_PROVIDE_KEY, {
props,
selectNode,
expandNode,
checkNode,
hasSelected,
hasChecked,
hasLoaded,
hasCheckLoaded,
hasActive,
transformData,
nodeList
});
const renderMenu = key => {
return createVNode(CascaderMenu, {
"menuKey": key,
"initialLoaded": initialLoaded.value,
"listEmptyText": listEmptyText.value
}, null);
};
const renderMenus = arr => arr.map(key => renderMenu(key));
return () => createVNode("div", {
"class": prefixCls,
"role": "cascader"
}, [renderMenus(menuKeys.value)]);
}
});
export { cascader as default };