【前端】项目开发前端知识要点地图

概述

下面整理了目前现有的所有文章,并提供了基本的学习路径。所有使用*标记的文章属于推荐必读文章。

目录

基础篇

入门篇

进阶篇

最佳实践篇

界面设计器实战篇

其他

API文档

Oinone社区 作者:数式-海波原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/51.html

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

Like (0)
数式-海波's avatar数式-海波数式管理员
Previous 2024年5月24日 pm9:11
Next 2024年5月25日 pm4:19

相关推荐

  • 表格页自定义按钮如何获取搜索区域的查询条件

    介绍 在使用 Oinone 平台开发过程中,开发者可能会遇到自定义动作需要获取搜索条件并传递给后端的情况。本文将介绍如何利用 Oinone平台 实现此功能。 技术基础知识 当我们在自定义一个动作的时候要先明确自定义的动作类型是什么样的,在Oinone平台中,分为了如下几个动作: 1: 视图动作2: 服务端动作3: 客户端动作3: URL动作 功能步骤或代码示例 案例1、服务端动作,动作点击时候要拿到搜索内容,然后传递给后端。 import { ActionType, ActionWidget, SPI, ServerActionWidget } from '@kunlun/dependencies'; @SPI.ClassFactory( ActionWidget.Token({ name: 'name', model: 'model', actionType: ActionType.Server }) ) export class MyServerActionWidget extends ServerActionWidget { protected async clickAction() { const rst = this.getSearchRsqlAndQueryParams(); } } 案例2、视图动作点击的时候把搜索内容带到另外一个视图或者弹窗 import { ActionType, ActionWidget, SPI, ServerActionWidget } from '@kunlun/dependencies'; @SPI.ClassFactory( ActionWidget.Token({ name: 'name', model: 'model' }) ) export class MyDialogViewActionWidget extends DialogViewActionWidget { // 继承当前动作原本的class protected async clickAction() { const { queryData } = this.getSearchRsqlAndQueryParams(); this.action.context = queryData super.clickAction() return true } } 在上述代码中,我们自定义了一个服务器动作,并在点击触发函数中调用了getSearchRsqlAndQueryParams方法,该方法会返回一个对象: { rsql: String, // 搜索内容对应的rsql queryData: Object, // 搜索的数据 condition: Condition, // 搜索内容对应的数据结构 queryDataToString: Function // 将搜索内容转成JSON字符串 } 这样我们就可以根据业务场景使用对应的值。 注意事项 1: 确保正确导入所需的依赖包。2: 理解并适当修改代码以满足特定业务需求。 总结 本文介绍了在 Oinone 平台中如何自定义一个服务端动作,并获取搜索条件传递给后端的方法。通过合理利用这些功能,开发者可以更灵活地定制应用程序,满足不同的业务需求。 实践案例 如何自定义点击导出动作绑定指定模板

    2024年3月6日
    1.8K00
  • 前端页面嵌套

    我们可能会遇到这些需求,如:页面中的一对多字段不是下拉框,而是另一个模型的表单组;页面中的步骤条表单,每一步的表单都需要界面设计器设计,同时这些表单可能属于不同模型。这时候我们就可以采取页面嵌套的方式,在当前页面中,动态创建一个界面设计器设计的子页面。以一对多字段,动态创建表单子页面举例,以下是代码实现和原理分析。 代码实现 AddSubformWidget 动态添加表单 ts 组件 import { ModelFieldType, ViewType, SPI, BaseFieldWidget, Widget, FormO2MFieldWidget, ActiveRecord, CallChaining, createRuntimeContextByView, queryViewDslByModelAndName, uniqueKeyGenerator } from '@oinone/kunlun-dependencies'; import { MyMetadataViewWidget } from './MyMetadataViewWidget'; import { watch } from 'vue'; import AddSubform from './AddSubform.vue'; @SPI.ClassFactory( BaseFieldWidget.Token({ viewType: ViewType.Form, ttype: ModelFieldType.OneToMany, widget: 'AddSubform' }) ) export class AddSubformWidget extends FormO2MFieldWidget { public initialize(props) { super.initialize(props); this.setComponent(AddSubform); return this; } @Widget.Reactive() public myMetadataViewWidget: MyMetadataViewWidget[] = []; @Widget.Reactive() public myMetadataViewWidgetKeys: string[] = []; @Widget.Reactive() public myMetadataViewWidgetLength = 0; // region 子视图配置 public get subviewModel() { return this.getDsl().subviewModel || 'clm.contractcenter.ContractSignatory'; } public get subviewName() { return this.getDsl().subviewName || '签署方_FORM_uiViewa9c114903e104800b15e8f3749656b64'; } // region 添加子视图块 // 按钮添加点击事件 @Widget.Method() public async onAddSubviewBlock() { const resView = await queryViewDslByModelAndName(this.subviewModel, this.subviewName); this.createDynamicSubviewWidget(resView); } // 创建子视图块 public async createDynamicSubviewWidget(view, activeRecord: ActiveRecord = {}) { if (view) { // 根据视图构建上下文 const runtimeContext = createRuntimeContextByView( { type: ViewType.Form, model: view.model, modelName: view.modelDefinition.name, module: view.modelDefinition.module, moduleName: view.modelDefinition.moduleName, name: view.name, dsl: view.template }, true, uniqueKeyGenerator(), this.currentHandle ); // 取得上下文唯一标识 const runtimeContextHandle = runtimeContext.handle; const slotKey = `Form_${uniqueKeyGenerator()}`; // 创建子视图组件 const widget = this.createWidget(new MyMetadataViewWidget(runtimeContextHandle), slotKey, // 插槽名 { metadataHandle: runtimeContextHandle,…

    2025年7月21日
    1.4K00
  • OioProvider详解

    OioProvider OioProvider是平台的初始化入口。 示例入口 main.ts import { VueOioProvider } from '@kunlun/dependencies'; VueOioProvider(); 网络请求/响应配置 http 平台统一使用apollo作为统一的http请求发起服务,并使用GraphQL协议作为前后端协议。 参考文档: apollo-client graphql 配置方式 VueOioProvider({ http?: OioHttpConfig }); OioHttpConfig /** * OioHttp配置 */ export interface OioHttpConfig { /** * base url */ url: string; /** * 拦截器配置 */ interceptor?: Partial<InterceptorOptions>; /** * 中间件配置(优先于拦截器) */ middleware?: NetworkMiddlewareHandler | NetworkMiddlewareHandler[]; } 内置拦截器可选项 InterceptorOptions /** * 拦截器可选项 */ export interface InterceptorOptions { /** * 网络错误拦截器 */ networkError: NetworkInterceptor; /** * 请求成功拦截器 (success) */ requestSuccess: NetworkInterceptor; /** * 重定向拦截器 (success) */ actionRedirect: NetworkInterceptor; /** * 登录重定向拦截器 (error) */ loginRedirect: NetworkInterceptor; /** * 请求错误拦截器 (error) */ requestError: NetworkInterceptor; /** * MessageHub拦截器 (success/error) */ messageHub: NetworkInterceptor; /** * 前置拦截器 */ beforeInterceptors: NetworkInterceptor | NetworkInterceptor[]; /** * 后置拦截器 */ afterInterceptors: NetworkInterceptor | NetworkInterceptor[]; } 内置拦截器执行顺序: beforeInterceptors:前置拦截器 networkError:网络错误 actionRedirect:重定向 requestSuccess 请求成功 loginRedirect:登录重定向 requestError:请求错误 messageHub:MessageHub afterInterceptors:后置拦截器 NetworkInterceptor /** * <h3>网络请求拦截器</h3> * <ul> * <li>拦截器将按照注册顺序依次执行</li> * <li>当任何一个拦截器返回false时,将中断拦截器执行</li> * <li>内置拦截器总是优先于自定义拦截器执行</li> * </ul> * */ export interface NetworkInterceptor { /** * 成功拦截 * @param response 响应结果 */ success?(response: IResponseResult): ReturnPromise<boolean>; /** * 错误拦截 * @param response 响应结果 */ error?(response: IResponseErrorResult): ReturnPromise<boolean>; } 自定义路由配置 router 配置方式 VueOioProvider({ router?: RouterPath[]…

    2023年11月6日
    2.4K00
  • action 和 function 有什么区别

    在 Oinone(开源低代码 / 企业应用开发平台) 里,Action 和 Function 都是“可被调用的逻辑单元”,但它们的定位和使用场景不同。可以简单理解为: Function = 纯逻辑函数(偏后端能力) Action = 面向业务操作的动作(偏应用行为 / UI触发) 下面给你详细对比一下。 1️⃣ Function:函数(逻辑能力) Function 更像是一个 可复用的服务方法。 特点 通常是 纯逻辑处理 不直接绑定 UI 可以被 Action / Service / 其他 Function 调用 用来封装 业务计算或工具逻辑 常见用途 比如: 价格计算 数据校验 数据转换 调用第三方 API 复杂业务规则 示例 @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type = FunctionTypeEnum.QUERY) public TradeOrder computePrice(TradeOrder data) { return data; } 用途: 订单金额计算逻辑 然后可能被多个地方调用: Action -> 调用 Function Service -> 调用 Function Workflow -> 调用 Function 📌 核心:可复用业务逻辑 2️⃣ Action:动作(业务操作) Action 是一个 业务动作,通常是 用户触发的行为。 特点 通常绑定 UI 可以在 按钮 / 菜单 / API / 工作流 中触发 通常操作 模型数据 可以调用 Function 常见用途 例如: 创建订单 提交审批 发布文章 批量删除 导入数据 示例 @Action public void submitOrder(Order order){ order.setStatus("SUBMITTED"); } UI 可能是: 订单详情页 [提交订单] 按钮 点击按钮 → 调用 Action。 📌 核心:业务行为入口 3️⃣ 核心区别总结 维度 Action Function 定位 业务动作 逻辑函数 是否绑定 UI 通常是 否 是否直接给用户操作 是 否 是否可复用 一般 很高 是否操作模型 常见 不一定 调用关系 可调用 Function 不调用 Action 4️⃣ 调用关系(典型架构) 通常推荐的结构: UI按钮 ↓ Action(业务入口) ↓ Function(业务逻辑) ↓ DAO / Repository 例如: 提交订单按钮 ↓ submitOrderAction ↓ checkInventoryFunction calcPriceFunction createOrderFunction 这样: Action 只负责 流程 Function 负责 逻辑 代码会更清晰。 5️⃣…

    2026年3月12日
    1.0K00
  • 自定义组件之手动渲染弹出层(v4)

    阅读之前 你应该: 了解自定义组件相关内容。 自定义组件之手动渲染基础(v4) 弹出层组件 我们内置了两个弹出层组件,弹窗(Dialog)和抽屉(Drawer),以下所有内容全部围绕弹窗(Dialog)进行描述,抽屉相关内容与弹窗完全一致。 下面这个对照表格可以帮助你区分两个弹出层组件的异同: 弹出层相关功能 弹窗(Dialog) 抽屉(Drawer) API方法 Dialog#create Drawer#create 内置组件 DialogWidget DrawerWidget 内置插槽 header, default, footer header, default, footer 渲染弹出层的方式 我们提供了三种渲染弹出层组件的方式,根据不同的情况使用不同的方式可以让实现变得更简单。 使用Dialog#createAPI方法创建弹窗:一般用于简单场景,动作区无法进行自定义。 使用DSL渲染能力创建弹窗 调用ActionWidget#click方法打开弹窗(适用于自动渲染场景) 使用createWidget创建DialogWidget并打开弹窗(适用于手动渲染场景) 使用第三方组件创建弹窗:一般用于弹窗需要自定义的场景中,性能最优,可用于任何场景。 使用Dialog#createAPI方法创建弹窗 以下是一个自定义组件的完整示例,其使用ViewCache#compule方法获取视图。 view.ts export const template = `<view> <field data="id" invisible="true" /> <field data="code" label="编码" /> <field data="name" label="名称" /> </view>`; ManualDemoWidget.ts import { BaseElementWidget, createRuntimeContextForWidget, Dialog, FormWidget, MessageHub, RuntimeView, SPI, ViewCache, ViewType, Widget } from '@kunlun/dependencies'; import ManualDemo from './ManualDemo.vue'; import { template } from './view'; @SPI.ClassFactory(BaseElementWidget.Token({ widget: 'ManualDemo' })) export class ManualDemoWidget extends BaseElementWidget { public initialize(props) { super.initialize(props); this.setComponent(ManualDemo); return this; } @Widget.Method() public async openPopup() { // 获取运行时视图 const view = await this.fetchViewByCompile(); if (!view) { console.error('Invalid view'); return; } // 创建运行时上下文 const runtimeContext = createRuntimeContextForWidget(view); const runtimeContextHandle = runtimeContext.handle; // 获取初始化数据 const formData = await runtimeContext.getInitialValue(); // 创建弹窗 const dialogWidget = Dialog.create(); // 设置弹窗属性 dialogWidget.setTitle('这是一个演示弹窗'); // 创建所需组件 dialogWidget.createWidget(FormWidget, undefined, { metadataHandle: runtimeContextHandle, rootHandle: runtimeContextHandle, dataSource: formData, activeRecords: formData, template: runtimeContext.viewTemplate, inline: true }); dialogWidget.on('ok', () => { MessageHub.info('click ok'); // 关闭弹窗 dialogWidget.onVisibleChange(false); }); dialogWidget.on('cancel', () => { MessageHub.info('click cancel'); // 关闭弹窗 dialogWidget.onVisibleChange(false); }); // 打开弹窗…

    前端 2023年11月1日
    1.6K00

Leave a Reply

Please Login to Comment