关于javascript:精读BI-搭建-筛选条件

10次阅读

共计 5255 个字符,预计需要花费 14 分钟才能阅读完成。

筛选条件是 BI 搭建的外围概念,咱们大部分所说的摸索式剖析、图表联动也都属于筛选条件的领域, 其本质就是一个组件对另一个组件的数据查问起到筛选作用

筛选组件是如何作用的

咱们最常见的筛选条件就是表单场景的查问控件,如下图所示:

若干“具备输入能力”的组件作为筛选组件,点击查问按钮时触发其作用组件从新取数。

留神这里“具备输入能力”的组件不仅是输入框等具备输出性质的组件,其实所有具备交互能力的组件都能够,甚至能够由一般组件承当筛选触发的能力:

一个表格的表头点击也能够触发筛选行为,或者柱状图的一个柱子被点击都能够,只有进行到这层形象, 组件间联动实质也属于筛选行为

同样重要的,筛选作用的组件也能够是具备输出能力的组件:

当指标组件是具备筛选能力组件时,这就是筛选联动场景了,所以 筛选联动也属于一般筛选行为 。至于指标组件触发取数后,是否立刻批改其筛选值,进而触发后续的筛选联动,就齐全由业务个性决定了。

一个组件也能够本人联动本人筛选,比方折线图点击下钻的场景,就是本人触发了筛选,作用到本人的例子。

什么是筛选组件

任何组件都能够是筛选组件

可能最容易了解的是输入框、下拉框、日期选择器等具备输出特色的组件,这些组件只能说人造适宜作为筛选组件,但不代表零碎设计要为这些组件非凡解决。

扩充想一想,其实一般的按钮、表格、折线图等等 具备展现属性的组件也具备输出个性的一面 ,比方按钮被点击时触发查问、单元格被点击时想查问以后城市的数据趋势、折线图某条线被点击时心愿本身从年下钻到月等等。

所以 不存在筛选组件这概念,而是任何组件都具备筛选的能力 ,因而筛选是一种任何组件都具备的能力,而不局限在某几个组件上,一旦这么设计,能够做到以下几点:

  1. 实现输出类组件到展现类组件的筛选,合乎根本筛选诉求。
  2. 实现展现类组件到展现类组件的筛选,属于图表联动图表的高级性能。
  3. 实现输出类组件到输出类组件的筛选,属于筛选联动性能。
  4. 实现组件本身到本身的筛选,实现下钻性能。

上面介绍 bi-designer 的筛选条件设计。

筛选条件设计

基于上述剖析,bi-designer 在组件元信息中没有减少所谓的筛选组件类型,而是将其设定为一种筛选能力,任何组件都能触发。

如何触发筛选

组件调用 onFilterChange 即可实现筛选动作:

import {useDesigner} from "@alife/bi-designer";  
  
const InputFilter = () => {const { onFilterChange} = useDesigner();  
  
  return (<input onChange={(event) => () => onFilterChange(event.target.value)} />  
  );  
};  

但这种开发方式违反了 低侵入 的设计理念,咱们能够采纳组件与引擎解构的形式,让输入框变更的时候间接调用 props.onChange,这个组件放弃了最大的独立性:

const InputFilter = ({onChange}) => {return <input onChange={(event) => () => onChange(event.target.value)} />;  
};  

那渲染引擎怎么将 onFilterChange 映射到 props.onChange 呢?如下配置 DSL 即可:

{  
  "props": {  
    "onChange": {  
      "type": "JSExpression",  
      "value": "this.onFilterChange"  
    }  
  }  
}  

筛选影响哪些组件

个别筛选组件会抉择作用于的指标组件,相似下图:

这些信息会存储在筛选组件的组件配置中,即 componentInstance.props,筛选指标组件在 componentMeta.eventConfigs 组件元信息的事件中配置:

import {Interfaces} from "@alife/bi-designer";  
  
const componentMeta: Interfaces.ComponentMeta = {eventConfigs: ({ componentInstance}) =>  
    componentInstance.props.targets?.map((target) => ({  
      // 筛选取数  
      type: "filterFetch",  
      // 触发组件  
      source: componentInstance.id,  
      // 作用组件  
      target: target.id,  
    })),  
};  

如上所示,假如作用于组件存储在 props.targets 字段中,咱们将其 map 一下都设置为 filterFetch 类型,示意筛选作用,source 触发源是本人,target 指标组件是存储的 target.id

这样当 source 组件调用了 onFilterChangetarget 组件就会触发取数,并在取数参数中拿到作用于其的筛选组件信息与筛选值。

组件如何感知筛选条件

组件取数是联合了筛选条件一起的,只有如上设置了 filterFetch,渲染引擎会主动在计算取数参数的回调函数 getFetchParam 中增加 filters 代表筛选组件信息,组件能够联合本身 componentInstancefilters 推导出最终取数参数:

最终,组件元信息只有写一个 getFetchParam 回调函数即可, 能够主动拿到作用于它的筛选组件,而不必关怀是哪些配置导致了关联,只有响应式的去解决筛选作用即可

import {Interfaces} from "@alife/bi-designer";  
  
const componentMeta: Interfaces.ComponentMeta = {  
  // 组装取数参数  
  getFetchParam: ({componentInstance, filters}) => {// 联合 componentInstance 与 filters.map... 返回取数参数},  
};  

筛选组件间联动带来的频繁取数问题

对于筛选联动的简单场景,会遇到频繁取数的问题。

假如国家、省、市三级联动筛选条件同时 filterFetch 作用于一个表格,这个表格取数的筛选条件须要同时蕴含国家、省、市三个参数,但咱们又设置了 国家、省、市 这三个筛选组件之间的 filterFetch 作为筛选联动,那么国家切换后、省扭转、联动市扭转,这个过程筛选值会变动三次,但咱们只想表格组件取数函数仅执行最初的一次,怎么办呢?

如上图所示,其实每个筛选条件在渲染引擎数据流中还存储了一个 ready 状态,示意筛选条件是否就绪, 一个组件关联的筛选条件只有有一个 ready 不为 true,组件就不会触发取数

因而咱们须要在筛选变动的过程中,总是保障一个筛选组件的 readyfalse,等筛选间联动结束了,所有筛选器的 readytrue,组件才会取数,咱们能够应用 filterReady 筛选依赖配置:

import {Interfaces, createComponentInstancesArray} from "@alife/bi-designer";  
  
const componentMeta: Interfaces.ComponentMeta = {eventConfigs: ({ componentInstance}) =>  
    componentInstance.props.targets?.map((target) => ({  
      // 筛选就绪依赖  
      type: "filterReady",  
      // 触发组件  
      source: componentInstance.id,  
      // 作用组件  
      target: target.id,  
    })),  
};  

这样配置后,当 source 组件触发 onFilterChange 后,target 组件的筛选 ready 会立刻设置为 false,只有 target 组件取完数后被动触发 onFilterChange 才会将本人的 ready 从新置为 trueThat’a all,其余流程没有任何感知

若干筛选组件聚合成一个查问控件

除了联动外,也会存在避免频繁查问的诉求,心愿将多个筛选条件绑定成一个大筛选组件,在点击“查问”按钮时再取数:

能够利用 筛选作用域 轻松实现此性能,只须要两步:

筛选组件设置独立筛选作用域

import {Interfaces} from "@alife/bi-designer";  
  
const componentMeta: Interfaces.ComponentMeta = {  
  // 通过 componentInstance 判断,如果是全局筛选器外部,则设置 filterScope  
  filterScope: ({componentInstance}) => ["my-custom-scope-name"],  
};  

这样,这批筛选组件就与其作用的组件属于不同的 筛选作用域 了,所以筛选不会对其立刻失效,性能实现了一半。

确认按钮点击时调用 submitFilterScope

import {useDesigner} from '@alife/bi-designer'  
  
const componentMeta: Interfaces.ComponentMeta = {const { submitFilterScope} = useDesigner()  
  // 点击确认按钮时,调用 submitFilterScope('my-custom-scope-name')  
};  

你能够在点击查问按钮后调用 submitFilterScope 并传入对应作用域名称,这样作用域内筛选组件就会立刻对其 target 组件失效了。

至于确认按钮、UI 上的聚合,这些你能够写一个自定义组件去做,利用 ComponentLoader 把筛选组件聚合到一起加载,总之性能与 UI 是解耦的。

如果你对原理感兴趣,能够再多看一下这张图:

冲破筛选作用域

然而理论场景中,可能存在更简单的组合,见上面的例子:

筛选器 1 同时对 筛选器 2、表格 产生筛选作用 filterFetch,但对 表格 的作用心愿通过查问按钮拦挡住,而对 筛选器 2 的作用心愿能立刻失效,对于这个例子有两种形式解决:

最简略的形式就是将 筛选器 1、筛选器 2 设置为雷同作用域 group1,这样就通过作用域宰割天然实现了成果, 而且这实质上是两个筛选器 UI 不在一起,但筛选作用域雷同的例子

然而再变动一下,如果筛选器 2 也对表格产生筛选作用,那咱们将 筛选器 1、筛选器 2 放入同一个 group1 等于对表格的查问都会受到“查问”按钮的管制,但 咱们又心愿筛选器 2 能够立刻作用于表格

如图所示,咱们只能将 筛选器 1 的筛选作用域设置为 group1,这样 筛选器 2 与 表格 属于同一个筛选作用域,他们之间筛选会立刻失效,咱们只有解决 筛选器 1 不能立刻作用于 筛选器 2 的问题即可,能够通过 ignoreFilterScope 形式冲破筛选作用域:

import {Interfaces} from "@alife/bi-designer";  
  
const componentMeta: Interfaces.ComponentMeta = {eventConfigs: ({ componentInstance}) =>  
    componentInstance.props.targets?.map((target) => ({  
      // 筛选取数  
      type: "filterFetch",  
      // 触发组件  
      source: componentInstance.id,  
      // 作用组件  
      target: target.id,  
      // 冲破筛选作用域  
      ignoreFilterFetch: true,  
    })),  
};  

咱们只有在 source: 筛选器 1 target: 筛选器 2 filterFetch 配置中,将 ignoreFilterFetch 设置为 true,这个 filterFetch 就会疏忽筛选作用域,实现立刻 筛选器 1 立刻作用到 筛选器 2 的成果。

总结

你还有哪些非凡的筛选诉求?能够用这套筛选设计解决吗?

探讨地址是:精读《BI 搭建 – 筛选条件》· Issue #270 · dt-fe/weekly

如果你想参加探讨,请 点击这里,每周都有新的主题,周末或周一公布。前端精读 – 帮你筛选靠谱的内容。

关注 前端精读微信公众号

版权申明:自在转载 - 非商用 - 非衍生 - 放弃署名(创意共享 3.0 许可证)

正文完
 0