iframe 组件
1 说明
iframe 组件主要要用于嵌入第三方定制化页面,定制页面通过接入 gg-sdk,调用组件配置的资源。比如,想在页面上展示一张网络图片,可以在数据源中粘贴图片的链接。是这么使用的吗?
2 配置
2.1 数据源
数据源 URL 支持配置域名 URL 或者配置表达式(通过变量拼接 URL)
支持相对 URL 和外部绝对 URL
预览开关可以控制 iframe 编辑态是否打开配置的网页
相对 URL 配置,如下图
绝对 URL 配置,如下图
关闭预览,如下图
2.2 配置参数
这些参数的意思是什么?我添加了这么多参数是在哪里用?添加参数里的资源、页面、禁用分别是什么作用(比如我选择了数据库中的一个实体,这个组件会呈现什么内容?)
参数配置标签栏可以
- 操作参数标签菜单
鼠标悬浮或在标签尾部的“...”,会出现参数配置的菜单列表
- 添加新的参数标签页
点击 添加参数 按钮,弹窗中输入标签名,可选择是否禁用,点击保存即可创建新的标签页
- 修改现有参数页
点击 修改 按钮,可在弹窗中修改参数信息
点击 保存 按钮,即可完成修改
- 删除现有参数页
点击 删除 按钮,即可删除参数
- 禁用现有参数页
点击 禁用 按钮,即可禁用参数
2.3 样式
补充
2.4 可见性设置
具体描述请点击详情 查看通用的描述(详情)
2.5 设计
具体描述请点击详情 查看通用的描述(详情)
2.6 SDK 对接相关
2.6.1 gg-sdk
第三方定制页接入需要使用 gg-sdk,具体文件可在模板项目中获取(https://gitlab.xuelangyun.com/cli-template/frame-project-template)
2.6.2 使用方式
在定制项目中,需要使用注册函数 registerIframeLintenerInner 注册监听,返回值中 callCommand 为调用指令的函数,removeListener 为移除监听的函数
在 vue 项目中建议将监听的注册卸载放在 vue 的页面挂载卸载回调中,防止重复切换页面导致重复监听
let callCmd;
onMounted(() => {
const { callCommand, removeListener } = registerIframeLintenerInner();
onUnmounted(removeListener);
callCmd = callCommand;
});
const clickItem = ({ cmd, params, title }) => {
if (!callCmd) {
return;
}
console.log(`触发外部gg ${title} 指令 ${cmd}`);
callCmd(cmd, params, (data) => {
console.log(`外部gg返回 ${title} 指令 ${cmd} 结果`, data);
// alert(JSON.stringify(data));
});
};
注册监听返回的 callCommand 函数有三个入参
第一个入参为指令名称,目前支持如下指令
// 指令名称
export const COMMAND_NAME = {
OPEN_PAGE: 'OPEN_PAGE', // 打开页面
CLOSE_PAGE: 'CLOSE_PAGE', // 关闭页面
RESET_FORM: 'RESET_FORM', // 重置表单
COMMON_ACTION: 'COMMON_ACTION', // commonAction
CALL_MICROFLOW: 'CALL_MICROFLOW', // 微流调用
CONTEXT_DATA: 'CONTEXT_DATA', // 上下文数据
REFRESH_PAGE: 'REFRESH_PAGE', // 刷新页面
GET_PAGEPKID: 'GET_PAGEPKID' , // 获取页面主键id
};
第二个入参为指令所需的参数,其中必须包含 resourceName 字段,即配置参数中配置的参数名称
第三个入参为调用指令的结果回调
其实 postMessage 方法本身只是 Windows API 提供的实现跨源通信的 api,本身是无法关联结果返回的,gg-sdk 通过约定消息结构,在消息体中加入 msgId 唯一标识,共工内部接收到指令处理获取结果后,会将结果带上 msgId,gg-sdk 通过 msgId 获取记录的回调函数,并以结果为入参执行
2.6.3 源代码
以下是 gg-sdk 源代码
const listenerType = 'message';
const guid = (prefix = '') => {
return (
prefix +
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
const r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
})
);
};
// 获取url origin
const getUrlOrigin = (url) => {
return (/^https?:\/\/[\w-.]+(:\d+)?/i.exec(url) || [''])[0];
};
const log = (...args) => {
console.log('gg-sdk', ...args);
};
// iframe嵌入类型
const FRAME_TYPE = {
IFRAME_IN_GG: 'IFRAME_IN_GG', //共工内嵌iframe
GG_IN_IFRAME: 'GG_IN_IFRAME', // 第三方内嵌共工
};
// 通用iframe消息监听
function registerLintener(frameType, targetOrigin = '*', iframeRef?) {
const messageCBMap = {};
const callCommand = (cmd, data, cb?) => {
const msgId = guid('mid');
cb && (messageCBMap[msgId] = cb);
let postWindow = window.parent;
if (iframeRef?.value) {
postWindow = iframeRef?.value?.contentWindow;
}
postWindow.postMessage({ frameType, cmd, msgId, data }, targetOrigin);
};
const listenerCB = (e) => {
const { msgId, data } = e.data;
const cmdCB = messageCBMap[msgId];
if (cmdCB) {
cmdCB(data);
}
};
const removeListener = () => {
log(`removeListener ${frameType} ${targetOrigin}`);
window.removeEventListener(listenerType, listenerCB);
};
window.addEventListener(listenerType, listenerCB, false);
return { callCommand, removeListener };
}
// 指令名称
export const COMMAND_NAME = {
OPEN_PAGE: 'OPEN_PAGE', // 打开页面
CLOSE_PAGE: 'CLOSE_PAGE', // 关闭页面
RESET_FORM: 'RESET_FORM', // 重置表单
COMMON_ACTION: 'COMMON_ACTION', // commonAction
CALL_MICROFLOW: 'CALL_MICROFLOW', // 微流调用
CONTEXT_DATA: 'CONTEXT_DATA', // 上下文数据
REFRESH_PAGE: 'REFRESH_PAGE', // 刷新页面
};
// 被共工内嵌的第三方页面使用
export const registerIframeLintenerInner = () => {
log('注册iframe消息监听 inner');
const frameType = FRAME_TYPE.IFRAME_IN_GG;
return registerLintener(frameType);
};
// 第三方内嵌共工页面使用
export const registerIframeLintenerOuter = (iframeRef, url) => {
log('注册iframe消息监听 outer');
const targetOrigin = getUrlOrigin(url);
const frameType = FRAME_TYPE.GG_IN_IFRAME;
return registerLintener(frameType, targetOrigin, iframeRef);
};