AI 助手
扣子 AI 帮助与支持
你好,我是 扣子 文档问答助手 🎉 你在阅读当前文档的过程中,无论对文档概念的解释,还是文档内容方面的疑问,都可以随时向我提问,我会全力为你解答
推荐问题
扣子 3.0 都有什么新特性?
扣子和扣子编程有什么区别?
扣子如何收费?
文档反馈
低代码项目
动态
快速开始
智能体
工作流
应用
资源
发布
模型
协作
开发工具
API 参考
SDK 参考
Chat SDK
Python SDK
Node.js SDK
Java SDK
Go SDK
音视频
推广与变现

安装并使用 Card SDK

复制页面

本文介绍如何安装并使用扣子 Card SDK,开发者可以参考本文档自定义智能体对话消息中的卡片效果。

功能简介

为了助力开发者打造更具个性化与交互性的消息展示体验,扣子提供 Card SDK。借助该 SDK,开发者可以灵活地定义卡片的结构和内容,并将渲染后的卡片集成到你自行实现的聊天应用中。

卡片是一种特殊的消息展示方式,它以结构化的布局和丰富的视觉元素呈现信息。与传统的纯文本消息相比,卡片可以包含图片、按钮、列表等多种元素,使得信息更加直观、易读。这不仅显著提升了用户体验,还提高了信息传递效率,增强了交互性。

效果预览

Image

功能简介

功能 说明
自定义内容格式 Card SDK 提供了强大的自定义功能,允许开发者根据具体需求定义卡片的布局和内容。开发者可以通过配置卡片的 DSL(Domain Specific Language,领域特定语言)数据,指定卡片中各个元素的类型、样式和交互逻辑。无论是简单的文本卡片,还是包含图片、按钮和列表的复杂卡片,都可以通过Card SDK 轻松实现。
自定义卡片样式 Card SDK 还允许开发者自定义卡片中按钮、图片等组件的渲染逻辑,实现个性化的样式和交互效果。通过 customComponentMap 接口,开发者可以为每个组件定义独特的渲染函数,从而实现更加丰富的视觉效果和交互行为。开发者可以根据具体的业务需求,设计出个性化的卡片样式。

浏览器兼容性

Card SDK 的运行环境要求如下表所示。

操作系统 浏览器 版本限制
PC Chrome 87.0 及以上
Edge 100.0 及以上
Safari 14.0 及以上
Firefox 79.0 及以上
Android Chrome 100.0 及以上
Edge 100.0 及以上
iOS Chrome 87.0 及以上
Safari 14.0 及以上

配置流程

步骤一:发布智能体

在智能体的发布页面,选择 Chat SDK,并单击发布。发布的详细流程可参考发布到 Chat SDK。

步骤二:安装 Card SDK

创建一个新的 HTML 页面,并将以下代码添加到 <body> 的 <script> 标签中,保存并运行后会自动加载 Card SDK 的 JavaScript 代码。

说明

示例代码中的版本号(1.2.0-beta.8)需要替换为 Chat SDK 最新的版本号,版本信息请参见Chat SDK 发布历史。

let c = document.createElement('script');
c.src = 'https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.2.0-beta.13/libs/cn/ui.js';
document.body.appendChild(c);

步骤三:配置卡片属性

示例代码

以下是基于 React 框架编写的示例代码,用于渲染卡片布局。

import React, { useCallback, useEffect, useRef } from 'react';

// 定义 CozeCard 组件,用于创建和管理 CozeWebSDK.WebCardRuntime 实例
const CozeCard = () => {
  // 使用 useRef 创建一个可变的引用对象,用于保存 CozeWebSDK.WebCardRuntime 实例
  const clientRef = useRef();

  // 使用 useCallback 缓存函数,避免组件重新渲染时函数重新创建
  const genCard = useCallback((elem) => {
    // 如果传入的元素为空,直接返回
    if (!elem) {
      return;data 
    }
    // 如果之前已经存在 CozeWebSDK.WebCardRuntime 实例,先销毁它
    if (clientRef.current) {
      clientRef.current.destroy();
    }
    // 创建新的 CozeWebSDK.WebCardRuntime 实例并保存到 clientRef 中
    clientRef.current = new CozeWebSDK.WebCardRuntime({
      // 指定要渲染的 DOM 元素
      el: elem,
      // 自定义组件映射,定义特定组件的渲染逻辑
      customComponentMap: {
        // 自定义 NewImage 组件的渲染逻辑
        '@flowpd/cici-components/NewImage': ({ name, element, props }) => {
          // 打印开发调试信息
          console.log("[dev]", { name, element, props });
          // 设置元素的 HTML 内容
          element.innerHTML = `Test`;
          // 设置元素的宽度
          element.style.width = '100px';
          // 设置元素的高度
          element.style.height = '100px';
          // 设置元素的背景颜色
          element.style.background = 'red';
          // 返回一个销毁函数,用于处理组件卸载时的清理工作
          return () => {
            // destroy, 例如react 等问题
          };
        },
        // 自定义 ColumnLayout1_2 组件的渲染逻辑
        '@flowpd/cici-components/ColumnLayout1_2': ({ name, element, props, renderChildren }) => {
          // 从 props 中解构出 Columns 属性
          const { Columns } = props;
          // 遍历 Columns 数组,渲染每个子元素
          Columns.map((column) => {
            const { content } = column;
            const elem = renderChildren(content());
            element.appendChild(elem);
          });
          // 打印开发调试信息
          console.log("[dev]", { name, element, props });
          // 设置元素的背景颜色
          element.style.background = 'yellow';
          // 设置元素的显示方式为弹性布局
          element.style.display = 'flex';
        },
      },
      // 运行时配置选项
      runtimeOptions: {
        // 解析后的 JSON 数据,定义组件的结构和属性
        dsl: JSON.parse(
          '{"elements":{"7c1EN9VHwU":{"id":"7c1EN9VHwU","name":"FlowpdCiciComponentsColumnLayout1_2","type":"@flowpd/cici-components/ColumnLayout1_2","props":{"Columns":[{"children":["DQKOI54sJV"],"config":{"vertical":"top","width":"auto"},"type":"slot"},{"children":["FE8Y2GcSwb","L3gNU6QxiI"],"config":{"vertical":"top","weight":2,"width":"weighted"},"type":"slot"}],"action":"enableUrl","backgroundColor":"transparent","enableClickEvent":true,"url":{"type":"expression","value":"{{url}}"}},"directives":{}},"DQKOI54sJV":{"id":"DQKOI54sJV","name":"FlowpdCiciComponentsNewImage","type":"@flowpd/cici-components/NewImage","props":{"action":"enableUrl","crop":"aspectFill","enableClickEvent":false,"enableCrop":false,"fixedSize":"medium","mode":"fixed","ratio":"1:1","src":{"type":"expression","value":"{{image}}"}},"directives":{}},"FE8Y2GcSwb":{"id":"FE8Y2GcSwb","name":"FlowpdCiciComponentsText","type":"@flowpd/cici-components/Text","props":{"action":"enableUrl","color":"neutral-100","content":{"type":"expression","value":"{{title}}"},"enableClickEvent":false,"enableLines":true,"fontSize":"large","fontWeight":"bold","lines":1,"textAlign":"left"},"directives":{}},"L3gNU6QxiI":{"id":"L3gNU6QxiI","name":"FlowpdCiciComponentsText","type":"@flowpd/cici-components/Text","props":{"action":"enableUrl","color":"neutral-70","content":{"type":"expression","value":"{{content}}"},"enableClickEvent":false,"enableLines":true,"fontSize":"small","fontWeight":"normal","lines":2,"textAlign":"left"},"directives":{}},"root":{"id":"root","name":"Root","type":"@flowpd/cici-components/PageContainer","children":["7c1EN9VHwU"],"directives":{}}},"rootID":"root","variables":{"content":{"ID":"content","name":"content","defaultValue":"26/22℃ 无持续风向3-4级 28/24℃ 无持续风向<3级 30/25℃ 无持续风向<3级 26/22℃ 无持续风向3-4级 28/24℃ 无持续风向<3级 30/25℃ 无持续风向<3级"},"image":{"ID":"image","name":"image","defaultValue":""},"title":{"ID":"title","name":"title","defaultValue":"【深圳天气预报15天_深圳天气预报15天查询】-中国天气网"},"url":{"ID":"url","name":"url"}}}'
        ),
        // 是否只读
        readonly: false,
        // 是否强制远程加载
        remoteForce: false,
        // 主题样式
        theme: 'dark',
        // 语言设置
        lang: 'en',
        // 渲染完成后的回调函数
        afterRender: () => {
          console.log('[dev] afterRender');
        },
      },
    });
  }, []);

  // 使用 useEffect 处理组件卸载时的清理工作
  useEffect(() => {
    // 返回一个清理函数,在组件卸载时销毁 CozeWebSDK.WebCardRuntime 实例
    return () => {
      clientRef.current?.destroy();
    };
  }, []);

  // 返回组件的 JSX 结构
  return (
    <>
      {/* 定义一个按钮,点击时更新运行时的主题为 light */}
      <button
        onClick={() => {
          clientRef.current?.updateRuntimeOptions({
            theme: 'light',
          });
        }}
      >
        ChangeTheme
      </button>
      {/* 定义一个 div 元素,使用 ref 绑定 genCard 函数,用于初始化 CozeWebSDK.WebCardRuntime 实例 */}
      <div ref={elem => genCard(elem)} style={{
        margin: '10px',
        width: '500px'
      }} />
    </>
  );
};

// 定义 TestCardDemo 组件,用于渲染两个 CozeCard 组件
const TestCardDemo: React.FC = () => {
  return (
    <div>
      <CozeCard />
      <CozeCard />
    </div>
  );
};

// 导出 TestCardDemo 组件,供其他模块使用
export default TestCardDemo;

卡片参数

卡片初始化和个性化配置的关键参数说明如下表所示。

参数 类型 是否必选 说明
el HTML Element 必选 卡片需要渲染的 HTML 元素。
customComponentMap Object 必选 自定义组件样式,其中 key 为组件的名称。你可以从 data 字段的卡片配置中获取组件名称。例如:@flowpd/cici-components/NewImage。
runtimeOptions Object 可选 运行时的选项。
runtimeOptions.dsl Object 可选 DSL 数据,定义卡片的结构和内容。

runtimeOptions.remoteForce

Boolean

可选

是否每次都从远程拉取组件。

  • true:每次自动拉取。
  • false:不自动拉取。

runtimeOptions.debug

Boolean

可选

是否打印报错信息。

  • true:打印。
  • false:不打印。
runtimeOptions.readonly Boolean 可选 是否开启只读模式,只读模式下卡片的交互效果不生效,例如无法跳转到其他网页等。
runtimeOptions.lang String 可选 设置卡片内容的语言。例如 zh。

runtimeOptions.theme

String

可选

卡片的深浅模式。

  • light:浅色模式。
  • dark:深色模式。
runtimeOptions.afterRender Function 可选 回调函数,在组件加载成功时自动触发。
runtimeOptions.onError Function 可选 回调函数,在渲染卡片失败时自动触发。

runtimeOptions.eventCallbacks

Object

可选

交互事件的回调函数,包括:

  • onElementOut(targetElemtent, linkurl)=> void:当鼠标从卡片链接上移出的时候,触发此函数。
  • onElementOver(targetElemtent, linkurl)=> void:当鼠标在卡片链接上移动的时候,触发此函数。
  • sendMsg:当点击发送消息按钮时触发此函数。
  • previewImage({url})=> void:当点击图片的时候触发此函数。

自定义卡片组件的样式

卡片中的组件使用默认的展示效果,你也可以通过 Card SDK 的 customComponentMap 接口自定义组件的渲染逻辑,实现个性化的样式和交互效果。

customComponentMap 接口的结构如下:

type DestoryFunc = () => void;
type RenderCustomComponentFunc = (params: {
    name: string, 
    element: HTMLDivElement, 
    props: Record<string, any>, 
    renderChildren: (node: React.ReactNode) => HTMLDivElement}
) => DestoryFunc | void;

interface {
     customComponentMap?: Record<string, RenderCustomComponentFunc>;
}

说明:

  • RenderCustomComponentFunc 是用于渲染卡片组件的渲染函数。你需要自行实现该函数,函数会接收到卡片组件传递的参数,并返回一个销毁函数。RenderCustomComponentFunc 支持的属性设置如下:
    参数 类型 是否必选 示例 说明
    name String 必选 @flowpd/cici-components/NewImage 元素的名称,通常用于标识和描述元素。
    element Object 必选 { style: { width: '100px', height: '100px' } } 指定挂载自定义组件的 HTML 元素,默认为一个空的
    容器。

    props

    Object

    必选

    props:

    {

    blockId:{element.id}

    children: {子节点}

    lang: zh

    cardState: (dsl.status

    ...elementProps (处理后的)

    }

    渲染组件时使用的属性,你可以从浏览器的开发者工具中查看 props 属性的值。

    renderChildren Function 必选 - 渲染子组件的方法。如果组件中有子组件,可以使用 renderChildren 函数将子组件渲染到指定的 HTML 元素中。
  • RenderCustomComponentFunc 的返回值是一个销毁函数,不需要某个组件时可以调用此函数销毁组件。你可以根据业务场景按需选择是否销毁组件。

设置样式的示例代码

以下是通过customComponentMap接口为组件 @flowpd/cici-components/NewImage 定制样式的示例代码。

customComponentMap: {
    '@flowpd/cici-components/NewImage': ({ name, element, props }) => {
      element.style.width = '100px';
      element.style.height = '100px';
      const renderRoot = createRoot(element); //使用react渲染组件
      renderRoot.render(<div style={{
        width: '100%',
        height: '100%',
        background: 'red',
      }}>
        Image Test
      </div>);
      return () => {
        renderRoot.unmount(); //销毁函数
      }
    }
}

常见问题

Card SDK 可以在 Chat SDK 中使用吗?

集成 Chat SDK 后无需再集成 Card SDK。Chat SDK 本身已内置对卡片功能的支持,无需额外集成 Card SDK。如果你的聊天应用中未使用 Chat SDK,但需要实现卡片效果,可以直接使用 Card SDK 将渲染后的卡片集成到你自行实现的聊天应用中。