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") // 监听端口
}
打赏