前端自定义左树右表中的树

在 oinone 平台中,提供了默认的左树右表的视图,用户可以通过界面设计器配置,默认的树视图不一定满足所有需求,尤其当需要自定义功能或复杂的交互时,我们可以通过自定义视图来实现更灵活的展现。

本文将带你一步步了解如何自定义左树右表视图中的树组件。

自定义树视图

1. 使用界面设计器配置视图

首先,我们需要通过界面设计器生成基础的左树右表视图。界面设计器允许用户根据不同需求进行拖拽配置,快速创建可视化界面。

配置完视图之后,我们可以重写左侧的树组件。Oinone 的默认树组件是 TableSearchTreeWidget,通过自定义的方式,我们可以实现更高级的功能。

2. 重写 TableSearchTreeWidget

import { BaseElementWidget, SPI, TableSearchTreeWidget, ViewType } from '@kunlun/dependencies';
import CustomTableSearchTree from './CustomTableSearchTree.vue';

@SPI.ClassFactory(
  BaseElementWidget.Token({
    viewType: [ViewType.Table, ViewType.Form],
    widget: 'tree',
    model: 'resource.k2.Model0000000100' // 改成自己的模型
  })
)
export class CustomTableSearchTreeWidget extends TableSearchTreeWidget {
  public initialize(props) {
    super.initialize(props);
    this.setComponent(CustomTableSearchTree);
    return this;
  }
}

3. 定义 Vue 树组件

接下来,我们来实现 CustomTableSearchTree.vue 组件。这个组件将处理树的数据加载、节点选中等逻辑。你可以根据项目的需要修改其中的交互逻辑或 UI 设计。

<template>
  <a-tree :load-data="onLoadData" :tree-data="treeData" @select="onSelected" />
</template>
<script lang="ts">
import { OioTreeNode, TreeUtils } from '@kunlun/dependencies';
import { computed, defineComponent } from 'vue';

export default defineComponent({
  props: {
    rootNode: {
      type: Object
    },
    loadData: {
      type: Function,
      required: true
    },
    onSelected: {
      type: Function,
      required: true
    }
  },
  setup(props) {
    // // 计算树的数据源,使用 TreeUtils 处理
    const treeData = computed(() => {
      return TreeUtils.fillLoadMoreAction([...(props.rootNode?.children || [])]);
    });

    // 异步加载子节点
    const onLoadData = async (node) => {
      return await props.loadData(node.dataRef);
    };

    // 处理节点选中事件
    const onSelected = (
      selectedKeys: string[],
      e: { nativeEvent: PointerEvent; node: { dataRef: OioTreeNode }; selected: boolean }
    ) => {
      props.onSelected?.(e.node.dataRef, e.selected);
    };

    return {
      treeData,

      onLoadData,
      onSelected
    };
  }
});
</script>

4. 自定义 UI

如果你希望修改树组件的 UI,比如调整样式或交互方式,可以在 CustomTableSearchTree.vue 文件中根据需要进行调整。通过这个自定义组件,你可以灵活地控制树的外观和行为,满足具体的业务需求。

默认选择第一条数据

有时在使用树结构时,我们希望页面加载后默认选中第一条数据。为此,我们可以监听 treeData 的变化,并在数据加载完成时,自动触发选中第一条记录的操作。

const stop = watch(
  () => treeData.value.length,
  async (len) => {
    if (!len) {
      return;
    }

    // 选中树中的第一条记录
    selectedKeys.value = [treeData.value[0].key];
    props.onSelected?.(treeData.value[0].value.metadata, true);
    stop(); // 停止监听
  },
  {
    immediate: true
  }
);

表格的新建按钮,获取选中的树节点

在树组件中,我们希望右侧的表格的上方的 新建按钮 点击的时候,可以获取当前树的 ID 作为条件传递给后端。那么这个时候,我们需要通过自定义 action 的方式来实现。

可以参考这篇文章

Oinone社区 作者:汤乾华原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/18420.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
汤乾华的头像汤乾华数式员工
上一篇 2024年10月18日 am9:37
下一篇 2024年10月21日 pm3:41

相关推荐

  • oio-drawer抽屉

    屏幕边缘滑出的浮层面板。 何时使用 抽屉从父窗体边缘滑入,覆盖住部分父窗体内容。用户在抽屉内操作时不必离开当前任务,操作完成后,可以平滑地回到原任务。 当需要一个附加的面板来控制父窗体内容,这个面板在需要时呼出。比如,控制界面展示样式,往界面中添加内容。 当需要在当前任务流中插入临时任务,创建或预览附加内容。比如展示协议条款,创建子对象。 API 参数 说明 类型 默认值 版本 class 对话框外层容器的类名 string – closable 是否显示左上角的关闭按钮 boolean true closeIcon 自定义关闭图标 VNode | slot destroyOnClose 关闭时销毁 Drawer 里的子元素 boolean false footer 抽屉的页脚 VNode | slot – getTriggerContainer 指定 Drawer 挂载的 HTML 节点 HTMLElement | () => HTMLElement | Selectors ‘body’ height 高度, 在 placement 为 top 或 bottom 时使用 string | number keyboard 是否支持键盘 esc 关闭 boolean true mask 是否展示遮罩 Boolean true maskClosable 点击蒙层是否允许关闭 boolean true placement 抽屉的方向 ‘top’ | ‘right’ | ‘bottom’ | ‘left’ ‘right’ style 可用于设置 Drawer 最外层容器的样式,和 drawerStyle 的区别是作用节点包括 mask CSSProperties – title 标题 string | slot – visible(v-model:visible) Drawer 是否可见 boolean – width 宽度 string | number 378 zIndex 设置 Drawer 的 z-index Number 1000 cancelCallback 点击遮罩层或右上角叉或取消按钮的回调, return true则关闭弹窗 function(e) enterCallback 点击确定回调 function(e)

    2023年12月18日
    1.2K00
  • oio-button 按钮

    主按钮:用于主行动点,一个操作区域只能有一个主按钮。 默认按钮:用于没有主次之分的一组行动点。 虚线按钮:常用于添加操作。 文本按钮:用于最次级的行动点。 链接按钮:一般用于链接,即导航至某位置。 以及四种状态属性与上面配合使用。 危险:删除/移动/修改权限等危险操作,一般需要二次确认。 禁用:行动点不可用的时候,一般需要文案解释。 加载中:用于异步操作等待反馈的时候,也可以避免多次提交。 API 按钮的属性说明如下: 属性 说明 类型 默认值 版本 block 将按钮宽度调整为其父宽度的选项 boolean false disabled 按钮失效状态 boolean false icon 设置按钮的图标类型 v-slot – loading 设置按钮载入状态 boolean | { delay: number } false type 设置按钮类型 primary | ghost | dashed | link | text | default default 事件 事件名称 说明 回调参数 版本 click 点击按钮时的回调 (event) => void 支持原生 button 的其他所有属性。

    2023年12月18日
    75200
  • 自定义mutation时出现校验不过时,如何排查

    场景描述 用户在自定义接口提供给前端调用时 @Action(displayName = "注册", bindingType = ViewTypeEnum.CUSTOM) public BaseResponse register(UserZhgl data) { //…逻辑 return result; } import java.io.Serializable; public class BaseResponse implements Serializable { private String code; private String msg; public BaseResponse() { } public BaseResponse(String code, String msg) { this.code = code; this.msg = msg; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } } gql执行时出现报错 { "errors":[ { "message":"Validation error of type SubSelectionNotAllowed: Sub selection not allowed on leaf type Object of field register @ 'zhglMutation/register'", "locations":[ { "line":3, "column":3 } ], "extensions":{ "classification":"ValidationError" } } ] } 解决方案 1.返回对象不为空时,对象必须是模型,否则无法解析返回参数2.前端调用GQL异常时,可以用Insomnia工具对GQL进行测试,根据错误提示对GQL进行修改和排查3.GQL正常情况下,执行以后可根据后端日志进行错误排查

    2023年11月1日
    1.7K00
  • 前端低无一体使用教程

    介绍 客户在使用oinone平台的时候,有一些个性化的前端展示或交互需求,oinone作为开发平台,不可能提前预置好一个跟客户需求一模一样的组件,这个时候我们提供了一个“低无一体”模块,可以反向生成API代码,生成对应的扩展工程和API依赖包,再由专业前端研发人员基于扩展工程(kunlun-sdk),利用API包进行开发并上传至平台,这样就可以在界面设计器的组件里切换为我们通过低无一体自定义的新组件。 低无一体的具体体现 “低”— 指低代码,在sdk扩展工程内编写的组件代码 “无”— 指无代码,在页面设计器的组件功能处新建的组件定义 低无一体的组件跟直接在自有工程内写组件的区别? 低无一体的组件复用性更高,可以在本工程其他页面和其他业务工程中再次使用。 组件、元件介绍 元件 — 指定视图类型(viewType) + 指定业务类型(ttype)字段的个性化交互展示。组件 — 同一类个性化交互展示的元件的集合。组件是一个大一点的概念,比如常用的 Input 组件,他的元件在表单视图有字符串输入元件、密码输入元件,在详情和表格展示的时候就是只读的,页面最终使用的其实是元件。通过组件+ttype+视图类型+是否多值+组件名可以找到符合条件的元件,组件下有多个元件会根据最优匹配规则找到最合适的具体元件。 如何使用低无一体 界面设计器组件管理页面添加组件 进入组件的元件管理页面 点击“添加元件” 设计元件的属性 这里以是否“显示清除按钮”作为自定义属性从左侧拖入到中间设计区域,然后发布 点击“返回组件” 鼠标悬浮到卡片的更多按钮的图标,弹出下拉弹出“低无一体”的按钮 在弹窗内点击“生成SDK”的按钮 生成完成后,点击“下载模板工程” 解压模板工程kunlun-sdk.zip 解压后先查看README.MD,了解一下工程运行要点,可以先运行 npm i 安装依赖 再看kunlun-plugin目录下已经有生成好的组件对应的ts和vue文件 下面在vue文件内增加自定义代码,可以运行 npm run dev 在开发模式下调试看效果 <template> <div class="my-form-string-input"> <oio-input :value="realValue" @update:value="change" > <template #prepend>MyPrepend</template> </oio-input> </div> </template> <script lang="ts"> import { defineComponent, ref } from 'vue'; import { OioInput } from '@kunlun/vue-ui-antd'; export default defineComponent({ name: 'customField1', components: { OioInput }, props: { value: { type: String }, change: { type: Function }, }, setup(props) { const realValue = ref<string | null | undefined>(props.value); return { realValue }; } }); </script> <style lang="scss"> .my-form-string-input { border: 1px solid red; } </style> 确定改好代码后运行 npm run build,生成上传所需的js和css文件 可以看到 kunlun-plugin目录下多出了dist目录,我们需要的是 kunlun-plugin.umd.js 和 kunlun-plugin.css 这2个文件 再次回到组件的“低无一体”管理弹窗页面,上传上面生成的js和css文件,并点击“确定”保存,到这里我们的组件就新增完成了。 下面我们再到页面设计器的页面中使用上面设计的组件(这里的表单页面是提前准备好的,这里就不介绍如何新建表单页面了) 将左侧组件库拉直最底部,可以看到刚刚新建的组件,将其拖至中间设计区域,我们可以看到自定义组件的展示结果跟刚刚的代码是对应上的(ps: 如果样式未生效,请刷新页面查看,因为刚刚上传的js和css文件在页面初始加载的时候才会导入进来,刚刚上传的动作未导入新上传的代码文件),再次点击设计区域中的自定义组件,可以看到右侧属性设置面板也出现了元件设计时拖入的属性。 最后再去运行时的页面查看效果,与代码逻辑一致! 注意事项 为什么我上传了组件后页面未生效? 检查前端启动工程的低无一体是否配置正确

    2023年11月6日
    3.4K00
  • 前端自定义组件之多页面步骤条

    本文将讲解如何通过自定义,实现多页面的步骤条组件。其中每个步骤的元素里都对应界面设计器的一个页面。以下是代码实现和原理分析。 代码实现 NextStepWidget 多页面步骤条 ts 组件 import { CallChaining, createRuntimeContextByView, customMutation, customQuery, RuntimeView, SPI, ViewCache, Widget, DefaultTabsWidget, BasePackWidget } from '@oinone/kunlun-dependencies'; import { isEmpty } from 'lodash-es'; import { MyMetadataViewWidget } from './MyMetadataViewWidget'; import NextStep from './NextStep.vue'; import { IStepConfig, StepDirection } from './type'; @SPI.ClassFactory(BasePackWidget.Token({ widget: 'NextStep' })) export class NextStepWidget extends DefaultTabsWidget { public initialize(props) { this.titles = props.template?.widgets?.map((item) => item.title) || []; props.template && (props.template.widgets = []); super.initialize(props); this.setComponent(NextStep); return this; } @Widget.Reactive() public get invisible() { return false; } // 配置的每一步名称 @Widget.Reactive() public titles = []; // region 上一步下一步配置 // 步骤配置,切换的顺序就是数组的顺序,模型没有限制 @Widget.Reactive() public get stepJsonConfig() { let data = JSON.parse( this.getDsl().stepJsonConfig || '[{"model":"resource.ResourceCountry","viewName":"国家form"},{"model":"resource.ResourceProvince","viewName":"省form"},{"model":"resource.ResourceCity","viewName":"市form"}]' ); return data as IStepConfig[]; } // 切换上一步下一步 @Widget.Method() public async onStepChange(stepDirection: StepDirection) { // 没有激活的,说明是初始化,取第一步 if (!this.activeStepKey) { const step = this.stepJsonConfig[0]; if (step) { this.activeStepKey = `${step.model}_${step.viewName}`; await this.initStepView(step); } return; } // 获取当前步骤的索引 if (this.currentActiveKeyIndex > -1) { await this.onSave(); // 获取下一步索引 const nextStepIndex = stepDirection === StepDirection.NEXT ? this.currentActiveKeyIndex + 1 : this.currentActiveKeyIndex – 1; // 在索引范围内,则渲染视图 if (nextStepIndex >= 0 && nextStepIndex < this.stepJsonConfig.length) { const nextStep = this.stepJsonConfig[nextStepIndex];…

    2025年7月21日
    78600

Leave a Reply

登录后才能评论