极乌客

我的一些笔记和日记

Design Token初探——Figma Tokens插件与Taro React的结合

老早之前就听说了Design Token,最近也在B站学习了草帽老师在新像素账号发表的Design Token的介绍与实战

作为UI兼开发,经常画完设计稿就懒得写样式了,不同的方式做到同一效果确实十分枯燥

使用Design Token也能减少一部分重复的工作

我对Design Token的理解

在我的理解Design Token就是将样式转换为一个Token,UI在设计时为元素或组件绑定Token后,在框架不变的情况下能够一定程度上不更改代码实现样式的更新与迭代

Design Token的搭建

首先是色板,色板的创建方式有很多种,为了方便我通过字节跳动的Figma的Semi插件生成了一个色板

然后根据草帽老师的讲解,我这里也使用了Figma Tokens插件

参考草帽老师,我建立了了三层Token:

(由于是测试可行性,我这里命名也十分草率)

目前一共是四个文件,后续根据我的工作流,可能还需要建立多个兼容文件,比如说React Native和小程序端支持的样式字段不一样

为了开发方便,token文件的名称如果没有特殊需求,最好与这个文件的根结点名字相同

上面的这个token在的根结点为com,它也存在于名为com的Token文件中

设计稿的绘制

我也随便绘制了一个设计图

为了测试切换,我就像上面的三层Token文件一样,制作了sys-dark,用于切换夜间模式

发现在设计稿中能够正常切换

结合程序开发

这样一个Token所生成的就是几个JSON文件,JSON对于开发来说再熟悉不过了,但是此时这个JSON文件转换成样式还需要另外处理

已知所有的颜色都在这几个JSON文件中,其中也有互相引用的部分

在某一个标签的颜色的Token中,在不断的寻找上一层的Token后,最终会找到这个颜色

通过这个Token我就能知道这个Token存在于哪个文件中

通过递归调用最终能找到这个颜色

由于我使用的是Taro,所以这里的例子中的夜间模式也是通过Taro的API判断的

例子代码(不是很会写TS):

import Taro from "@tarojs/taro";

import base from './token/base.json'
import sys from './token/sys.json'
import sys_dark from './token/sys-dark.json'
import com from './token/com.json'

type Token = {
    value: string | object;
    type: string;
}

export default class StyleToken {
    systemInfo: any;

    constructor() {
        this.systemInfo = Taro.getSystemInfoSync()
    }

    private getBatch(key: string): object {
        if (key[0] == '$') {
            key = key.substring(1)
        }

        switch (key.split('.')[0]) {
            case 'base':
                return base;
            case 'sys':
                if (this.systemInfo.theme === 'dark') {
                    return sys_dark;
                }
                return sys;
            case 'com':
                return com;
            default:
                return {}
        }
    }

    private getToken(token: string): null | string | Token {
        if (token[0] == '$') {
            token = token.substring(1)
        }

        let keys = token.split('.');
        let batch = this.getBatch(keys[0]);

        let result: any = batch;

        for (let i = 0; i < keys.length; i++) {
            result = result[keys[i]];
        }

        return result;
    }

    public get(token: string): string | object {
        const { value, type } = this.getToken(token) as Token;

        if (typeof value === 'string') {
            if (value[0] == '$') {
                return this.get(value.substring(1))
            } else {
                return value;
            }
        }

        if (typeof value === 'object') {
            Object.keys(value as object).map(e => {
                (value as object)[e] = this.get(value[e]);
            })

            return value!;
        }

        return value
    }
}

在全局状态中实例化上面这个StyleToken类,然后通过这个类的公开方法get获取到某个token的样式

我这里就直接在某个组件中使用了

import StyleToken from '@/common/styles/getToken'
const Style = new StyleToken();


// ......省略若干代码......

{
    backgroundColor: Style.get('sys.color.surface'),
}

// ......省略若干代码......

最终效果

我也只实践了顶上的导航栏,为了简便也没有放icon,页面的颜色切换是微信适配的

最后

这也是我对Design Token的初步探索,不知道后续会不会有所更新这一部分。

最后十分感谢草帽老师的分享,让我对Design Token有了认识。

博客服务器又迁移

上一篇

使用Docker部署包含Prisma的项目

下一篇
评论
发表评论 说点什么