(摘) Htmx浅看

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

Htmx用于 HTML 的高性能工具. htmx 允许您访问 AJAX、CSS 转换 、WebSockets 和服务器发送事件 直接在 HTML 中使用属性 ,因此您可以构建 现代用户界面 ,具有简单性和 超文本的力量
htmx 很小(~14k min.gz’d), 无依赖性, 与 React 相比,可扩展且代码库大小减少了 67%

  <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.7/dist/htmx.min.js"></script>
  <!-- have a button POST a click via AJAX -->
  <button hx-post="/clicked" hx-swap="outerHTML">
    Click Me
  </button>

简单看了一下,好象还是值得一试的.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="/js/htmx.min.js"></script>
    <title>简单的H5页面</title>
</head>
<body>
    <p>学习HTMX https://htmx.org/docs</p>
    <button hx-put="/messages">点击事件</button>
    <hr>

    <div hx-post="/mouse_entered" hx-trigger="mouseenter">
        [鼠标移动到此,自动post到url]
    </div>    
    <hr>

    <h3>如果输入已更改,此输入将在 key up 事件后 500 毫秒发出请求,并将结果插入 id 为 search-results 的 div 中</h3>
    <input type="text" name="q"
        hx-get="/trigger_delay"
        hx-trigger="keyup changed delay:500ms"
        hx-target="#search-results"
        placeholder="Search...">
    <div id="search-results"></div>    
    <hr>

    <h3>仅在按住 Control 键并单击元素时触发的示例(使用方括号来应用触发器过滤器)</h3>
    <div hx-get="/clicked" hx-trigger="click[ctrlKey]">
        按Ctrl键,然后点击
    </div>    
    <hr>

    <h3>每 2 秒向 /news 发出 GET 并将响应加载到 div 中 <br/>
        如果要停止从服务器响应轮询,可以使用 HTTP 响应代码 286 进行响应 并且该元素将取消轮询。
    </h3>
    <div hx-get="/news" hx-trigger="every 2s"></div>
    <hr>

    <h3>负载轮询 ??</h3>
    <div hx-get="/load" hx-trigger="load delay:1s" hx-swap="outerHTML"></div>
    <hr>

    <h3>载入时显示,完成后隐藏</h3>
    <button hx-get="/click">
        Click Me!
        <img class="htmx-indicator" src="/images/spinner.gif">
    </button>
    <hr>
    
    <h3>hx-target加载到发出请求的元素以外的其他元素</h3>
    <input type="text" name="q"
        hx-get="/trigger_delay"
        hx-trigger="keyup delay:500ms changed"
        hx-target="#search-results"
        placeholder="Search...">
    <div id="search-results"></div>    
    <hr>

    <h3>操作确认</h3>
    <button hx-delete="/account" hx-confirm="确认进行此操作?">
        Delete My Account
    </button>    
    <hr>

    <h3>属性继承</h3>
    <div hx-confirm="确认进行此操作?">
        <button hx-delete="/account">
            Delete My Account
        </button>
        <button hx-put="/account">
            Update My Account
        </button>
    </div>    
    <hr>

    <h3>不进行属性继承</h3>
    <div hx-confirm="Are you sure?">
        <button hx-delete="/account">
            Delete My Account
        </button>
        <button hx-put="/account">
            Update My Account
        </button>
        <button hx-confirm="unset" hx-get="/">
            Cancel
        </button>
    </div>
    <hr>
    
    <h3>向 /blog 发出 AJAX GET 请求,并将响应交换到 body 标记中</h3>
    <div hx-boost="true">
        <a href="/blog">Blog</a>
    </div>
    <hr>

    <h3>Requests & Responses  请求和响应</h3>
    <code>
        默认情况下,可以返回 204 - No Content 响应代码,htmx 将忽略响应的内容<br>
        如果服务器出现错误响应(例如 404 或 501),htmx 将触发 htmx:responseError 事件<br>
        如果出现连接错误,将触发 htmx:sendError 事件<br>
    </code>

    <h3>Request Headers  请求标头</h3>
    <code>
        htmx 在请求中添加了一些自己的header <br>
        HX-Boosted: 表示请求是通过使用 hx-boost 的元素进行的 <br>
        HX-Current-URL: 浏览器的当前 URL
        HX-Target: 目标元素的 ID(如果存在)<br>
        HX-Trigger-Name: 触发元素的名称 (如果存在)<br>
        HX-Trigger: 触发元素的 ID(如果存在)
    </code>

    <h3>验证示例</h3>
    <form id="example-form" hx-post="/test">
        <input name="example"
            onkeyup="this.setCustomValidity('') // reset the validation on keyup"
            hx-on:htmx:validation:validate="if(this.value != 'foo') {
                        this.setCustomValidity('Please enter the value foo') // set the validation error
                        htmx.find('#example-form').reportValidity()          // report the issue
                    }">
    </form>    

    <h3>点击事件</h3>
    <button hx-on:click="alert('You clicked me!')">
    Click Me!
    </button>

    <h3>htmx.onLoad</h3>
    <code>
        htmx.onLoad(function(content) {
            var sortables = content.querySelectorAll(".sortable");
            for (var i = 0; i < sortables.length; i++) {
                var sortable = sortables[i];
                new Sortable(sortable, {
                    animation: 150,
                    ghostClass: 'blue-background-class'
                });
            }
        })        
    </code>

    <h3>hx-history: false</h3>
    禁止保存在缓存中

</button>
</body>
</html>

再写个web服务端

package main

import (
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	// 静态文件服务
	r.Static("/html", "./html")     // 所有html文件放到/html目录
	r.Static("/images", "./images") // 所有图片放到/images目录
	r.Static("/js", "./js")

	// 首页重定向到 1.html
	r.GET("/", func(c *gin.Context) {
		c.Redirect(http.StatusFound, "/html/1.html")
	})

	// /messages PUT 请求
	r.PUT("/messages", func(c *gin.Context) {
		c.String(http.StatusOK, "按钮已点击,收到PUT请求!")
	})

	// /mouse_entered POST 请求
	r.POST("/mouse_entered", func(c *gin.Context) {
		c.String(http.StatusOK, "鼠标已移入,收到POST请求!")
	})

	// /trigger_delay GET 请求,返回搜索结果
	r.GET("/trigger_delay", func(c *gin.Context) {
		q := c.Query("q")
		if q == "" {
			c.String(http.StatusOK, "请输入搜索内容")
		} else {
			c.String(http.StatusOK, "你搜索了: %s", q)
		}
	})

	// /clicked GET 请求
	r.GET("/clicked", func(c *gin.Context) {
		headers := ""
		for k, v := range c.Request.Header {
			headers += k + ": " + v[0] + "<br>"
		}
		// c.String(http.StatusOK, "Ctrl+点击事件已触发!")
		c.String(http.StatusOK, "Ctrl+点击事件已触发!<br>请求Header如下:<br>%s", headers)
	})

	// /news GET 请求,模拟新闻轮询
	r.GET("/news", func(c *gin.Context) {
		// 你可以根据实际情况返回 286 状态码来停止轮询
		c.String(http.StatusOK, "最新新闻时间: %s", time.Now().Format("15:04:05"))
	})

	// /load GET 请求,负载轮询
	r.GET("/load", func(c *gin.Context) {
		c.String(http.StatusOK, "<div>页面已加载,收到GET请求!</div>")
	})

	// /click GET 请求
	r.GET("/click", func(c *gin.Context) {
		c.String(http.StatusOK, "按钮Click Me!已点击")
	})

	r.GET("/blog", func(c *gin.Context) {
		c.String(http.StatusOK, "欢迎访问我的博客!")
	})

	r.Run(":80") // 监听端口
}