跳转到内容

立即体验按钮

默认情况下,素材下载完成后,Kivicube 会展示“立即体验”按钮,等待用户点击后再真正进入场景。

为什么默认保留这个按钮

它不仅是一个 UI 元素,也承担了浏览器媒体策略上的作用:

  • 让浏览器知道是用户在请求打开摄像头,否则可能打开失败
  • 为音频和视频提供用户手势来激活,方便后续正常播放
  • 避免在资源刚下载完就立即进入体验造成闪屏或突兀切换
  • 给宿主层留出展示说明、提示权限的时间

强制隐藏

可以通过属性 hideStart 强制隐藏:

js
await kivicubeIframePlugin.openKivicubeScene(iframe, {
  sceneId,
  hideStart: true,
});

或在 HTML 中写:

html
<iframe id="kivicubeScene" scene-id="..." hide-start></iframe>

隐藏后的影响

  • AR体验时的背景可能变黑或白,因为摄像头打开失败
  • 素材下载完成后会直接开始加载,进入AR体验,不出现此按钮
  • 如果场景里有视频或音频,浏览器可能拦截播放请求

更稳妥的替代方案

比起直接 hideStart,更推荐:

  1. 保留平台的开始逻辑
  2. 或者宿主自己自定义一个“立即体验”按钮
  3. 在用户点击后再允许流程继续

如果你的业务一定要按钮存在才能功能正常,建议用宿主层按钮配合默认流程事件,而不是粗暴自动进入。

适合隐藏的场景

  • 纯 Web3D 展示,无音视频播放要求
  • 体验流程非常短,希望减少一步点击

不建议隐藏的场景

  • 视频、音频较多,且有需求进行自动播放
  • 需要用户先明确授权或阅读提示

自定义立即体验按钮

如果你想保留 Kivicube 原生“立即体验”按钮提供的默认能力,但又希望把按钮和宿主页 UI 对齐,可以使用场景或合辑高级 API 提供的两个方法:

ts
getStartButtonRect(): Promise<DOMRect | undefined>
setStartButtonRect(rect: Partial<CSSStyleDeclaration>): Promise<void>
  • getStartButtonRect() 返回 iframe 内真实按钮的 getBoundingClientRect() 结果。
  • setStartButtonRect(rect) 会把传入对象合并到按钮的内联样式上,常用字段包括 positionlefttoprightbottomwidthheighttransform等。

获取方式

场景页中,在 ready 事件里拿到 SceneApi

js
let api = null;

iframe.addEventListener('ready', (event) => {
  api = event.detail.api;
});

合辑页中,在 ready 事件里拿到 CollectionApi

js
let api = null;

iframe.addEventListener('ready', (event) => {
  api = event.detail.api;
});

场景中

什么时候调用

  • 在ready事件及后续事件中,都可调用,例如 downloadAssetEnd。可在按钮出现前提前获取位置大小,和修改其位置大小。
  • 如果配置了 hideStart: true,通常也可以调用,但失去了意义。

宿主页在相同位置覆盖一个自定义按钮,并设置 CSS pointer-events: none,让点击落到 iframe 的真实按钮上。

常见方案A:直接调整 iframe 内按钮的位置和大小

通过 setStartButtonRect() 直接把 iframe 内按钮移动到新的位置,再和宿主层标题、提示文案、品牌装饰进行对齐。

js
const hostStartButton = document.querySelector('#hostStartButton');
hostStartButton.style.visibility = 'hidden'; // 默认先隐藏按钮
hostStartButton.style.pointerEvents = 'none'; // 必须配置
iframe.addEventListener("ready", async (e) => {
  const api = e.detail.api;

  // 确保此时hostStartButton按钮在DOM中已经渲染完成,并完成布局。
  const rect = hostStartButton.getBoundingClientRect();
  // 让下面iframe中的开始按钮,和上面按钮的位置大小保持一致。
  // 才能在用户点击上面按钮时,击穿到下面实际开始按钮上。
  // 也同时覆盖插件内部的按钮,才能进行按钮样式自定义。
  await api.setStartButtonRect({
      left: rect.left + 'px',
      top: rect.top + 'px',
      width: rect.width + 'px',
      height: rect.height + 'px'
  });
});
iframe.addEventListener("downloadAssetEnd", async (e) => {
  // 素材下载完成,显示按钮
  hostStartButton.style.visibility = 'visible';
});
iframe.addEventListener("loadSceneStart", (e) => {
  // 当iframe中的开始按钮被点击,就开始加载场景,此时隐藏按钮
  hostStartButton.style.display = 'none';
});

常见方案B:读取按钮区域,在宿主层覆盖自定义按钮

通过 getStartButtonRect() 让自定义按钮和 iframe 内按钮位置大小保持一致,同时覆盖插件内部的按钮,才能进行按钮样式自定义。

js
const hostStartButton = document.querySelector('#hostStartButton');
iframe.addEventListener('ready', (event) => {
  const api = event.detail.api;

  const rect = await api.getStartButtonRect();
  Object.assign(hostStartButton.style, {
    visibility: 'hidden', // 此时隐藏
    position: 'fixed',
    left: `${rect.left}px`,
    top: `${rect.top}px`,
    width: `${rect.width}px`,
    height: `${rect.height}px`,
    pointerEvents: 'none', // 重要,必须设置
  });
});
iframe.addEventListener("downloadAssetEnd", async (e) => {
  // 素材下载完成,显示按钮
  hostStartButton.style.visibility = 'visible';
});
iframe.addEventListener("loadSceneStart", (e) => {
  // 当iframe中的开始按钮被点击,就开始加载场景,此时隐藏按钮
  hostStartButton.style.display = 'none';
});

无论方案A还是B,都是让iframe内的按钮和宿主层的按钮保持一致,然后点击宿主层按钮时,点击事件穿透到iframe内的按钮上,从而触发iframe内的按钮点击事件。

合辑中

等待完善,但核心逻辑和场景一致。