diff --git a/packages/fighting-design/option/src/option.vue b/packages/fighting-design/option/src/option.vue index 783247ee9..57b5f1aec 100644 --- a/packages/fighting-design/option/src/option.vue +++ b/packages/fighting-design/option/src/option.vue @@ -3,7 +3,8 @@ import { useRun } from '../../_hooks' import { isString, isArray, isObject } from '../../_utils' import { TRIGGER_CLOSE_KEY } from '../../trigger/src/props' - import { inject, toRefs, useSlots, computed } from 'vue' + import { inject, useSlots, computed } from 'vue' + import { warning } from '../../_utils' import { SELECT_PROPS_TOKEN } from '../../select/src/props' import type { SelectProvide, SelectModelValue } from '../../select' import type { TriggerProvide } from '../../trigger' @@ -27,9 +28,16 @@ return '' } - const _slot: VNodeNormalizedChildren | string = slot.default()[0].children + /** 获取到插槽的内容 */ + const content: VNodeNormalizedChildren | string = slot.default()[0].children - return isString(_slot) ? _slot : '' + // 如果不是字符串,暂时无法处理,先警告信息,返回空字符串 + if (!isString(content)) { + warning('f-option', 'slot content is not a string') + return '' + } + + return content }) /** 控制是否显示 */ @@ -39,20 +47,8 @@ return false } - // 没有 filter 属性,则展示 - if (!parentInject.filter) { - return true - } - - /** 获取到 label */ - const label = slotLabel.value || prop.label?.toString() || prop.value?.toString() - /** 获取到选中的项目 */ - const currentItem = parentInject.childrenLabels.find(item => { - return item.slot === label - }) - - if (currentItem) { - return currentItem.show + if (parentInject.filter && parentInject.isFiltering) { + return (currentLabel as string).includes(parentInject.inputValue) } return true @@ -83,7 +79,7 @@ * * @param {*} values 参数集合 */ - const getEffectiveValue = (...values: any[]): any => { + const getEffectiveValue = (...values: any[]): string => { // 没有数据返回空字符串 if (!values || !values.length) { return '' @@ -113,6 +109,32 @@ return effectiveValue !== void 0 ? effectiveValue : values[values.length - 1] } + /** + * 最新的 label + * + * 返回优先级:插槽 > label > value + */ + const currentLabel: SelectModelValue = getEffectiveValue( + slotLabel.value, + prop.label, + prop.value + ) + + /** + * 最新的 value + * + * 返回优先级:value > label > 插槽 + */ + const currentValue: SelectModelValue = getEffectiveValue( + prop.value, + prop.label, + slotLabel.value + ) + + if (currentValue === parentInject?.modelValue) { + parentInject && run(parentInject.setValue, currentValue, currentLabel) + } + /** * 点击传入指定的 value * @@ -124,32 +146,8 @@ // 如果没有获取到注入的依赖项或者禁用状态 则返回 if (!parentInject || prop.disabled) return - const { value, label } = toRefs(prop) - - /** - * 最新的 label - * - * 返回优先级:插槽 > label > value - */ - const currentLabel: SelectModelValue = getEffectiveValue( - slotLabel.value, - label.value, - value.value - ) - - /** - * 最新的 value - * - * 返回优先级:value > label > 插槽 - */ - const currentValue: SelectModelValue = getEffectiveValue( - value.value, - label.value, - slotLabel.value - ) - // 执行父组件的设置方法 - parentInject && run(parentInject.setValue, currentValue, currentLabel, evt) + run(parentInject.setValue, currentValue, currentLabel, evt) // 点击之后关闭 triggerInject && run(triggerInject.close) } diff --git a/packages/fighting-design/select/src/select.vue b/packages/fighting-design/select/src/select.vue index 886850927..4bac672c0 100644 --- a/packages/fighting-design/select/src/select.vue +++ b/packages/fighting-design/select/src/select.vue @@ -2,23 +2,14 @@ import { Props, SELECT_PROPS_TOKEN } from './props' import { FInput } from '../../input' import { useList, useRun } from '../../_hooks' - import { - provide, - computed, - useSlots, - ref, - reactive, - toRef, - nextTick, - watch, - onBeforeUnmount - } from 'vue' + import { provide, computed, useSlots, ref, reactive, toRef, nextTick } from 'vue' import { FDropdown } from '../../dropdown' import { getChildren, isFunction } from '../../_utils' import { FSvgIcon } from '../../svg-icon' + import { FEmpty } from '../../empty' import { FIconChevronDown } from '../../_svg' - import type { VNode, Slots, WatchStopHandle } from 'vue' - import type { SelectProvide, SelectModelValue, SelectChildren } from './interface' + import type { VNode, Slots } from 'vue' + import type { SelectProvide, SelectModelValue } from './interface' defineOptions({ name: 'FSelect' }) @@ -42,6 +33,10 @@ const selectContentRef = ref() /** 是否有搜索内容 */ const isHaveValues = ref(true) + /** 文本框绑定的值 */ + const inputValue = ref('') + /** 是否正在输入过滤搜索中 */ + const isFiltering = ref(false) /** * 获取子元素 option @@ -55,64 +50,6 @@ return getChildren(slot.default(), 'FOption') }) - /** 当前绑定的值 */ - const keyword = computed({ - get: (): string => { - // 如果插槽没内容,则返回空字符串 - if (!options.value.length) return '' - - /** - * 通过插槽内容 - * - * 过滤出和绑定值相同的那一项 - */ - const currentOption: VNode[] = options.value.filter((node: VNode): boolean => { - /** 获取到子组件的 props */ - const optionProp = node.props - - // 判断是否有传递 props - if (optionProp) { - return optionProp.value - ? `${optionProp.value}` === `${prop.modelValue}` - : `${optionProp.label}` === `${prop.modelValue}` - } - - /** - * 如果没有传递 props 则根据插槽来判断 - * - * 放心,这里一定会有插槽,子组件已经做了判断 - */ - return (node as SelectChildren).children.default()[0].children === prop.modelValue - }) - - /** - * 如果没有通过插槽找出和绑定值相同的 - * - * 则返回空 - */ - if (!currentOption.length) return '' - - /** 获取到当前满足要求的子元素 */ - const firstChildren: VNode = currentOption[0] - - /** 获取到当前子元素的插槽内容 */ - const slot: string | undefined = - firstChildren.children && - (firstChildren.children as { default: Function }).default()[0].children - /** 获取到当前子元素的 label 参数 */ - const label: string | undefined = firstChildren.props?.label - /** 获取到当前子元素的 value 参数 */ - const value: string | undefined = firstChildren.props?.value - - // 返回优先级:插槽 > label > value - return slot || label || (value && value.toString()) || '' - }, - set: (val: string): string => { - modelValue.value = val - return val - } - }) - /** * 设置新的值 * @@ -123,41 +60,21 @@ const setValue = ( currentValue: SelectModelValue, currentLabel: SelectModelValue, - evt: MouseEvent + evt?: MouseEvent ): void => { - // 设置文本框展示的内容 - keyword.value = currentValue.toString() - - // 如果最新的 value 和绑定的 value 不一致时,才触发 change 事件 - if (currentLabel !== prop.modelValue) { + /** + * 如果最新的 value 和绑定的 value 不一致时 + * + * 而且还需要带有 evt 对象的时候才需要触发 change 事件 + * + * 如果没有 evt 对象,则代表是首次赋值,则不予触发 + */ + if (currentLabel !== prop.modelValue && evt) { run(prop.onChange, currentValue, currentLabel, evt) } modelValue.value = currentValue - } - - /** - * 设置子节点的展示状态和 label - */ - const setChildrenLabels = (): void => { - if (!options.value || !options.value.length) { - childrenLabels.value = [] - } - - childrenLabels.value = options.value.map((item: VNode) => { - /** 获取到当前子元素的插槽内容 */ - const slot: string = - item.children && (item.children as { default: Function }).default()[0].children - - return { slot, show: !!(slot && slot.includes(modelValue.value.toString())) } - }) - - // 如果是过滤状态,判断是否存在搜索结果 - if (prop.filter) { - const isHave: boolean = childrenLabels.value.some(y => y.show) - - isHaveValues.value = isHave - } + inputValue.value = currentLabel?.toString() } /** 下拉菜单开启之后的回调 */ @@ -187,23 +104,6 @@ } } - /** 监听器实例 */ - const watchStopHandle = ((): WatchStopHandle | undefined => { - if (!prop.filter) { - return - } - return watch((): SelectModelValue => modelValue.value, setChildrenLabels, { - immediate: true - }) - })() - - // 页面卸载的时候,如何有监听器 则停止 - onBeforeUnmount(() => { - if (watchStopHandle) { - watchStopHandle() // 监听器实例 - } - }) - // 向子组件注入依赖项 provide( SELECT_PROPS_TOKEN, @@ -211,7 +111,9 @@ setValue, childrenLabels, modelValue: toRef(prop, 'modelValue'), - filter: toRef(prop, 'filter') + filter: toRef(prop, 'filter'), + inputValue, + isFiltering }) ) @@ -221,18 +123,35 @@ const inputBlur = (): void => { isFocus.value = false + if (prop.filter) { + isFiltering.value = false + } + // 失去焦点的时候如果子节点的 title 中不包含输入项目,则情况文本框的内容 if (!isHaveValues.value) { - keyword.value = '' + inputValue.value = '' } } + + const inputFocus = (): void => { + isFocus.value = true + + // if (prop.filter) { + // isFiltering.value = true + // } + } + + const inputInput = (): void => { + console.log('change') + isFiltering.value = true + }