作者:中子星000
这个教程里,我们将使用自定义控件实现一个BASE64编解码器
(文末附源码,已投稿至控件商城)
控件类型定义
基本信息
首先我们创建一个常量叫 BASE64_ZZX_WIDGET,用于定义控件类型,以及一些会用到的常量(如图标、颜色等)。
这里使用自定义图标(上传方式见上传控件图标方式)和自定义颜色。(使用#RGBA可以让积木透明)
const BLOCK_COLOR = '#00B6B6AA';const WIDGET_ICON = 'https://creation.codemao.cn/716/appcraft/IMAGE_KvkhthrhIl_1643078284866';const BLOCK_ICON = 'https://creation.codemao.cn/716/appcraft/IMAGE_e2CmsKVPl_1643078450099';const AUTHER = '中子星000';const HOMEPAGE = 'https://shequ.codemao.cn/user/2867423';const QQ = 2422481178;const BASE64_ZZX_WIDGET = {};
接下来我们需要定义控件的基本信息。
type代表控件的类型,按照传统一般为全大写并以 _WIDGET结尾)。
icon代表控件的图标。
title代表控件的名称,会在拖拽图标的下方以及创建控件实例时作为控件的默认名称显示。
version代表控件版本,这里就设置成1.0(相信我不会再更新了)。
isInvisibleWidget代表控件是否不可见控件。
isGlobalWidget代表控件是否为全局控件。
docs代表控件文档,docs.url是文档连接。
const BASE64_ZZX_WIDGET = {type: 'BASE64_ZZX_WIDGET',icon: WIDGET_ICON,title: 'BASE64',version: '1.0',platforms: ['android', 'ios', 'web'],isInvisibleWidget: true,isGlobalWidget: true,docs: {url: 'https://www.yuque.com/appcraft/widget/base64'},};
控件属性
接下来我们需要定义控件的属性。首先添加字段 properties。我们通过一个对象定义属性,具体每个字段的含义请参考 开发指南。这里用不到本内容,请参考其他教程或开发指南。
const BASE64_ZZX_WIDGET = {type: 'BASE64_ZZX_WIDGET',icon: WIDGET_ICON,title: 'BASE64',version: '1.0',platforms: ['android', 'ios', 'web'],isInvisibleWidget: true,isGlobalWidget: true,docs: {url: 'https://www.yuque.com/appcraft/widget/base64'},properties: [],};
控件方法
接下来我们需要定义控件的方法。首先添加字段 methods。和属性类似,我们通过一个对象定义方法的基本属性,具体每个字段的含义请参考 开发指南。这里我们定义了一个方法 BASE64,用于编码和解码两个功能。为了实现两个功能,可以使用dropdown设定下拉选项。
valueType可以决定是否有返回值,此处返回值类型为string。
blockOptions则是积木选项,blockOptions.icon是积木图标;blockOptions.color是积木颜色。
tooltip是鼠标悬停在积木上时的提示。
const BASE64_ZZX_WIDGET = {type: 'BASE64_ZZX_WIDGET',icon: WIDGET_ICON,title: 'BASE64',version: '1.0',platforms: ['android', 'ios', 'web'],isInvisibleWidget: true,isGlobalWidget: true,docs: {url: 'https://www.yuque.com/appcraft/widget/base64'},properties: [],methods: [{key: 'BASE64',label: 'BASE64编解码',valueType: 'string',params: [{key: 'mode',valueType: 'string',defaultValue: 'encode',dropdown: [{ label: '编码', value: 'encode' },{ label: '解码', value: 'decode' }]},{key: 'str',label: '文本',valueType: 'string',defaultValue: ''},],blockOptions: {icon: BLOCK_ICON,color: BLOCK_COLOR,},tooltip: `本扩展支持中文 编码模式:将字符串编码为BASE64;解码模式:将BASE64解码为字符串`,},],},
控件事件
接下来我们需要定义控件的事件。首先添加字段 events。和属性、方法类似,我们通过一个对象定义事件的基本属性,具体每个字段的含义请参考 开发指南。不过呢这里我们不需要定义它的事件,所以留空。
const BASE64_ZZX_WIDGET = {type: 'BASE64_ZZX_WIDGET',icon: WIDGET_ICON,title: 'BASE64',version: '1.0',platforms: ['android', 'ios', 'web'],isInvisibleWidget: true,isGlobalWidget: true,docs: {url: 'https://www.yuque.com/appcraft/widget/base64'},properties: [],methods: [/* ... */],events: [],},
有了这部分的定义,我们就能够生成编辑态下的控件定义,包括控件选择界面,属性面板和积木外观。



(注:点击“如何使用?”打开控件文档)
接下来我们需要定义BASE64编解码在运行时的行为表现,也就是调用了上面的积木后,控件会做出的响应。这里我们需要实现一个叫 BASE64的js类。
控件实体定义
控件实体是一个继承 isInvisibleWidget 或者 VisibleWidget 的类,其中包含初始化、方法定义、事件触发、渲染(仅可见控件)等。
在运行时,会根据控件的属性值初始化一个实例对象。
初始化
将控件的属性通过 props 传入,这里的 props 其实就是控件类型定义中的 properties 中的属性,但本教程中不需要使用属性。
class WIDGET extends InvisibleWidget {constructor(props) {super(props);}}
方法定义
在控件类型定义中,定义了一个方法BASE64,对应的我们需要在控件实体中定义同名的两个方法,方法的参数类型和数量也需要一致
由于JavaScript中自带的btoa()、atob()方法不支持中文,所以我们还应对输入的文本做一定处理。
class WIDGET extends InvisibleWidget {constructor(props) {super(props);}BASE64(mode, str) {if (mode === 'encode') {return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,function toSolidBytes(match, p1) {return String.fromCharCode('0x' + p1);}))}else {return decodeURIComponent(atob(str).split('').map(function (c) {return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);}).join(''))}}}
导出控件
最后我们需要将这些定义通过两个变量导出,types对应控件的基本定义,widget对应用于生成运行态实例的控件类。
exports.types = BASE64_ZZX_WIDGET;exports.widget = WIDGET;
将写好的内容保存到 BASE64.js中,通过CoCo编辑器导入(或通过控件商城【强烈建议】),我们就可以正常的使用自定义的BASE64控件啦!

源码下载
- BASE64控件 JS 源码:BASE64
- 可以在控件商城导入 BASE编解码控件(升级版,支持BASE64和BASE91)
- 在下方代码框复制源码
const BLOCK_COLOR = '#00B6B6AA';const WIDGET_ICON = 'https://creation.codemao.cn/716/appcraft/IMAGE_KvkhthrhIl_1643078284866';const BLOCK_ICON = 'https://creation.codemao.cn/716/appcraft/IMAGE_e2CmsKVPl_1643078450099';const AUTHER = '中子星000';const HOMEPAGE = 'https://shequ.codemao.cn/user/2867423';const QQ = 2422481178;const BASE64_ZZX_WIDGET = {type: 'BASE64_ZZX_WIDGET',icon: WIDGET_ICON,title: 'BASE64',version: '1.0',platforms: ['android', 'ios', 'web'],isInvisibleWidget: true,isGlobalWidget: true,docs: {url: 'https://www.yuque.com/appcraft/widget/base64'},properties: [],methods: [{key: 'BASE64',label: 'BASE64编解码',valueType: 'string',params: [{key: 'mode',valueType: 'string',defaultValue: 'encode',dropdown: [{ label: '编码', value: 'encode' },{ label: '解码', value: 'decode' }]},{key: 'str',label: '文本',valueType: 'string',defaultValue: ''},],blockOptions: {icon: BLOCK_ICON,color: BLOCK_COLOR,},tooltip: `本扩展支持中文 编码模式:将字符串编码为BASE64;解码模式:将BASE64解码为字符串`,},],events: []};class WIDGET extends InvisibleWidget {constructor(props) {super(props);}BASE64(mode, str) {if (mode === 'encode') {return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,function toSolidBytes(match, p1) {return String.fromCharCode('0x' + p1);}))}else {return decodeURIComponent(atob(str).split('').map(function (c) {return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);}).join(''))}}}exports.types = BASE64_ZZX_WIDGET;exports.widget = WIDGET;
