UNPKG

@fesjs/fes-design

Version:
227 lines (223 loc) 7.43 kB
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 };