classnames-rs 库

classnames-rs 库

大家好, 好久没有更新文章了, 接下来我会分享一些 rust, Dioxus 相关的知识. 并会翻译 Dioxus 的官方文档. 有兴趣的可以关注一下哦.

介绍

虽然我已经接触 rust 好多年了, 但也是最近才使用它来开发后台服务, 并且最近开始学习 Dioxus 框架, 他是一个 rust 开发的跨平台 GUI 库.他利用 web 技术, 能够做到一份代码在多平台运行.和 tauri 不同的是, Dioxus 有自己的 DSL 他和 rust 代码有很好的结合, 并且利用 IDE 能做到很好的代码提示.

在接下来的学习过程中, 我会翻译其官方文档并发布在该公众号. 喜欢 Dioxus 的朋友可以关注一下我, 我们一起学习进步.我也会尽可能在学习过程中结合自己的使用, 分析一些更有趣的 demo.

来自 classnames 的灵感

今天先来分享一下我写的 classnames-rs, classnames-const-rs 库, 它的灵感来自前端的 classnames 库.我在使用 Dioxus 进行web 开发时, 发现处理和管理 class 样式代码有很多缺点

  1. 样式混杂不清晰, 无法注解,也不利于后期维护
  2. 对于一些条件可选的样式, 会导致代码充斥了大量的样板代码

缺点分析

可选的组件样式

就如下面代码中的条件判断, 每次组件收到条件都要进行必要的判断:

rust 复制代码
let icon_class = if let Some(class) = &props.class {
        format!("animate-spin {}", class) // 对于 loading 状态添加旋转动画
    } else if matches!(props.status, ValidationStatus::Loading) {
        "animate-spin".to_string()
    } else {
        String::new()
    };

我们需要判断通过组件传入的 class 样式是否为 None, 如果不为 None, 则进行拼接.

动态的条件判断

再比如下面的代码, 我们需要根据动态的状态 (比如是否 disabled), 来控制其样式

rust 复制代码
let class = if props.is_support {
    props.product.class()
} else {
    "text-zinc-400 dark:text-zinc-500 opacity-60 grayscale".to_string()
};

混杂的样式定义

当我们定义样式时, 很容易定义成如下的样式

rust 复制代码
pub const BASE_STYLE: &str = "relative block w-full before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm";

使用 classnames-rs 库

正是因为这些缺点,我开发了这2个库

  1. classnames-rs 运行时处理样式
  2. classnames-const-rs 编译时处理样式,确保0运行时开销

classnames-const-rs 库

我们可以使用 classnames-const-rs 来优化静态样式的定义, 如下:

rust 复制代码
pub(crate) const CONTROL: &str = classnames_concat!(
    // Basic layout
    "relative block w-full",
    // Background color + shadow applied to inset pseudo element, so shadow blends with border in light mode
    "before:absolute before:inset-px before:rounded-[calc(var(--radius-lg)-1px)] before:bg-white before:shadow-sm",
    // Background color is moved to control and shadow is removed in dark mode so hide `before` pseudo
    "dark:before:hidden",
    // Focus ring
    "after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:ring-transparent after:ring-inset sm:focus-within:after:ring-2 sm:focus-within:after:ring-blue-500",
    // Disabled state
    "has-data-disabled:opacity-50 has-data-disabled:before:bg-zinc-950/5 has-data-disabled:before:shadow-none",
    // Invalid state
    "has-data-invalid:before:shadow-red-500/10",
);

我们可以自由的注释样式含义, 方便管理和后期维护.而无需担心运行时的开销, 因为都是静态字符串, 会在编译时进行字符串拼接处理.

classnames-rs 库

我们可以使用该库来管理所有动态的条件判断:

rust 复制代码
let class = classnames!(
	CONTROL,
	choose!(props.is_support, props.product.class(), "text-zinc-400 dark:text-zinc-500 opacity-60 grayscale"),
	maybe!(props.class),
	when!(is_activate, "btn btn-active")
);

几行代码就实现了之前需要多个 if else 的样板代码才能实现的功能. 我来介绍一下库中的主要宏

  • classnames! 主要宏, 用来拼接多个 class 样式表达式
  • choose! 如代码的 if else 其参数顺序为 判断表达式, true_value 表达式, false_vlaue 表达式
  • maybe! 用来处理 Option<T> 类型
  • when! 是 单条件的写法 结合使用这些宏, 可以极大的方便 class 样式的编写.

总结

我们使用 classnames-const-rs 库的 classnames_concat!宏来定义管理静态的基础样式, 他会在编译时生成静态字符串对象, 没有运行时开销. 使用 classnames-rsclassnames! 宏来组装运行时的条件判断.

感谢看到最后, 这是我写的第一篇公众号文章, 文章可能有不少啰嗦不当之处, 敬请谅解.

相关推荐
翻滚吧键盘2 分钟前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js
秃了也弱了。20 分钟前
Chrome谷歌浏览器插件ModHeader,修改请求头,开发神器
前端·chrome
乆夨(jiuze)41 分钟前
记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。
前端·javascript·vue.js
忧郁的蛋~1 小时前
HTML表格导出为Excel文件的实现方案
前端·html·excel
小彭努力中1 小时前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
然我1 小时前
别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考
前端·面试·html
NanLing1 小时前
【纯前端推理】纯端侧 AI 对象检测:用浏览器就能跑的深度学习模型
前端
呆呆的心1 小时前
前端必学:从盒模型到定位,一篇搞定页面布局核心 🧩
前端·css
小飞悟1 小时前
前端高手才知道的秘密:Blob 居然这么强大!
前端·javascript·html
小old弟1 小时前
用Sass循环实现炫彩文字跑马灯效果
前端