# 白板

白板是显示在直播间上的一个自定义大小的图层,其显示的内容是由小程序页面里的某个区域投屏映射而来的,给开发者更大的开发空间,可以开发出更多富有创意的小程序。

PC主播端效果截图:

# 白板类型

# 普通白板

在小程序独立弹窗webview中指定某个区域进行投屏,投屏区域画面会实时同步到直播视频画面里,如下图所示

# 独立白板

小程序独立弹窗webview作为交互控制面板,通过创建白板API创建一个隐藏的webview加载相同的小程序页面,小程序里通过判断是否独立白板环境而展示不同的内容,然后将隐藏webview投屏到直播视频里。独立白板无法直接参与交互,只能通过小程序独立弹窗webview给独立白板发消息控制其交互行为,如下图所示

独立白板与小程序主webview共用相同的代码,但各自的状态却是完全独立,主webview的数据变更无法直接影响到独立白板。 独立白板使用流程大致如下:创建独立白板->克隆小程序页面->判断白板环境渲染不同的组件->监听来自主webview数据->修改白板端数据->根据白板数据渲染白板。 由于流程的特殊性以及代码复用的特点。白板的代码与主播端的代码有一定耦合,需要借助条件渲染使得白板得以渲染出不同的东西。

# 开发过程

完整的创建白板使用流程涉及多个sdk,包含:创建白板,获取初始化参数,监听发往白板的数据,发送数据给白板,删除白板等sdk。下面将由浅入深进行讲解。

# 开发基础

此步请参考示例demo送礼助手

# 新建项目

此步请参考文档

在使用@fxext/cli脚手架工具初始化项目时务必勾选 主播端推流类型

然后在开发者中心创建小程序,请参考文档

创建完小程序和版本后,需要在版本设置中 程序配置——布局类型 里将PC端布局更改为 推流 并提交保存

# 创建白板

# 普通白板

import React, { useState } from "react";
import "./index.pc.scss";

export default function Hello() {
  const [wbId, setWbId] = useState(null);
  const createWb = () => {
    // 创建普通白板
    FxExt.createWB({
      type: "NORMAL",
      x: 0,
      y: 0,
      width: 450,
      height: 560,
    })
      .then((res) => {
        setWbId(res.wbId);
      })
      .catch((err) => {
        console.error(err);
      });
  };
  return (
    <>
      <div>这是普通白板</div>
      <button className="button" onClick={createWb}>
        创建普通白板
      </button>
    </>
  );
}

创建普通白板的函数代码如上,在创建白板时可以设置白板的大小,这里设置width为450,height为560。这个数字刚好和主播端小程序webview页面的大小一致,即投屏整个小程序画面,开发者也可以通过改变参数投屏页面中某个区域。创建时需要一个state来保存白板的id值,为之后销毁白板的参数。创建好白板后,可以通过画面设置拖动面板的绿框进行大小缩放和位置移动。点击创建按钮,效果如下:

# 独立白板

独立白板和普通白板有点类似但渲染流程上却有比较大的区别,独立白板加载的是跟主播端小程序同样的页面,然后根据白板环境判断进行条件渲染出不同的路由或组件。因为是两个完全独立的页面,所以独立白板与主播端小程序的数据和状态是分开的,需要主播端小程序调用小程序SDK API FxExt.sendToExtraWB 来发送数据到独立白板,独立白板通过 FxExt.onExtraWBMessage 来监听主播端小程序发来的消息更新自身的数据和状态。下面将通过简单的demo演示这个过程。

import React, { useState } from "react";
import "./index.pc.scss";

export default function Hello() {
  const [wbId, setWbId] = useState(null);
  const [wbMsg, setWbMsg] = useState('');
  const createWb = () => {
    // 创建独立白板
    FxExt.createWB({
      type: "EXTRA",
      x: 0,
      y: 0,
      width: 450,
      height: 560,
    })
      .then((res) => {
        setWbId(res.wbId);
      })
      .catch((err) => {
        console.error(err);
      });
  };
  return (
    <>
      <div>收到的消息</div>
      <div className="msg">{wbMsg}</div>
      <label>数据</label>
      <input />
      <button className="button" onClick={sendMsgToWb}>
        发送数据
      </button>
      <button className="button" onClick={createWb}>
        创建白板
      </button>
    </>
  );
}

创建独立白板的代码如上,创建独立白板时设置的width和height为独立白板容器的大小。创建独立白板后需要保存白板id值即wbId,以便后续往该独立白板发送数据或移除该白板。创建好白板后,可以在直播伴侣画面设置对该白板进行大小缩放或位置移动。点击创建按钮,效果如下:

可以看出独立白板此时渲染的画面和主播端小程序一致,但这两个页面的state却是完全独立的,除了该区别外,独立白板其他行为跟主播端小程序一致,包括小程序SDK API调用。

# 独立白板数据监听与修改

直接通过主播端小程序setState是改变不了独立白板的数据,只会影响主播端小程序本身,因此需要调用监听函数提供一个修改独立白板端数据的桥梁。

调用监听函数的操作必须放在组件初始化或生命周期里,只有这些地方,创建独立白板后独立白板会一并执行,而放在其他地方将无法确保独立白板及时监听来自主播端小程序发来的消息。

如下,在初始化函数中加入监听函数,同时在原先发送数据的按钮上添加发送数据到独立白板这一操作,代码如下:

// 独立白板初始化函数加入监听操作
useEffect(() => {
  // 获取当前环境的白板信息
  FxExt.getWBInfo().then(({ wbId, param }) => {
    // 如果当前环境的wbId不为空则为独立白板环境
    if (wbId) {
      // 独立白板环境则初始化时监听主播端小程序消息
      FxExt.onExtraWBMessage(msg => {
        console.log(msg)
        setWbMsg(msg);
      });
    }
  });
}, []);

// 主播端小程序发送白板数据到独立白板
const sendMsgToWb = () => {
  FxExt.sendToExtraWB({
    wbId,
    data: inputRef.current.value
  });
}

如图,数据成功传送到了独立白板的msg上,与此同时,主播端小程序和独立白板的显示出现了一定差异,印证了主播端小程序的数据和独立白板的数据是独立分开的这一特性。

# 条件渲染

独立白板数据和主播端小程序数据是分开的,因此可以根据数据的不同,让独立白板渲染出和主播端小程序完全不一样的效果出来。下面讲解怎么区分独立白板数据与主播端小程序数据并渲染不同的内容。

export default function Hello() {
  const [isWb, setIsWb] = useState(false);
  useEffect(() => {
    // 调用SDK API获取当前环境的白板信息
    FxExt.getWBInfo().then(({ wbId, param }) => {
      // 如果当前环境的wbId不为空则为独立白板环境
      if (wbId) {
        setIsWb(true);
        // 独立白板环境则初始化时监听主播端小程序消息
        FxExt.onExtraWBMessage(msg => {
          setWbMsg(msg);
        });
      }
    });
  }, []);

  const renderWb = () => {
    return (
      <>
        <div>这里是独立白板</div>
        <div className="msg">{wbMsg}</div>
      </>
    );
  };

  const renderForm = () => {
    // 和原先主播端小程序渲染函数一致
  };

  // 根据是否是白板环境渲染不同的组件
  if (isWb) {
    return renderWb();
  } else {
    return renderForm();
  }
}

# 总结

这个小程序主要讲解了普通白板和独立白板的区别以及用法:独立白板与主播端小程序共用一套代码,但有着独立的数据状态。主要通过以下SDK方法实现了主要功能。

# FAQ

Q: 如何调试独立白板?

A: 在主播端小程序创建独立白板后,可通过 Ctrl + F12 打开独立白板控制台。

Q: 能否创建多个白板?

A: 不行,每个小程序只能创建一个白板。

Q:为什么我创建了白板之后看不到白板?

A:参数需要确保正确,请确保设置好了长和宽。

Q:独立白板端能否主动传递数据给主播端小程序?

A:不能。只能由主播端小程序单向发数据给独立白板控制其行为。