mcpField
D
datastar

datastar

github.com/maragudk开发49110 次安装31 周前更新
代码仓库

关于 datastar

Datastar 是一种轻量级前端框架,以 HTML 属性驱动响应式界面,结合后端状态更新与前端交互。该技能还介绍 gomponents-datastar,供 Go 应用通过 gomponents 生成 Datastar 属性。

主要功能

  1. 01通过 HTML 属性管理响应式状态
  2. 02绑定文本、表单和动态样式
  3. 03使用事件与修饰符处理交互
  4. 04通过 SSE 更新 DOM 和信号
  5. 05提供 gomponents 的 Go 属性函数

适用场景

  1. 01为服务端渲染页面添加交互
  2. 02构建由后端状态驱动的界面
  3. 03通过 SSE 推送实时页面更新
  4. 04在 Go 项目中用 gomponents 编写 Datastar 属性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/maragudk/skills --skill datastar

安装后在 Claude Code 中输入/datastar确认已加载。

详细介绍

Datastar

概述

Datastar 是一个轻量级前端框架,通过以超媒体为先的方法,让 UI 由后端驱动并具备交互性。它使用标准 HTML data-* 属性,将后端响应式能力(类似 htmx)与前端响应式能力(类似 Alpine.js)结合起来。

何时使用此技能

在以下情况下使用此技能:

  • 为服务器渲染的 HTML 添加前端交互性
  • 构建由后端状态驱动的响应式 UI
  • 在 Go 应用中使用 Datastar 和 gomponents
  • 使用服务器发送事件(SSE)实现实时更新

前置条件: 在 Go 中使用 Datastar 时,还要使用 gomponents 技能了解 HTML 组件模式。

安装

浏览器(CDN)
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/[email protected]/bundles/datastar.js"></script>
Go(gomponents-datastar)
go get maragu.dev/gomponents-datastar

第 1 部分:Datastar 基础知识

核心概念

信号

信号是响应式状态容器。当信号的值发生变化时,所有依赖它的表达式都会自动更新。

<div data-signals="{count: 0}">
    <span data-text="$count"></span>
    <button data-on:click="$count++">Increment</button>
</div>
  • 在表达式中,信号名称以 $ 为前缀
  • 将信号设置为 null 或 undefined 会将其移除
  • 使用点号表示法访问嵌套信号:$user.name
DOM 修补

Datastar 使用形态变换,只更新发生变化的 DOM 部分,同时保留状态。后端发送 HTML 片段,将其修补到现有页面中。

属性参考

状态管理

data-signals - 初始化响应式信号:

<div data-signals="{name: 'World', count: 0}"></div>

data-computed - 创建派生的只读信号:

<div data-computed="{doubled: $count * 2}"></div>

data-init - 在元素加载时运行表达式:

<div data-init="console.log('Loaded')"></div>
数据绑定

data-text - 将文本内容绑定到表达式:

<span data-text="'Hello, ' + $name"></span>

data-bind - 为表单元素提供双向绑定:

<input data-bind="$name" type="text">

data-show - 有条件地显示或隐藏元素:

<div data-show="$isVisible">Only shown when true</div>
样式

data-class - 有条件地应用 CSS 类:

<div data-class="{'active': $isActive, 'error': $hasError}"></div>

data-style - 动态设置内联样式:

<div data-style="{'color': $textColor, 'opacity': $opacity}"></div>

data-attr - 动态设置 HTML 属性:

<button data-attr="{'disabled': $isLoading}">Submit</button>
事件

data-on - 附加事件监听器:

<button data-on:click="$count++">Click me</button>
<input data-on:input="$search = evt.target.value">
<form data-on:submit__prevent="@post('/submit')">

evt 变量引用事件对象。

data-on-intersect - 在元素进入视口时触发:

<div data-on-intersect="@get('/load-more')">Loading...</div>

data-on-interval - 按固定间隔运行:

<div data-on-interval="$elapsed++">Timer: <span data-text="$elapsed"></span></div>

data-on-signal-patch - 在信号更新时执行:

<div data-on-signal-patch="console.log('Signals changed:', patch)"></div>
DOM 控制

data-ref - 创建一个引用 DOM 元素的信号:

<input data-ref="$inputEl" type="text">

data-ignore - 将元素排除在 Datastar 处理之外:

<div data-ignore>Third-party widget here</div>

data-ignore-morph - 保持 Datastar 处于活动状态,但跳过形态变换:

<div data-ignore-morph>Preserve this DOM structure</div>

data-preserve-attr - 在形态变换期间保留属性:

<input data-preserve-attr="value" type="text">
后端操作

@get()、@post()、@put()、@patch()、@delete() - 向后端发送请求:

<button data-on:click="@get('/api/data')">Load</button>
<button data-on:click="@post('/api/submit')">Submit</button>

修饰符

修饰符使用双下划线语法扩展属性行为:

时序修饰符
  • __debounce / __debounce_500ms - 对执行进行防抖
  • __throttle / __throttle_1s - 对执行进行节流
  • __delay / __delay_200ms - 延迟执行
事件修饰符
  • __prevent - 调用 preventDefault()
  • __stop - 调用 stopPropagation()
  • __capture - 使用捕获阶段
  • __passive - 将监听器标记为被动监听器
  • __once - 仅执行一次
  • __self - 仅当目标是元素本身时触发
  • __outside - 在元素外部发生事件时触发
  • __window - 将监听器附加到 window
带修饰符的示例
<input data-on:input__debounce_300ms="@get('/search?q=' + $query)">
<button data-on:click__once="@post('/track-click')">Track</button>
<form data-on:submit__prevent="@post('/submit')">

服务器发送事件(SSE)

Datastar 使用 SSE 流式传输响应。后端发送的事件使用 text/event-stream 内容类型。

SSE 事件类型

datastar-patch-elements - 将 HTML 修补到 DOM 中:

event: datastar-patch-elements
data: elements <div id="content">Updated content</div>

datastar-patch-signals - 更新信号值:

event: datastar-patch-signals
data: signals {count: 42}

datastar-remove-elements - 根据选择器移除元素:

event: datastar-remove-elements
data: selector #old-element

第 2 部分:gomponents-datastar

概述

gomponents-datastar 提供 Go 函数,可将 Datastar 属性生成为 gomponents 节点。它与 gomponents 库无缝集成。

导入约定

使用点导入,获得简洁的 DSL:

import (
    . "maragu.dev/gomponents"
    . "maragu.dev/gomponents/html"
    data "maragu.dev/gomponents-datastar"
)

注意:对于 datastar,建议使用 data 别名。

如需最新的 API 文档,请运行:

go doc maragu.dev/gomponents-datastar

函数参考

状态管理

Signals - 初始化响应式信号:

data.Signals(map[string]any{
    "count": 0,
    "name":  "World",
})

Computed - 创建计算信号(键值对):

data.Computed("doubled", "$count * 2")

Init - 加载时运行表达式:

data.Init("console.log('Component loaded')")
数据绑定

Text - 绑定文本内容:

Span(data.Text("'Hello, ' + $name"))

Bind - 双向表单绑定:

Input(Type("text"), data.Bind("$name"))

Show - 条件显示:

Div(data.Show("$isVisible"), Text("Shown when visible"))
样式

Class - 条件类(键值对):

data.Class("active", "$isActive", "error", "$hasError")

Style - 动态内联样式(键值对):

data.Style("color", "$textColor", "opacity", "$opacity")

Attr - 动态属性(键值对):

data.Attr("disabled", "$isLoading", "aria-busy", "$isLoading")
事件

On - 附加事件监听器:

data.On("click", "$count++")
data.On("click", "@post('/submit')", data.ModifierPrevent)
data.On("input", "$search = evt.target.value", data.ModifierDebounce)

OnIntersect - 视口交叉:

data.OnIntersect("@get('/load-more')")

OnInterval - 定期执行:

data.OnInterval("$elapsed++")

OnSignalPatch - 响应信号变化:

data.OnSignalPatch("console.log('Updated')")
DOM 控制

Ref - 引用 DOM 元素:

data.Ref("$inputEl")

Ignore - 跳过 Datastar 处理:

data.Ignore()

IgnoreMorph - 仅跳过变形:

data.IgnoreMorph()

PreserveAttr - 变形时保留属性:

data.PreserveAttr("value", "checked")
请求辅助函数

Indicator - 显示加载状态:

data.Indicator("$isLoading")

JSONSignals - 控制要发送的信号:

data.JSONSignals(data.Filter{Include: "form.*"})
data.JSONSignals(data.Filter{Exclude: "internal.*"})

修饰符

在事件函数中使用修饰符常量:

// Timing
data.ModifierDebounce  // __debounce
data.ModifierThrottle  // __throttle
data.ModifierDelay     // __delay

// Event behavior
data.ModifierPrevent   // __prevent
data.ModifierStop      // __stop
data.ModifierCapture   // __capture
data.ModifierPassive   // __passive
data.ModifierOnce      // __once
data.ModifierSelf      // __self
data.ModifierOutside   // __outside
data.ModifierWindow    // __window

// Duration/threshold helpers
data.Duration(500 * time.Millisecond)  // __500ms
data.Threshold(0.5)                     // __threshold_0.5

完整示例

package views

import (
    "net/http"

    . "maragu.dev/gomponents"
    . "maragu.dev/gomponents/html"
    ghttp "maragu.dev/gomponents/http"
    ds "maragu.dev/gomponents-datastar"
)

func CounterPage() Node {
    return HTML5(HTML5Props{
        Title:    "Counter",
        Language: "en",
        Head: []Node{
            Script(
                Type("module"),
                Src("https://cdn.jsdelivr.net/gh/starfederation/[email protected]/bundles/datastar.js"),
            ),
        },
        Body: []Node{
            Div(
                data.Signals(map[string]any{"count": 0}),

                H1(data.Text("'Count: ' + $count")),

                Button(
                    data.On("click", "$count++"),
                    Text("Increment"),
                ),

                Button(
                    data.On("click", "$count--"),
                    Text("Decrement"),
                ),

                Button(
                    data.On("click", "@post('/api/save')"),
                    Text("Save to Server"),
                ),
            ),
        },
    })
}

func SearchForm() Node {
    return Form(
        data.Signals(map[string]any{"query": "", "results": []any{}}),
        data.On("submit", "@get('/search?q=' + $query)", data.ModifierPrevent),

        Input(
            Type("text"),
            data.Bind("$query"),
            data.On("input", "@get('/search?q=' + $query)", data.ModifierDebounce, data.Duration(300*time.Millisecond)),
            Placeholder("Search..."),
        ),

        Div(
            ID("results"),
            data.Show("$results.length > 0"),
            data.Text("'Found ' + $results.length + ' results'"),
        ),
    )
}

SSE 处理器模式

func handleSSE(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")

    flusher, ok := w.(http.Flusher)
    if !ok {
        http.Error(w, "SSE not supported", http.StatusInternalServerError)
        return
    }

    // Patch HTML elements
    fmt.Fprintf(w, "event: datastar-patch-elements\n")
    fmt.Fprintf(w, "data: elements <div id=\"content\">Updated!</div>\n\n")
    flusher.Flush()

    // Update signals
    fmt.Fprintf(w, "event: datastar-patch-signals\n")
    fmt.Fprintf(w, "data: signals {\"count\": 42}\n\n")
    flusher.Flush()
}

提示

  1. 信号命名: 在表达式中使用 $ 前缀,在 Go 代码中则不要使用
  2. 避免冲突: Datastar 文本绑定使用 data.Text(),静态内容使用 gomponents 的 Text()
  3. 修饰符: 可链式使用多个修饰符:data.On("click", "...", data.ModifierPrevent, data.ModifierOnce)
  4. SSE ID: 通过 SSE 修补的元素需要匹配的 id 属性
  5. 变形: 默认情况下,Datastar 会在 DOM 更新期间保留表单输入状态

评论

支持 Markdown