From 00a97e6b137559a588228873fec1e4b1e5bc68c3 Mon Sep 17 00:00:00 2001 From: Kagol Date: Wed, 20 Nov 2024 17:01:01 +0800 Subject: [PATCH 1/3] feat(tree-select): add data init function --- .../basic-usage-composition-api.vue | 2 +- .../demos/pc/app/tree-select/basic-usage.vue | 2 +- .../collapse-tags-composition-api.vue | 2 +- .../pc/app/tree-select/collapse-tags.vue | 2 +- .../tree-select/multiple-composition-api.vue | 2 +- .../demos/pc/app/tree-select/multiple.vue | 2 +- packages/renderless/src/tree-select/index.ts | 123 ++++++++++++++++++ packages/renderless/src/tree-select/vue.ts | 24 +++- packages/vue/src/tree-select/src/pc.vue | 2 + 9 files changed, 148 insertions(+), 13 deletions(-) diff --git a/examples/sites/demos/pc/app/tree-select/basic-usage-composition-api.vue b/examples/sites/demos/pc/app/tree-select/basic-usage-composition-api.vue index 1ba6505759..313bb1d112 100644 --- a/examples/sites/demos/pc/app/tree-select/basic-usage-composition-api.vue +++ b/examples/sites/demos/pc/app/tree-select/basic-usage-composition-api.vue @@ -6,7 +6,7 @@ import { ref } from 'vue' import { TinyTreeSelect } from '@opentiny/vue' -const value = ref('') +const value = ref(4) const treeOp = ref({ data: [ diff --git a/examples/sites/demos/pc/app/tree-select/basic-usage.vue b/examples/sites/demos/pc/app/tree-select/basic-usage.vue index 125c778ca9..424d85ce20 100644 --- a/examples/sites/demos/pc/app/tree-select/basic-usage.vue +++ b/examples/sites/demos/pc/app/tree-select/basic-usage.vue @@ -11,7 +11,7 @@ export default { }, data() { return { - value: '', + value: 10, treeOp: { data: [ { diff --git a/examples/sites/demos/pc/app/tree-select/collapse-tags-composition-api.vue b/examples/sites/demos/pc/app/tree-select/collapse-tags-composition-api.vue index 91675b37ca..a831d77b43 100644 --- a/examples/sites/demos/pc/app/tree-select/collapse-tags-composition-api.vue +++ b/examples/sites/demos/pc/app/tree-select/collapse-tags-composition-api.vue @@ -17,7 +17,7 @@ import { ref } from 'vue' import { TinyTreeSelect } from '@opentiny/vue' -const value = ref([]) +const value = ref([9, 6]) const treeOp = ref({ data: [ diff --git a/examples/sites/demos/pc/app/tree-select/collapse-tags.vue b/examples/sites/demos/pc/app/tree-select/collapse-tags.vue index ee2db32f97..1b8d64c7bf 100644 --- a/examples/sites/demos/pc/app/tree-select/collapse-tags.vue +++ b/examples/sites/demos/pc/app/tree-select/collapse-tags.vue @@ -22,7 +22,7 @@ export default { }, data() { return { - value: [], + value: [9, 6], treeOp: { data: [ { diff --git a/examples/sites/demos/pc/app/tree-select/multiple-composition-api.vue b/examples/sites/demos/pc/app/tree-select/multiple-composition-api.vue index b79c6846d2..63ddbaa4bd 100644 --- a/examples/sites/demos/pc/app/tree-select/multiple-composition-api.vue +++ b/examples/sites/demos/pc/app/tree-select/multiple-composition-api.vue @@ -6,7 +6,7 @@ import { ref } from 'vue' import { TinyTreeSelect } from '@opentiny/vue' -const value = ref([]) +const value = ref([9, 6]) const treeOp = ref({ data: [ diff --git a/examples/sites/demos/pc/app/tree-select/multiple.vue b/examples/sites/demos/pc/app/tree-select/multiple.vue index cff5f57fea..5efcbedf77 100644 --- a/examples/sites/demos/pc/app/tree-select/multiple.vue +++ b/examples/sites/demos/pc/app/tree-select/multiple.vue @@ -11,7 +11,7 @@ export default { }, data() { return { - value: [], + value: [9, 6], treeOp: { data: [ { diff --git a/packages/renderless/src/tree-select/index.ts b/packages/renderless/src/tree-select/index.ts index 1b757fe722..908ca85bdb 100644 --- a/packages/renderless/src/tree-select/index.ts +++ b/packages/renderless/src/tree-select/index.ts @@ -1,9 +1,17 @@ +import { find } from '../common/array' + +/** + * 树节点过滤事件 + */ export const filter = ({ vm }) => (value) => { vm.$refs.treeRef.filter(value) } +/** + * 单选,节点选择事件 + */ export const nodeClick = ({ props, vm, emit }) => (data) => { @@ -24,6 +32,9 @@ export const nodeClick = } } +/** + * 多选,勾选事件 + */ export const check = ({ props, vm, emit }) => (data, { checkedNodes }) => { @@ -47,3 +58,115 @@ export const check = emit('update:modelValue', currentValue) } } + +/** + * 嵌套树结构转成扁平树结构 + * @params data 嵌套树结构 示例:[{ children: [ { label: '二级 1-1', value: 4 }, ... ], label: '一级 1', value: 1 }, ...] + * @return 扁平树结构 示例:[{ label: '一级 1', value: 1, pId: null }, { label: '二级 1-1', value: 4, pId: 1 }, ...] + */ +export const getTreeData = + ({ props, state }) => + (data) => { + const nodes = [] + const getChild = (data, pId) => { + data.forEach((node) => { + node.pId = pId + nodes.push(node) + + if (node[state.childrenName] && node[state.childrenName].length > 0) { + getChild(node[state.childrenName], node[props.valueField]) + } + }) + } + + getChild(data, null) + + return nodes + } + +/** + * 多选,获取匹配的树节点 + * @params value 树节点 value + * @return 完整的树节点 示例:[{ label: "三级 1-1-2", value: 10, pId: 1, children: [...] }] + */ +export const getPluginOption = + ({ api, props, state }) => + (value) => { + const isRemote = + (props.filterable || props.searchable) && + props.remote && + (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function') + const { textField, valueField } = props + const sourceData = isRemote ? state.remoteData : api.getTreeData(state.treeData) + const selNode = find(sourceData, (item) => item[valueField] === value) + const items = [] + + if (selNode) { + selNode.currentLabel = selNode[textField] + items.push(selNode) + } + + return items + } + +/** + * 多选,获取选中的树节点 value 数组,用于初始化树节点的勾选状态 + * @return 示例:[9, 6] + */ +export const getCheckedData = + ({ props, state }) => + () => { + const checkedKey = [] + + if (!Array.isArray(state.selected)) { + return props.modelValue ? [props.modelValue] : [state.selected[props.valueField]] + } else { + state.selected.length > 0 && + state.selected.forEach((item) => { + checkedKey.push(item[props.valueField]) + }) + + return checkedKey + } + } + +export const mounted = + ({ api, state, props, vm }) => + () => { + if (!state.value || state.value.length === 0) return + + if (props.multiple) { + let initialNodes = [] + if (Array.isArray(state.value)) { + state.value.forEach((value) => { + const option = api.getPluginOption(value) + initialNodes = initialNodes.concat(option) + }) + } + + vm.$refs.baseSelectRef.updateSelectedData( + initialNodes.map((node) => { + return { + ...node, + currentLabel: node[props.textField], + value: node[props.valueField], + isTree: true + } + }) + ) + + state.defaultCheckedKeys = api.getCheckedData()[0] + } else { + const data = api.getPluginOption(state.value)[0] + vm.$refs.baseSelectRef.updateSelectedData({ + ...data, + currentLabel: data[props.textField], + value: data[props.valueField], + state: { + currentLabel: data[props.textField] + } + }) + + state.currentKey = data[props.valueField] + } + } diff --git a/packages/renderless/src/tree-select/vue.ts b/packages/renderless/src/tree-select/vue.ts index 4836dbaab6..838df28186 100644 --- a/packages/renderless/src/tree-select/vue.ts +++ b/packages/renderless/src/tree-select/vue.ts @@ -1,20 +1,28 @@ -import { filter, nodeClick, check } from './index' +import { check, filter, getCheckedData, getPluginOption, getTreeData, mounted, nodeClick } from './index' -export const api = ['state', 'filter', 'nodeClick', 'check'] +export const api = ['state', 'check', 'filter', 'nodeClick'] -export const renderless = (props, { reactive, computed, watch }, { vm, emit }) => { +export const renderless = (props, { reactive, computed, watch, onMounted }, { vm, emit }) => { const api = {} const state = reactive({ - value: computed(() => props.modelValue), - treeData: props.treeOp.data + childrenName: computed(() => (props.treeOp.props && props.treeOp.props.children) || 'children'), + currentKey: props.modelValue, + defaultCheckedKeys: [], + remoteData: [], + treeData: props.treeOp.data, + value: computed(() => props.modelValue) }) Object.assign(api, { state, + check: check({ props, vm, emit }), filter: filter({ vm }), - nodeClick: nodeClick({ props, vm, emit }), - check: check({ props, vm, emit }) + getCheckedData: getCheckedData({ props, state }), + getPluginOption: getPluginOption({ api, props, state }), + getTreeData: getTreeData({ props, state }), + mounted: mounted({ api, state, props, vm }), + nodeClick: nodeClick({ props, vm, emit }) }) watch( @@ -23,5 +31,7 @@ export const renderless = (props, { reactive, computed, watch }, { vm, emit }) = { immediate: true, deep: true } ) + onMounted(api.mounted) + return api } diff --git a/packages/vue/src/tree-select/src/pc.vue b/packages/vue/src/tree-select/src/pc.vue index 5f4f279262..1c7dd7a55d 100644 --- a/packages/vue/src/tree-select/src/pc.vue +++ b/packages/vue/src/tree-select/src/pc.vue @@ -11,7 +11,9 @@