Svelte 模板基础语法详解:从 HTML++ 标记、属性规则到事件委托实现 Svelte 模板基础语法详解从 HTML 标记、属性规则到事件委托实现【免费下载链接】svelteweb development for the rest of us项目地址: https://gitcode.com/GitHub_Trending/sv/svelte本文基于 Svelte 官方文档 Basic markup 展开系统讲解 Svelte 组件中HTML模板体系的六大核心能力元素与组件标签的区分规则、静态/动态属性及布尔属性的取值语义、组件 props 与展开属性、on*事件属性及其底层的事件委托机制、花括号文本表达式与 HTML 转义以及注释的多种形态。读完后你将不仅会写 Svelte 模板还能结合仓库源码如 utils.js、events.js理解这些语法在编译期与运行期的真实行为。Svelte 模板HTML 心智模型Svelte 组件中的标记markup可以被视为HTML它在标准 HTML 之上叠加了 JavaScript 表达式、组件引用、展开属性和响应式能力但不改变 HTML 的基本形态。掌握这套模板语法的关键在于分清三类标记——普通元素、组件、表达式——以及它们各自遵循的规则。标签元素还是组件标签的大小写和命名方式决定了它的语义小写标签如div表示普通的 HTML 元素首字母大写的标签如Widget或使用点号分隔的标签如my.stuff表示一个组件component。script import Widget from ./Widget.svelte; /script div Widget / /div组件必须先在script中通过import引入才能在模板中使用。编译器会根据标签名判断目标类型进而走不同的转换路径——元素走 DOM 属性/事件逻辑组件走 props 传参与实例化逻辑。元素属性Element Attributes静态属性与无引号值默认情况下元素属性与标准 HTML 行为完全一致div classfoo button disabledcant touch this/button /div和 HTML 一样属性值可以不加引号input typecheckbox /表达式在值中或就是值属性值中可以用花括号内嵌任意 JavaScript 表达式a hrefpage/{p}page {p}/a整个属性值也可以直接是一个表达式button disabled{!clickable}.../button这两种写法在 客户端属性编译逻辑 中都会被统一处理静态字符串走字符串字面量路径含表达式的属性则被编译为可在响应式更新时重新求值的动态调用。布尔属性与 nullish 规则这是 Svelte 属性语义中最容易被误解的一点文档明确区分了两类规则布尔属性值为truthy时属性出现在元素上值为falsy时属性被移除其他所有属性只要值不是nullish即null或undefined就会出现。input required{false} placeholderThis input field is not required / div title{null}This div has no title attribute/div[!NOTE] 给单个表达式加引号不影响值的解析方式但在 Svelte 6 中会导致值被强制转换为字符串button disabled{number ! 42}.../button哪些属性算布尔属性由源码中的白名单决定。在 utils.js 中DOM_BOOLEAN_ATTRIBUTES列出了allowfullscreen、autofocus、checked、disabled、muted、required、readonly等 28 个属性is_boolean_attribute()据此判断——所以button disabled{!clickable}中的!clickable走的是truthy 则保留、falsy 则移除的分支而不是把false写进 DOM。属性简写Shorthand当属性名与值相同name{name}时可简写为{name}button {disabled}.../button !-- 等价于 button disabled{disabled}.../button --组件 Props按惯例传给组件的值称为properties / props而attributes是 DOM 的概念。规则与元素属性一致同样支持{name}简写Widget foo{bar} answer{42} texthello /组件内部如何接收这些值传统export let或 runic 的$props()属于另一主题可参考 props 文档。展开属性Spread Attributes展开属性允许一次性把一组属性或 props 传给元素/组件并且可以与普通属性交错出现。顺序很重要——后出现的属性覆盖先出现的同名项Widget ab {...things} cd /若things.a存在它优先于ab因为展开在ab之后而cd优先于things.c因为cd在展开之后。即同一位置上的后写者胜这一语义对元素和组件同样成立。事件Eventson* 事件属性通过在元素上添加以on开头的属性来监听 DOM 事件。例如监听click事件就给按钮加onclick属性button onclick{() console.log(clicked)}click me/button事件属性是大小写敏感的onclick监听的是click事件而onClick监听的是Click事件——两者是不同的事件。这一设计保证了你可以监听名称中含大写字母的自定义事件例如组件通过createEventDispatcher派发的自定义事件。事件属性也是属性因为事件本质上就是属性所以同样适用属性规则简写button {onclick}click me/button展开button {...thisSpreadContainsEventAttributes}click me/button在时序上事件属性总是在绑定bindings触发的事件之后执行——例如oninput总是在bind:value更新之后触发。底层实现上一部分事件处理器通过addEventListener直接挂到元素上另一部分则通过事件委托处理见下文。触摸事件的 passive 优化使用ontouchstart与ontouchmove事件属性时处理器会以 passive 模式注册从而允许浏览器立即滚动文档而不是等待看事件处理函数是否调用event.preventDefault()大幅提升移动端响应性。从源码看这一行为由 utils.js 中的PASSIVE_EVENTS [touchstart, touchmove]决定源码注释解释了原因这两个事件触发频繁、多发生在性能更弱的移动设备上且默认经委托路径处理因此显式标记为 passive。极少数确实需要preventDefault阻止默认行为的场景应改用从svelte/events导入的on函数例如在 action 内部。事件委托Event Delegation为降低内存占用、提升性能Svelte 对特定事件使用事件委托在应用根部只挂一个监听器由它负责执行事件传播路径上各元素的处理器。以下 23 个事件会走委托beforeinput、click、change、dblclick、contextmenu、focusin、focusout、input、keydown、keyup、mousedown、mousemove、mouseout、mouseover、mouseup、pointerdown、pointermove、pointerout、pointerover、pointerup、touchend、touchmove、touchstart这份清单与 utils.js 中的DELEGATED_EVENTS常量逐条一致并由can_delegate_event()供编译器在分析阶段见 Attribute.js 中的调用判断某个on*属性能否走委托路径。委托模式的两个陷阱手动派发事件如果你dispatchEvent一个使用委托监听器的事件务必设置{ bubbles: true }否则事件到不了应用根部处理器不会执行直接使用addEventListener避免在其中调用stopPropagation否则事件到不了根部、委托处理器不会触发。同时根部手动添加的处理器会在捕获与冒泡两个阶段都先于深层声明式处理器如onclick{...}执行。因此官方建议需要手动挂事件时用从svelte/events导入的on函数而非addEventListener它会保证与声明式处理器的执行顺序正确、并妥善处理stopPropagation。源码走读委托处理器如何工作on函数定义于 internal/client/dom/elements/events.js其 JSDoc 明确说明了它存在的意义Attaches an event handler to an element and returns a function that removes the handler. Using this rather thanaddEventListenerwill preserve the correct order relative to handlers added declaratively (with attributes likeonclick), which use event delegation for performance reasons委托的运行时机制分三步见 events.js注册期delegated(event_name, element, handler)不挂任何监听器而是把处理器按事件名存到元素上的一个event_symbol符号属性中delegate(events)则在根部登记应用关注哪些事件。触发期根部监听器调用 handle_event_propagation它通过event.composedPath()拿到完整传播路径从目标元素起沿路径向上遍历逐个查找element[event_symbol][event_name]并调用遇到event.cancelBubble即停止。一致性保证遍历过程中会临时把event.currentTarget代理为当前路径上的真实目标元素保证委托处理器内event.currentTarget语义与原生监听器一致多个嵌套挂载的应用之间通过event[event_symbol]记录已在何处处理过来避免重复触发。也就是说onclick在编译产物中并不会真的调用addEventListener而是一次在元素上登记 等根部统一分发的操作——这正是文档提示手动dispatchEvent必须bubbles的根本原因。文本表达式Text Expressions花括号内可写任意 JavaScript 表达式{expression}求值结果为null或undefined时会被省略其余值一律转换为字符串。在模板中输出字面量花括号若确实需要在模板里显示{或}使用 HTML 实体lbrace;、lcub;、#123;表示{rbrace;、rcub;、#125;表示}。正则表达式字面量在表达式中使用正则字面量RegExpliteral notation时必须用圆括号包裹避免解析歧义h1Hello {name}!/h1 p{a} {b} {a b}./p div{(/^[A-Za-z ]$/).test(value) ? x : y}/div自动转义与 XSS 防护表达式会被字符串化并转义以防止代码注入XSS。转义逻辑实现在 escaping.js 的escape_html(value, is_attr)中普通文本转义与属性模式额外转义。如果确实需要渲染 HTML使用{html}标签{html potentiallyUnsafeHtmlString}[!NOTE] 务必对传入字符串做转义或只填充你自己完全可控的值否则会造成 XSS 攻击。注释CommentsHTML 注释组件内可直接使用标准 HTML 注释!-- this is a comment! --h1Hello world/h1svelte-ignore以svelte-ignore开头的注释会关闭其后一段标记上的警告通常是可访问性警告。关闭警告务必有充分理由可用的 a11y 警告清单见 a11y.md!-- svelte-ignore a11y_autofocus -- input bind:value{name} autofocus /component 文档注释以component开头的特殊注释会在其他文件中悬停hover该组件名时作为文档提示显示支持 Markdown 和代码块!-- component - You can use markdown here. - You can also use code blocks here. - Usage: html Main nameAretha--Hello, {name}标签内的 JS 风格注释在标签的属性之间还可以写 JavaScript 风格的行注释div // this is a comment! contenteditable="false">【免费下载链接】svelteweb development for the rest of us项目地址: https://gitcode.com/GitHub_Trending/sv/svelte创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考