news 2026/9/10 15:55:44

tldraw 修改默认样式指南:用 StyleProp.setDefaultValue 控制新形状的默认 size、color、dash 与 fill

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
tldraw 修改默认样式指南:用 StyleProp.setDefaultValue 控制新形状的默认 size、color、dash 与 fill

tldraw 修改默认样式指南:用 StyleProp.setDefaultValue 控制新形状的默认 size、color、dash 与 fill

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

tldraw中每个样式属性(style prop)都带有内置默认值:新建形状默认使用m尺寸、black颜色、draw线条样式等。本文以仓库中的官方示例 changing-default-style 为骨架,讲解如何通过setDefaultValue在运行时替换这些默认值,并结合@tldraw/tlschema中 StyleProp 的实现 深入说明其原理、可用取值与调用时机。读完本文后,你将能在自己的 tldraw 应用中随心定制“新图形出厂样式”,也能把同一套方法迁移到自定义样式属性上。

从一个官方示例开始:让新形状默认变小

官方示例的核心诉求很直接:把内置size样式的默认值从m改为s,使之后新建的每个形状都默认是小号

完整的示例组件位于 ChangingDefaultStyleExample.tsx,其注册说明见同目录下的 README.md。核心代码只有几行:

import { DefaultSizeStyle, Tldraw } from 'tldraw' import 'tldraw/tldraw.css' // Call this at module level, before any editor is created, so every editor // (and every new shape) picks up the new default. DefaultSizeStyle.setDefaultValue('s') export default function ChangingDefaultStyleExample() { return ( <div className="tldraw__editor"> <Tldraw persistenceKey="changing-default-style-example" /> </div> ) }

逐行拆解:

  • DefaultSizeStyle是 tldraw 导出的一组内置样式属性常量之一,定义在 TLSizeStyle.ts;
  • setDefaultValue('s')把该样式属性的默认值改写为's'
  • 注释中的“module level”(模块顶层)是成败关键:setDefaultValue必须在任何Tldraw/Editor实例创建之前执行,改动才会对所有编辑器与之后创建的所有新形状生效;
  • <Tldraw persistenceKey="changing-default-style-example" />用于示例数据的本地持久化隔离;外层<div className="tldraw__editor">是各示例共用的容器类名,用来占据视口并把画布铺满(tldraw/tldraw.css已随包导出并被引入)。

在仓库中启动该示例的方式与其它apps/examples示例一致:在apps/examples目录安装依赖后,按 package.json 中的开发脚本(vite dev server)启动,再打开本示例对应的路由即可交互验证——新建一个形状,其描边、文字等尺寸相关表现均为小号。

setDefaultValue 的底层实现

setDefaultValue并不是什么魔法,它本质上是StyleProp类上的一个普通实例方法。看 StyleProp.ts 的实现:

/** @internal */ protected constructor( readonly id: string, public defaultValue: Type, readonly type: T.Validatable<Type> ) {} setDefaultValue(value: Type) { this.defaultValue = value }

可见:

  • defaultValue在构造时作为公开可读写字段public defaultValue)保存,setDefaultValue只是对它重新赋值,API 语义更清晰、便于阅读与搜索;
  • 每个StyleProp还带一个唯一的id与一个type校验器,前者用于区分不同属性,后者在形状数据落库、加载时用于校验取值。

EnumStyleProp 与 defineEnum

DefaultSizeStyleDefaultColorStyle这类“有固定枚举取值”的属性,实际由StyleProp.defineEnum创建为EnumStyleProp子类实例(见 StyleProp.ts 中 defineEnum 与 EnumStyleProp):

static defineEnum<const Values extends readonly unknown[]>( uniqueId: string, options: { defaultValue: Values[number]; values: Values } ) { const { defaultValue, values } = options return new EnumStyleProp<Values[number]>(uniqueId, defaultValue, values) }

EnumStyleProp在父类基础上额外维护了一个只读的values数组,并用T.literalEnum(...values)构造取值校验器。因此DefaultSizeStyle既知道“当前默认值是什么”,也知道“合法取值有哪些”。顺带一提,枚举子类还提供了运行时扩展能力addValues/removeValues(StyleProp.ts#L130-L157),可用于向内置颜色等集合追加/移除自定义值,但需要注意同步修改相关 TypeScript 类型。

内置默认样式速查表

了解内置样式属性的默认值与合法取值,是决定“改成什么”的前提。下表信息均来自packages/tlschema/src/styles/下的真实定义:

样式属性属性 id内置默认值可选值源码位置
DefaultSizeStyletldraw:size'm'smlxlTLSizeStyle.ts
DefaultColorStyletldraw:color'black'见下方说明TLColorStyle.ts
DefaultLabelColorStyletldraw:labelColor'black'同颜色集TLColorStyle.ts
DefaultDashStyletldraw:dash'draw'drawsoliddasheddottednoneTLDashStyle.ts
DefaultFillStyletldraw:fill'none'nonesemisolidpatternfilllined-fillTLFillStyle.ts

几点补充说明,避免误用:

  • 颜色取值比较特殊TLColorStyle.ts中用于初始化的名称集合包含blackgreylight-violetvioletbluelight-blueyelloworangegreenlight-greenlight-redredwhite等,但注释明确指出颜色命名空间的真正事实来源已经迁移到TLTheme(TLTheme 相关代码及registerColorsFromThemes会动态同步注册的色名)。也就是说,可用色名会随主题定义而变化,修改颜色默认值前建议以当前主题导出的色名为准。
  • size会同时影响描边粗细、文字字号等成比例元素。tldraw 在 default-shape-constants.ts 中用STROKE_SIZESFONT_SIZES等常量把s/m/l/xl映射为具体像素数值,这也是改动 size 默认值后“肉眼可见变小/变大”的落点。
  • draw是 tldraw 的手绘风格线条(类似手写草图质感),solid才是常规实线;fillsemi表示半透明填充,pattern/lined-fill则是基于当前颜色的纹理填充。

实战扩展:同时改写多个默认样式

setDefaultValue是普通实例方法,你可以对任意多个内置样式属性依次调用,组合出“你想要的新手形状出厂外观”。例如希望新形状默认为小号、红色、实线、实心填充:

import { DefaultColorStyle, DefaultDashStyle, DefaultFillStyle, DefaultSizeStyle, Tldraw, } from 'tldraw' import 'tldraw/tldraw.css' // 全部在模块顶层、创建编辑器之前执行 DefaultSizeStyle.setDefaultValue('s') // 默认尺寸:小 DefaultColorStyle.setDefaultValue('red') // 默认颜色:红 DefaultDashStyle.setDefaultValue('solid') // 默认线条:实线 DefaultFillStyle.setDefaultValue('solid') // 默认填充:实心 export default function CustomDefaultStylesExample() { return ( <div className="tldraw__editor"> <Tldraw /> </div> ) }

实际使用中的经验要点:

  1. 取值必须属于该 prop 的合法枚举setDefaultValue的当前实现只是赋值,并不会在调用瞬间对取值做合法性校验(校验发生在数据读写时,由T.literalEnum构造的type完成)。传一个不在values里的字符串,不会立即报错,却可能在后续数据校验阶段暴露问题,因此务必对照上表取值。
  2. 改写是全局生效的。这些内置 prop 是模块级单例常量,setDefaultValue改变的是进程内共享状态。如果你在不同的入口/路由中希望使用不同默认值,应当只在“创建编辑器之前唯一执行一次”的位置(例如应用入口文件)调用,避免顺序依赖带来的不确定性。
  3. 自定义形状同样受益。若你的自定义 shape 在 props 里复用了DefaultSizeStyleDefaultColorStyle等内置 prop(这正是 tldraw 官方推荐做法,见 StyleProp.ts 的类文档),那么对内置 prop 默认值的改写会一并影响这些自定义形状,无需逐个维护。

调用时机:为什么必须早于编辑器创建

该示例 README 特别强调setDefaultValue要在“任何编辑器创建之前”于模块顶层调用,其原因可以结合StyleProp的类文档(StyleProp.ts#L4-L23)理解:

同一个值可以被同时设置到大量形状上;最近一次使用的值会被自动保存,并应用到之后新建的形状

tldraw 的样式机制本质上是一个“最近使用(last used)”追踪器:你在工具栏选择颜色、尺寸后,后续新建的形状都会沿用该值;而用户尚未做任何选择时,形状会回退到该样式属性此刻的defaultValuesetDefaultValue改写的正是这个兜底默认值。

因此,把调用放在模块顶层、早于Tldraw挂载,可以保证:

  • 编辑器内部状态初始化时读到的就是新默认值;
  • 新建形状、粘贴外部内容等路径在“无最近使用记录”的情况下全部落到新默认值上,行为处处一致。

如果在编辑器已经创建之后再调用,此时编辑器可能已经用旧默认值初始化了样式状态,或已有形状记录了各自显式取值,改写效果就会大打折扣、难以保证“处处生效”。

与另一种方案的关系:自定义 StyleProp 时直接给 defaultValue

除了运行时改写内置 prop,更“源头”的做法是在用StyleProp.define/StyleProp.defineEnum自定义样式属性时就指定默认值。两种方式互补:

import { T } from '@tldraw/validate' import { StyleProp } from '@tldraw/tlschema' // 数值型自定义样式:定义时直接确定默认值 const MyLineWidthProp = StyleProp.define('myApp:lineWidth', { defaultValue: 1, type: T.number, }) // 枚举型自定义样式 const MySizeProp = StyleProp.defineEnum('myApp:size', { defaultValue: 'medium', values: ['small', 'medium', 'large'], })

二者都作用于StyleProp.defaultValue这一字段:

  • 定义时设置适合“这个样式属性天然就该用什么默认值”的场景,属于声明式、确定性的配置;
  • setDefaultValue运行时改写适合对内置 prop(你无法改变其定义)或共享 prop 做全局定制,比如本文示例那样把整个应用的默认尺寸改成s

若你的需求只是某个编辑器实例局部生效,更贴合 tldraw 架构的做法是自定义一个带默认值的StyleProp,而不是改写全局共享的内置 prop;若需求是“整个应用的新手形状一律小号”,那么示例中的setDefaultValue就是最直接、最小侵入的方案。

小结

setDefaultValue为 tldraw 的样式体系提供了一个轻量的全局定制入口:一行DefaultSizeStyle.setDefaultValue('s')即可让之后创建的每个形状默认变小。它的背后是StyleProp中简单直白的字段赋值(StyleProp.ts#L90-L92),而“何时生效”则依赖 tldraw 的“最近使用值优先、默认值兜底”样式机制。把握住三点即可用好它:取值须在合法枚举内、调用须在编辑器创建前的模块顶层、内置 prop 的改动会影响所有复用它们的形状。如需继续深入,可进一步阅读仓库中的 StyleProp 完整实现、内置样式的四个定义文件(size / color / dash / fill),以及示例编写规范,了解如何把这类“默认样式定制”沉淀为可在画廊中直接运行交互的官方示例。

【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. World's best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 15:54:32

Simulink仿真风光储微电网:建模与优化实践

1. 项目概述&#xff1a;风光储互补微电网的Simulink仿真实践 风光储互补微电网作为新能源领域的重要研究方向&#xff0c;通过整合风力发电、光伏发电和储能系统&#xff0c;实现了能源的多元化利用与稳定供应。我在最近的一个微电网优化项目中&#xff0c;采用MATLAB/Simulin…

作者头像 李华
网站建设 2026/9/10 15:53:53

消除游戏-flask sqlite

本项目为前几天收费帮学妹做的一个项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 网页版休闲消除游戏 — 霓虹赛博朋克风格 127.0.0.1:5000/ 二、项目功能 – &am…

作者头像 李华
网站建设 2026/9/10 15:52:51

Python异步编程与结构化并发实战解析

1. Python异步编程的现状与挑战在当今互联网应用中&#xff0c;高并发处理能力已经成为衡量系统性能的关键指标。Python作为最受欢迎的编程语言之一&#xff0c;其异步编程模型近年来经历了重大变革。从早期的回调地狱到现在的async/await语法&#xff0c;Python的异步生态已经…

作者头像 李华