【EasyPage 教你写表单04】- 搜索下拉框

32 阅读2分钟

搜索下拉框

在表单中,下拉框的处理也是一个比较复杂的场景,它复杂在:

  • 可以基于搜索,去获取下拉框选项数据。
  • 在编辑的时,需要进行回填,之前基于关键词搜索的选项,在回填时,查询选项或还需再查询一次。
  • 回填时,基于回填的选项里额外的信息,做相关提示信息展示。

案例

上述描述,可能有点云里雾里,我们可以通过下述例子来感受其复杂:

  • 创建一个下拉框
    import {
      Empty,
      SelectEffectType,
      SelectState,
      UI_COMPONENTS,
      nodeUtil,
    } from '@easy-page/antd-ui';
    
    import type { DefaultOptionType } from 'antd/es/select';
    type GoodState = SelectState<number, { mark: string }>;
    
    export const goods = nodeUtil.createField<
      GoodState,
      { goods: GoodState },
      Empty,
      SelectEffectType<{ mark: string }>
    >(
      'goods',
      '商品',
      {
        /** 默认选中一个选项的 id **/
        value: { choosed: 1 },
        required: true,
        mode: 'single',
      },
      {
        ui: UI_COMPONENTS.SELECT,
        select: {
          /** 下拉框 antd 的一些配置,便于后续做搜索功能 **/
          showSearch: true,
          notFoundContent: null,
          filterOption: false,
        },
      }
    );
    
  • 增加 action 副作用加载数据。
    • 初始化时,加载默认查询选项;如果查询选项中不包含默认选中的选项,则基于 ID 查询该选项;合并查询结果并返回。
    • 在搜索时,基于关键词,查询选项;同理如果查询的选项中不包含已选择选项,则继续查询一次。
    export const goods = nodeUtil.createField<
      GoodState,
      { goods: GoodState },
      Empty,
      SelectEffectType<{ mark: string }>
    >(
      'goods',
      '商品',
      {
        ...
        actions: [
          {
            /** 监听自身 value 的变化,感知 keyword 变化,执行副作用。 **/
            effectedKeys: ['goods'],
            /** 初始化执行 */
            initRun: true,
            /** 初始化查询选中数据 */
            action: async ({ value, initRun }) => {
              /** 只有初始化时,或者存在关键词时才做查询 **/
              if (initRun || value.keyword !== undefined) {
                /** 查询选项 */
                const options = (await searchByKeywords(value.keyword)) || [];
                const hasChoosed = options.find((x) => x.value === value.choosed);
                if (value.choosed && !hasChoosed) {
                  /** 选择的选项不在查询的列表中,单独搜索选中选项 */
                  const choosed = await searchById(value.choosed);
                  return {
                    fieldValue: {
                      ...value,
                      options: [choosed, ...options],
                      keyword: undefined,
                    },
                  };
                }
                return { fieldValue: { ...value, options, keyword: undefined } };
              }
              return {};
            },
          },
        ],
      },
      ...
    );
    
    

改进

从上面示例的:action 中可见其复杂程度,当然这样的逻辑,我们可以抽象到底层基础组件。这样我们的 action 逻辑就会变成:

import { searchAction } from '@easy-page/antd-ui';

  export const goods = nodeUtil.createField<
    GoodState,
    { goods: GoodState },
    Empty,
    SelectEffectType<{ mark: string }>
  >(
    'goods',
    '商品',
    {
      ...
      actions: [
        {
          ...
          action: async ({ value, initRun }) => {
            return searchAction<number, { mark: string }>({
              async searchByChoosed(choosed) {
                const result = await searchById(choosed);
                return result ? [result] : [];
              },
              async searchByKeyword(keyword) {
                const result = await searchByKeywords(keyword);
                return result || [];
              },
              initRun,
              value,
            });
          },
        },
      ],
    },
    ...
  );

 

Demo

我们来看看此时的实际效果:

image.png

文档站:easy-page.github.io/easy-page-d…