暗黑模式支持

我不记得什么时候开始流行起来的“暗黑模式/深色模式”(英文叫 Dark Mode),现在主流的应用乃至手机都默认内置支持暗黑模式,在iPhone手机上面,还可以自动根据时间切换呢。据说这个模式特别适合在夜晚时使用,对眼睛有些好处吧。

Teams的客户端也默认支持暗黑模式,并且还支持多一种,叫高对比度模式,这种模式对于视力不太好的用户来说会有很大的帮助。

如何支持多主题

那么,如何让你设计的应用,也能支持以上提到的三种模式呢?首先,这个要从不同的场景来介绍。

如果是机器人,或者消息扩展,或者连接器等开发场景,本质上它们与用户的交互,都是通过消息来实现的,这种消息可能是文本消息,也可能是卡片消息。而不管是哪一种,因为最终的呈现都是由Teams自己来实现,所以它默认就会根据当前客户端的主题色进行自动切换,你无需做任何的额外工作。例如下面几个卡片,在不同的主题模式下显示的效果。

浅色模式

深色模式

高对比度模式

作为应用开发者,你真正需要关心的是选项卡应用,因为这些界面是由你自己实现的。那么到底怎么实现呢?下面是我总结的三个经验和常见做法:

  1. 尽量用到官方提供的组件库来构建界面
  2. 默认加载当前客户端的主题
  3. 检测Teams客户端的主题切换

要实现上面的东西不难,因为官方已经提供了框架进行支持。下面通过一个实际的例子带领大家了解一下吧。

创建项目

本例使用 Node.js 来实现,请安装好必要的工具,并运行下面的命令来创建项目。

npx create-react-app themeapp --template typescript

然后继续运行命令

cd themeapp
yarn add @microsoft/teams-js @fluentui/react-northstar

这里添加的两个模块,都是微软官方提供的,第一个是Teams的客户端JS SDK,可以用来跟客户端打交道(本例用来检测客户端的主题,及其变化),第二个是官方提供的UI框架,它里面定义了很多我们需要用到的组件,可以直接用,并且它定义了以上提到的三套主题的样式。

使用当前主题

通过如下的方式,修改App.tsx 的代码

import { Button, Flex, FlexItem, Provider, Segment, teamsTheme } from "@fluentui/react-northstar";

const App = () => {


  return (
    <Provider theme={teamsTheme}>
      <Flex column fill gap="gap.small">
        <Flex>
          <FlexItem push>
            <Segment content="用户名" color="blue"></Segment>
          </FlexItem>
        </Flex>

        <Segment content="第一行文字." color="red" />
        <Segment inverted content="第二行文字." color="red" />
        <Button content="按钮" primary></Button>
      </Flex>
    </Provider>
  );
};


export default App;

这个代码其实很简单,fluentui 这套框架提供了一个Provider的组件,可以从顶层往下层传递主题的信息,而teamsTheme是当前客户端的主题信息。其他一些代码都是基本的一些布局和组件,这里只是做范例演示。

看起来还不错,但是如果你现在去切换设置中的主题,你会发现界面并没有变化,例如即便我切换到暗黑模式,以上的界面还是没有变化,而在暗黑模式下,会很不协调。

检测主题的变化

我们需要检测到第一次加载时的主题,以及后续用户手动在进行主题的切换这个行为。这个可以通过 JS SDK来实现。下面是实现的代码。

import { Button, Flex, FlexItem, Provider, Segment, teamsDarkTheme, teamsHighContrastTheme, teamsTheme, ThemePrepared } from "@fluentui/react-northstar";
import * as microsoftTeams from "@microsoft/teams-js";
import { useState, useEffect } from "react";


const App = () => {

  const [theme, setTheme] = useState<ThemePrepared>();

  useEffect(() => {
    microsoftTeams.initialize();
    microsoftTeams.getContext((ctx) => {
      switch (ctx.theme) {
        case "dark":
          setTheme(teamsDarkTheme);
          break;
        case "contrast":
          setTheme(teamsHighContrastTheme);
          break;
        default:
          setTheme(teamsTheme)
          break;
      }
    });

    microsoftTeams.registerOnThemeChangeHandler((theme) => {
      switch (theme) {
        case "dark":
          setTheme(teamsDarkTheme);
          break;
        case "contrast":
          setTheme(teamsHighContrastTheme);
          break;
        default:
          setTheme(teamsTheme)
          break;
      }
    })

  }, [])


  return (
    <Provider theme={theme || teamsTheme}>
      <Flex column fill gap="gap.small">
        <Flex>
          <FlexItem push>
            <Segment content="用户名" color="blue"></Segment>
          </FlexItem>
        </Flex>

        <Segment content="第一行文字." color="red" />
        <Segment inverted content="第二行文字." color="red" />
        <Button content="按钮" primary></Button>
      </Flex>
    </Provider>
  );
};


export default App;

现在,当用户切换到暗黑模式后,我们都界面也会自动更换颜色,这样看起来就很舒服,不是吗?

使用第三方库

上面的实现方式挺简单的,但是代码看起来还是有点繁琐。其实上面这么写出来,是想让大家理解这个原理,真正开发时,你可以通过一定第三方库来更加容易地实现。这个库叫 msteams-react-base-component , 你可以通过这里了解更多它的信息。

yarn add msteams-react-base-component

用如下的代码覆盖掉App.tsx .

import {
  Button,
  Flex,
  FlexItem,
  Provider,
  Segment
} from "@fluentui/react-northstar";
import { useTeams } from "msteams-react-base-component";



const App = () => {

  const [{ theme }] = useTeams();

  return (
    <Provider theme={theme}>
      <Flex column fill gap="gap.small">
        <Flex>
          <FlexItem push>
            <Segment content="用户名" color="blue"></Segment>
          </FlexItem>
        </Flex>

        <Segment content="第一行文字." color="red" />
        <Segment inverted content="第二行文字." color="red" />
        <Button content="按钮" primary></Button>
      </Flex>
    </Provider>
  );
};


export default App;

只要一行代码就可以搞定,看起来真不错。

这个案例的完整代码,请参考

https://github.com/code365opensource/teamsapp-samples-tab-theming

results matching ""

    No results matching ""