FinClip为企业提供小程序生态圈技术产品,开发者可在FinClip小程序开发帮助中心找到相关FinClip小程序指引

# 编写 JS 对象

在低代码中的 JavaScript 编辑器允许您创建一个可重用的 JavaScript 函数,你可以在组件内调用这些函数,从而实现对应的功能。在低代码项目中,处处皆可JS。

# 如何创建JS对象

JS 对象是由多个函数和变量组成的实体。它是一个可以在其他 JS 对象中引用的可重用组件,允许您创建一组有组织的层次结构。

您可以从左侧菜单栏的【查询/JS】中新增JS对象

# 如何调用JS对象

你可以在PagePlug任何的输入框中,来调用JS对象中定义的函数,例如:

1、可以修改js对象的名称

2、代码编辑选项,可以在里面编写JS代码

3、支持设置异步函数

4、可以定义变量

5、可以定义函数

6、这里可以支持多种内容,举几个例子:

  • 编写代码
  • 调用内置或用户定义的函数
  • API调用
  • 数据库执行查询

7、向JS对象添加多个函数

8、可以选择要执行的函数名称

9、点击执行

TIP

定义的 JS 对象可跨 API、查询或为特定页面定义的其他 JS 对象使用,并且具有页面级访问权限,不能跨页面访问。

# 调用JS函数

例如我们刚刚在上面创建了一个JSObject1对象,我们可以在任意组件中调用JSObject1对象中定义的函数,例如在按钮组件里面:

组件的属性框都支持编写JS

# 使用Synchronous或Asynchronous的JS对象编写函数

Synchronous

例如,下面的代码片段显示了一个数据过滤器:

Api.data.filter(() => {}); // filtering data

这里的数据过滤是选择您要选择用于查看或分析的数据子集的过程。要过滤数据,您必须一个接一个地遍历整个数据集,如果符合过滤条件,则将其隔离。因此,您需要同步执行

Asynchronous

例如使用Promises,Api.run(),Query.Run()(例如。showModal)。它基本上可以让您延迟执行嵌入在异步函数中的代码,并在需要时执行。

您可以为异步功能配置其他设置并增强用户体验。// 待做

# JS代码编辑器介绍

JavaScript 编辑器是一个功能广泛的编辑器,可在编写代码时提供额外的功能,你可以用它做很多事情。

1、返回结果选项

在开发时执行每个功能,都可以在返回结果选项中查看输出

2、编码错误检查

JavaScript 编辑器会自动检查您的源代码是否存在编程错误。如果代码在编程上不正确,它会在错误代码下方使用红色波浪线突出显示错误。例如,return被拼错为 ret 的语法错误也会被 linting 捕获。

3、错误选项

错误选项卡显示代码执行产生的所有类型的错误。这些错误可能包括语法错误、运行时错误(如解析错误)等。

4、日志选项

日志选项显示能看到执行的时间情况,你也可以通过单击控制台右下角的调试图标来打开“日志”选项(如下面的屏幕截图所示)。在日志选项中,使您可以通过在过滤器框中输入关键字或从下拉列表中选择日志类型来灵活地过滤日志。

示例

可以添加以下代码片段

export default {
   hello: () => {
      return “Hello World”;
   }
}

请注意

您可以点击右上角的运行可用来执行JS 函数。如果你的 JS 对象只定义了一个函数,编辑器会默认函数名。但如果您的 JS 对象定义了多个函数,您可以选择要执行的函数,然后单击运行。

# debugger和console功能

你可以使用debugger或console.log()调试您的代码并分别在浏览器控制台中检查它,这样可以检查代码的情况,并逐行检查它以帮助识别和修复任何错误

控制台对象仅支持log、error和warn方法。您还可以使用信息和调试方法。但是,这些方法提供与日志方法相同的功能。

# console.log()用法

你可以使用console.log()将有关代码的信息打印到浏览器的控制台,帮你查看代码执行的不同点检查变量值或应用程序的状态。

console.log(<VARIABLE_NAME>)

当你运行你的代码时,<VARIABLE_NAME> 的值将打印到浏览器的控制台,查看它是否符合您的预期

示例

  • 首先创建一个get_users的api
https://mock-api.appsmith.com/users
  • 创建一个js对象,打印接口数据

把下列代码输入到代码器中

export default {
    getUser: async () => {
			const res = await get_users.run();
			console.log(res);
    }
}

之后点击右上角运行,之后就看到打印的接口的返回数据

  • 延伸,我们再试下打印一个变量值
export default {
    getUser: async () => {
        const {users} = await get_users.run();
        console.log(users);
        users[0].id = 5;
        console.log(users[0]);	
    }
}

# debugger功能

我们可以在代码中要暂停的地方插入一个debugger,然后运行你的应用程序。当到达调试器语句时,代码的执行将暂停,它的工作方式类似于breakpoint. 然后,您可以使用调试器工具单步执行代码、检查变量并查看代码的执行情况。

# 编写 REST API

可新增 rest Api 来进行数据的请求

使用介绍

  1. 该请求的名称,可自行更改

  2. 请求方式,可选 Get、post、put、delete、patch

  3. 请求地址,需检查是否可用

  4. 请求头和参数,以key-value 的形式添加,请求体和设置请看下图

请求体可以以多种形式携带

设置

可以设置执行时机,是否页面加载完立即发送请求,以及 API 的超时时间

  1. 点击运行,可在这里看到返回结果

  2. 发送请求时携带的请求头可在这里看到

  3. 请求失败时,在这里可以看到错误信息

# 操作数组介绍

介绍常用的数组方法,下面提供一些简单的案例介绍

使用 Lodash

工具库中默认装载了 Lodash。Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库。下面给出一些使用 Lodash 库的方法操作数组的示例,若您想要了解更多操作,请参阅 Lodash 文档。// 待做

方法 介绍 示例
_.head(array) 返回数组的第一个元素
_.last(array) 返回数组最后一个元素
_.nth(array, n) 获取第 n 个元素,n 可以为负数(例如取第三个)
_.chunk(array, size) 将数组拆分成多个长度为 size 的小数组,小数组构成新数组
_.uniq(array) 去重数组
_.initial(array) 删除数组最后一个元素
_.pull(array, [values]) 移除数组 array中所有和[values] 相等的元素
_.tail(array) 删除数组第一个元素

常用的数组操作方法

方法 介绍
.length 返回数组的长度
.join 将数组中的元素组合成字符串,分隔符可以自定义(通常为空格)
.indexOf 返回数组中指定值第一次出现的索引
.map 返回一个新数组,其中包含对原始数组的每个元素运行指定函数的结果
.filter 返回一个新数组,其中包含原始数组中匹配指定条件的元素
.includes 如果数组包含传递给方法的值,则返回true或false
.reduce 通过为数组的每个值(从左到右)运行函数,将数组缩减为单个数值
.concat 合并 2 个或多个数组

# 异步 Javascript

本文档会给你解释如何编写异步 Javascript 代码。

JavaScript promises

JavaScript Promises有助于实现使用回调时难以管理的异步工作流。PagePlug为 JavaScript 提供原生支持,Promises让异步操作更容易,且PagePlug的框架函数,如showAlert()、showModal()、storeValue()和其他函数都返回一个Promises,使异步工作流的实现更容易和可读。

# Callbacks vs promises

要了解Callbacks和 promise 实现之间的区别,请考虑一个依次执行三个 API 查询并在所有 API 成功运行完成时显示一条消息的示例,例如:

// Using Callbacks
{{
    MockApi.run(() => {
        MockApi1.run(() => {
            MockApi2.run(() => {
                showAlert('done') 
                })
        })   
    }) 
}}

对同一个示例使用promise可以让实现更易于管理和可读。

{{
    MockApi.run()
        .then(() => MockApi1.run())
        .then(() => MockApi2.run())
        .then(() => showAlert('done'))
 }}

# Promise方法

JavaScript Promise有几个内置方法。

tips

传递函数给.then()or的时候.catch()一定要记得把它作为回调函数传递,如下图:

错误方法

{{
 (function() {
   MockApi.run().then(showAlert(`Success`))      
  })()
}}

正确方法

{{
  (function() {
     return MockApi.run().then(() => showAlert(`Success`))
   })()
}}

方法一:Promise.any()

Promise.any()将可迭代的Promise作为输入并返回单个Promise。当其中一个Promise首次履行时,它会返回一个Promise,该Promise解决了已履行Promise的价值。如果你只想完成一个action/Promise以进一步执行,你可以使用Promise.any()方法。

{{
      (function(){
          
        return Promise.any([
              MockApi.run({ name: 1 }), // if name:1 finished early
              MockApi.run({ name: 2 })
        ]).then((res) => {
          showAlert(`Winner: ${res.args.name}`) // Alert Message showns as "Winner: 1" 
        });
      })()
}}

在这个例子中:

  • 该函数调用多个 API 查询传递和参数到每个 API 调用。Promise.any()收到退回的Promise。

  • 当任何 API 调用首先完成并返回已履行的Promise时,将显示一条警报消息。该消息包含发送到 API 的参数,API 完成执行并在 API 调用中首先返回Promise。

方法二:Promise.race()

它等待第一个已确定的Promise、fulfilled或rejected,以获得结果。Promise.race()当您只需要一个action/promise来完成执行时,您可以使用。

{{
        (function(){
            return  Promise.race([
                    MockApi.run({ name: 1 }),
                    MockApi.run({ name: 2 })
            ]).then((res) => {
                showAlert(`Winner: ${res.args.name}`)
            });
        })()
}}

在示例中:

  • 该函数调用多个 API 查询传递和参数到每个 API 调用。

  • 返回的 Promise 传递给Promise.race()

  • 当任何 API 调用首先完成并返回已履行的Promise时,将显示一条警报消息。该消息包含发送到 API 的参数,该参数在 API 调用中首先完成并返回Promise。

方法三:Promise.all

它接受一组Promise(从技术上讲是任何可迭代的,但通常是一个数组)并返回一个新的Promise。Promise 的结果数组成为新 Promise 的结果。如果其中一个 promise 失败(拒绝状态),新的 Promise 会立即拒绝并返回相同的错误。您可以Promise.all()在希望所有操作成功完成执行时使用。

{{
    (function(){
        let employeeNames = ["Employee 1","Employee 2"];
        // Start a bunch of calls running in parallel and store returned promise
        const calls = employeeNames.map(employeeName => MockApi.run({ name: employeeName }));
        
        // Wait for all to finish (or any to reject).
        return Promise.all(calls)
                .then(() => showAlert('Promise.all - All successful'))
                .catch(() => showAlert('Promise.all - Something went wrong'))
                .finally(() => showAlert('Promise.all - finished'))
    })()
}}

在示例中:

  • 该函数使用作为参数传递的员工姓名运行 API。

  • 该calls数组存储每个 API 调用的返回Promise。

  • 根据中的成功或失败案例显示一条警告消息Promise.all()。

方法四:Promise.allSettled()

它等待所有 promise 解决,不管结果如何(resolved 或 rejected)。Promise.allSettled()当您希望所有操作首先完成时,您可以使用。

{{
  (function(){
    let employeeNames = ["Employee 1","Employee 2"];
    // Start a bunch of calls running in parallel and store returned promise
    const calls = employeeNames.map(employeeName => MockApi.run({ name: employeeName }));
    
    // Wait for all to resolve / reject.
    return Promise.allSettled(calls)
          .then(() => showAlert('Promise.allSettled - All successful'))
          .catch(() => showAlert('Promise.allSettled - Something went wrong'))
          .finally(() => showAlert('Promise.allSettled - finished'))
  })()
}}

在示例中:

  • 该函数使用作为参数传递的员工姓名运行 API。

  • 该calls数组存储每个 API 调用的返回Promise。

  • 根据中的成功或失败案例显示一条警告消息Promise.allSettled()。

# 通用指南

  • 项目中大多数操作触发器都会返回Promise,因此您可以在继续之前附加一个.then()或await等待操作。

  • 所有触发器都包含在Promise中,因此任何遗漏的错误都会导致未捕获的Promise错误。

  • 附有返回promise.then(),如下所示:

{{
  (function() {
        // the .then only runs if a promise is returned
        return MockApi.run()
            .then(() => showAlert('success'))
    })()
}}
  • 参数不再在.then()的参数中传递action.run()。只传递response,如下:

将下端代码放到 {{}} 中使用

(function() {
    const params = { name: "PagePlug" }
    return MockApi.run(params).then((response) => {
            showAlert(`${response.length} users found in `${params.name}`)
        })
})()

# async和await

async和await关键字可以让异步工作流能够以更干净的风格编写,从而避免了显式配置promise链的需要。

  • async

async在函数前添加关键字总是返回一个promise。其他值自动包装在已解决的promise中

  • await

该关键字await使 JavaScript 等待,直到 Promise 完成并返回其结果。

{{
    (async function(){ 
        const response = await MockApi.run({ name: 'PagePlug' }); 
        await storeValue( "name", response.args.name ); 
        await showAlert(global.store.name); 
    })() 
}}

在前面的示例中:

  • MockApi使用参数作为“PagePlug”运行查询name并等待响应。

  • storeValue()当您收到响应时,将响应存储在 global.store中。

  • 成功执行后storeValue(),显示一条警告消息,其中包含保存在global的数据。

# 异步 JavaScript 函数设置

异步函数允许您选择何时执行代码。例如,您可能希望延迟查询执行或按需获取数据。

如果您正在执行以下操作之一,则函数被称为异步:

  • 你有一个关键字 (async) 来标记函数的异步执行
export default{
    functionName: async() => {
       //use async-await or promises
    }
}
  • 您在功能块中添加了内置组件的功能,例如showModal(), showAlert()等。

  • 您想要在运行时执行查询或调用 API。例如,你有一个 API GetUsersList,,你想在运行时调用这个 API,也就是每当callAPI()执行 JS Object 函数时。您的功能可能如下所示:

export default {
   callAPI: () => {
      GetUsersList.run();
   }
 }

这行代码GetUsersList.run()标记了异步执行的函数callAPI(),因此callAPI函数被认为是异步的。

低代码项目 中的 JavaScript 编辑器为异步函数提供了一些附加设置,可帮助您添加更多配置。

# 如何在低代码项目中定义异步函数

  • 你可以在代码选项旁边的设置选项,进行异步函数的设置

  • 页面加载后执行:你可以设置这个函数是否在加载页面时候执行。例如,您有一个页面并添加了一个 JS 对象,该对象具有获取用户角色的功能。你希望在页面加载时执行查询,以便登录用户能够看到用户列表。要使其正常工作。

# global 对象

global对象提供有关应用程序当前状态的信息

global对象包含以下属性:

{
   echartInstance: Object,
   store: object,
   URL: object,
   user: object,
   geolocation: object,
   mode: string,
   inCloudOS: Boolean,
   theme: Object
}

# store

该对象包含应用程序本地存储的键值对。可以使用storeValue()更新存储的值。可以使用它们的键访问存储中的值。

// 存
storeValue("test", 123)
// 取
{{ global.store.text}}

# URL

该对象包含与用户所在的当前 URL 关联的所有值。该字段的 queryParams 对象可用于读取使用**navigateTo()**从其他页面发送到该页面的数据。可以使用以下方法访问 URL 中的值:

{{ global.URL }}

{
  host: string,
  hostName: string,
  fullPath: string,
  pathName: string,
  port: string,
  protocol: string,
  hash: string,
  queryParams: object
}
  • host

URL 对象的host属性是一个字符串,其中包括主机名,然后是 ,:后跟 URL 的端口(如果端口可用)。

//{{global.URL.host}}
"app.appsmith.com:111"
  • hostname

URL 的hostname属性是一个包含URL 域的字符串。简单来说,hostname 就是主机名(不含端口号)。

//{{global.URL.hostname}}
"app.appsmith.com"
  • fullPath

完整路径 URL 指定一个确切的位置(例如页面、应用程序、文件等)。除了域和顶级域 (TLD) 之外,完整路径 URL 还需要包括协议、子域(例如“app”、“support”等)、路径/目标以及可能的文件扩展名以及查询参数。完整路径可以包括:

  • 协议

  • 子域名

  • 域名

  • 顶级域 (TLD)

  • 路径

  • 参数

//{{global.URL.fullPath}}
"https://app.appsmith.com/app/demo-app/page1-6324031aa"

提示

在前面的示例中,6324031aa表示名为 的页面的IDpage1。URL 中的当前页面 slug 是通过组合创建的$pageName-$pageId。每个页面都有一个分配给它的唯一页面 ID。

  • pathname

它是由一组路径段组成的字符串,每个路径段都有/前缀字符。如果 URL 没有路径段,则空字符串将是路径名属性的值

//{{global.URL.pathname}}
"/app/demo-app/page1-6324031aa"
  • port

URL 的port属性是一个字符串,其中包含 URL 的端口号。

//{{global.URL.port}}
"3000"
  • protocol

URL 的protocol属性是一个字符串,表示 URL 的协议方案,包括:

资源名称和协议标识由一个冒号和两个正斜杠彼此分隔

//{{global.URL.protocol}}
"https:"
  • hash

该值是主题标签(包括global.URL.hash)之后的字符串。URL 片段标识后跟一个哈希符号(#),这是 URL 接口的哈希属性。

//{{global.URL.hash}}
"#n912xhego"
  • queryParams

查询参数是一组预定义的参数,这些参数根据传递的数据定义特定的内容或操作。URL 的所有查询参数都附加在末尾,并以 a?作为分隔符。

//{{global.URL.queryParams}}
"?name=value&variable=value"

# user

该对象包含当前经过身份验证的用户的数据。

{
  email: string
  username: string
  name: string
  role: string
  useCase: string
  accountNonExpired: boolean
  accountNonLocked: boolean
  credentialsNonExpired: boolean
  adminSettingsVisible: boolean
  cloudOSLogged: boolean  
}

# geolocation

该对象包含请求当前用户位置和从此请求接收的坐标的函数

{
 canBeRequested: boolean,
 getCurrentPosition: Function,
 watchPosition: Function,
 clearWatch: Function,
 currentPosition: {
   coords: {
      accuracy: number,
      altitude: number | null,
      altitudeAccuracy: number | null,
      heading: number | null,
      latitude: number,
      longitude: number,
      speed: number | mull,
   },
   timestamp: number,
 }
}

获取当前位置

(
 onSuccessCallback?,
 onErrorCallback?,
 options?: { maximumAge?: number, timeout?: number, enableHighAccuracy?: boolean } 
) -> void

与原始浏览器 API 几乎相似,除了不需要传递成功回调之外。成功后,该位置将自动存储在global.geolocation.currentPosition.coords。如果传递了 onSuccessCallback,则会使用收到的位置信息调用它。

  • watchPosition
(
  onSuccessCallback?,
  onErrorCallback?,
  options?: { maximumAge?: number, timeout?: number, enableHighAccuracy?: boolean } 
) -> void

与原始浏览器 API 几乎相似,除了不需要传递成功回调之外。成功后,该位置将自动存储在上次更新位置时的更新位置global.geolocation.currentPosition.coords。

global.geolocation.currentPosition.timestamp回调(如果提供)会在位置更改时自动执行。没有 watchId 被返回以及平台只允许一个watchPosition

  • clearWatch

() -> Promise

与原始浏览器 API 几乎相似,除了您不必传递 watchId。如果watch处于活动状态,则必须在开始新watch之前将其清除。

# Query 对象

介绍如何使用 Query 对象运行查询并访问响应中的数据。

# run()

调用查询的 run() 函数执行该查询。 run() 是异步的并返回一个 promise,所以你可以使用 .then() 链式调用 和 async/await 这样的异步语法。

run(params: Object): Promise
使用 {{ this.params.key }} 访问
方法 介绍
params 包含要传递到查询中的键值对的对象。
// 使用promise语法按顺序链式调用
{{
    Query1.run(params)
        .then(() => {...}) // 成功后执行的回调函数
        .catch(() => {...}) // 遇到错误后执行的回调函数
}}

# JS 库

支持自定义 Javascript 库!!!能为 PDF 生成、CSV 解析、分析、身份验证、错误记录等复杂用例提供了更高级的功能,还能支持您通过自定义库来操作或转换数据,这些外部库提供了额外的方法来帮助您构建复杂的应用程序和业务逻辑。

# 库的兼容性

目前仅与支持 UMD 构建的库兼容。如果库支持 UMD 构建格式,则库索引文件的源代码应符合此 基本模式。root大多数兼容库的索引文件可以在, /umd 或 文件夹下找到 /browser ,并具有.min.js文件扩展名。如果您希望使用的库不支持 UMD 构建,您可以使用 browserify 生成一个并将其托管在您选择的 CDN 中。

  • 有效网址:

https://cdn.jsdelivr.net/npm/exceljs@4.3.0/dist/exceljs.min.js

  • 有效网址,但不支持的构建格式:

https://cdn.jsdelivr.net/npm/uuid@9.0.0/dist/index.js

  • 网址无效。不指向索引文件:

https://www.jsdelivr.com/package/npm/datejs

# 安装外部JS库

在安装JS库的时候,菜单栏会有一些推荐的库可供选择,您只需单击安装图标即可进行安装。但是,如果您想使用 URL 安装特定的库,过程也很简单。要安装其他库:

  • jsDelivr (opens new window) 或 UNPKG等流行的 CDN 服务上 查找兼容的库。

  • 将 URL 复制到其索引文件并将其粘贴到 PagePlug 上以开始安装。

  • 导航到资源管理器选项卡

  • 单击+旁边的标志Libraries。

  • 将 URL 粘贴到指定字段中。例如

  • 之后点击安装,安装成功就可以在项目中使用啦

# 案例演示

可以像在应用内通过的方式使用 JavaScript 一样在内部使用外部库,提供一些示例:

export default {
  myVar1: [],
  myVar2: {},
  myFun1 () {
		//	write code here
		//	this.myVar1 = [1,2,3]
	},
  createWorkbook: async () => {
    const workbook = new ExcelJS.Workbook();
    console.log(workbook, "66666")
    workbook.creator = "Tomato";
    workbook.lastModifiedBy = "Tomato";
    workbook.created = new Date();
    workbook.modified = new Date();
    workbook.calcProperties.fullCalcOnLoad = true;
  
    const worksheet = workbook.addWorksheet("Tomato page 1", {
      properties: { tabColor: { argb: "#FF0000" } },
      pageSetup: { paperSize: 9, orientation: "landscape" },
    });
  
    worksheet.getCell("A1").value = "Hello, World!";
    worksheet.getCell("B1").value = "What time is it?";javaja
    worksheet.getCell("A2").value = 7;
    worksheet.getCell("B2").value = "12pm";
  
    const buf = await workbook.xlsx.writeBuffer();
    const blob = new Blob([buf], {
      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    });
    const url = URL.createObjectURL(blob);
  
    await download(url, "test.xls");
  }
}

# 注意事项

由于平台限制,您可能无法安装或使用某些库的方法:

  • DOM访问:试图操纵文档对象的库将无法工作。示例: https: //d3js.org/

  • XHR:仅依赖 XHR 的库将无法工作。

  • 其他 API:在后台使用以下 API 的库方法将不起作用:setInterval、clearInterval、setImmediate、localStorage和Navigator。

  • DOM访问:试图操纵文档对象的库将无法工作。示例: https: //d3js.org/ XHR:仅依赖 XHR 的库将无法工作。 其他 API:在后台使用以下 API 的库方法将不起作用:setInterval、clearInterval、setImmediate、localStorage和Navigator。

如果您在连接外部库时遇到困难,可以参考JavaScript 错误故障排除指南

© 2022 FinClip with ❤