写在前面
最近看了几篇关于 htmx 的文章,自己也去看了一眼官网,也去油管看了一下当时 htmx 发布会的时候他们的演示,下面说几点我对这个所谓的新型起来的技术的看法,
他的来源是什么
首先说一下他虽然是一个新型的技术,但是其实他是有点炒冷饭的感觉,他其实是对 jQuery 的 [intercoolerjs](https://intercoolerjs.org/reference.html 进行了一个重写,也就是说在过去intercoolerjs这个玩意就已经可以实现类似 htmx 的效果,就是不需要绑定任何事件,直接就进行标签请求一个地址,将返回的信息直接渲染到对应的页面上,这些功能是他已经存在的,关于intercoolerjs的文章网上也是有很多的,感兴趣的可以自己去看看,引用官方一个 DEMO
<!-- This is the initial UI (which would normally be generated by the userDisplayTemplate below of course) Note that the button targets the outer div which encloses the entire contact UI because that's what we want to replace when the button is clicked. --> <div id="contact-div"> <div><strong>First Name</strong>: Joe</div> <div><strong>Last Name</strong>: Smith</div> <div><strong>Email</strong>: joesmith@example.com</div> <button ic-target="#contact-div" ic-get-from="/contact/1/edit" class="btn btn-default"> Click To Edit </button> </div> <script> //======================================================================== // Mock Server-Side HTTP End Points //======================================================================== $.mockjax({ url: "/contact/1/edit", response: function (settings) { var mockUser = dataStore.findUser("1"); this.responseText = userFormTemplate(mockUser); } }); $.mockjax({ url: "/contact/1", response: function (settings) { var mockUser = dataStore.findUser("1"); var params = parseParams(settings.data); if (params['_method']== 'PUT') { mockUser.firstName = params['firstName']; mockUser.lastName = params['lastName']; mockUser.email = params['email']; } this.responseText = userDisplayTemplate(mockUser); } }); //======================================================================== // Mock Server-Side Templates //======================================================================== function userFormTemplate(mockUser) { // Pretty simple bootstrap form, but note that the form uses an ic-put-to and the cancel button uses // an ic-get-from rather than the usual HTML attributes return '\ <form ic-put-to="/contact/1" ic-target="#contact-div"> \ <div class="form-group"> \ <label>First Name</label> \ <input type="text" class="form-control" name="firstName" value="' + mockUser.firstName + '"> \ </div> \ <div class="form-group"> \ <label>Last Name</label> \ <input type="text" class="form-control" name="lastName" value="' + mockUser.lastName + '"> \ </div> \ <div class="form-group"> \ <label>Email address</label> \ <input type="email" class="form-control" name="email" value="' + mockUser.email + '"> \ </div> \ <button class="btn btn-default">Submit</button> \ <button ic-get-from="/contact/1" ic-target="#contact-div" class="btn btn-danger">Cancel</button> \ </form>'; } function userDisplayTemplate(mockUser) { return '\ <div><strong>First Name</strong>: ' + mockUser.firstName + '</div> \ <div><strong>Last Name</strong>: ' + mockUser.lastName + '</div> \ <div><strong>Email</strong>: ' + mockUser.email + '</div> \ <button ic-target="#contact-div" ic-get-from="/contact/1/edit" class="btn btn-default"> \ Click To Edit \ </button>'; } //======================================================================== // Mock Data Store //======================================================================== var dataStore = (function() { var mockUser = { "firstName": "Joe", "lastName": "Smith", "email": "joesmith@example.com" }; return { findUser : function(id) { return mockUser } } })() </script>
他能做什么
说了这些也没有正式的演示过它可以做什么,它可以做的事情是直接在 html 标签上写一些 js 才可以做的东西,他的目的就是去 js 化,尽可能的少写或者不写 js 代码,因为我们知道,浏览器其实只认识 html 代码,他编译 html 代码是具有先天优势的,那么也就是说如果我们的代码中只有 html 代码那么理论上上渲染速度是很快的,但是他依赖于服务器,也就是我们前端之前的 js 代码其实没有消失,只是放到了 server 端执行了,通过上面的代码也是可以看出来的,所以它可以做的事情就是在什么标签上发送什么请求,请求返回的内容他来指定放到哪里,同时中间和用户的一个交互和反馈怎么设计,他就做这些,也仅仅做这些即可!
演示一下?
-
我自己也试了一下他的功能,使用起来是比较简单的,可以像使用 jQuery 一样的方式直接引入 CDN 或者是 npm i 安装也是可以的,那么之后我们就可以直接在 html 中使用他的语法了
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>测试 htmx 的用法</title> <script src="./js/htmx@1.9.5htmx.min.js" integrity="sha384-xcuj3WpfgjlKF+FXhSQFQ0ZNr39ln+hwjN3npfM9VBnUskLolQAcN80McRIVOPuO" crossorigin="anonymous"></script> </head> <body> <script type="text/javascript"> // const baseGetRequest = 'http://jsonplaceholder.typicode.com/users' // window.baseGet = baseGetRequest </script> <!-- 测试基础的 get 请求 --> <div hx-get="http://jsonplaceholder.typicode.com/users"> Put To Messages </div> <!-- 测试基础的 post 请求 并将请求的结果给到另一个 span 的元素上 --> <div hx-post="http://jsonplaceholder.typicode.com/posts/1/comments" hx-target='#aimDiv'>测试一条数据</div> <span id="aimDiv"></span> <!-- 模拟一个对话框的请求 --> <button hx-get="http://jsonplaceholder.typicode.com/users" hx-confirm="Are you sure you wish to delete your account?"> Delete My Account </button> <!-- 测试一个 boost 的请求 --> <div hx-boost="true"> <a href="http://jsonplaceholder.typicode.com/users">Blog</a> </div> <!-- 测试一个表单 --> <div id="search-results"></div> <form action="/search" method="POST"> <input class="form-control" type="search" name="search" placeholder="Begin typing to search users..." hx-post="http://jsonplaceholder.typicode.com/posts/1/comments" hx-trigger="keyup changed delay:500ms, search" hx-target="#search-results" hx-indicator=".htmx-indicator"> </form> <!-- 测试 table --> <input class="form-control" type="search" name="search" placeholder="Begin Typing To Search Users..." hx-post="http://jsonplaceholder.typicode.com/posts/1/comments" hx-trigger="keyup changed delay:500ms, search" hx-target="#search-results" hx-indicator=".htmx-indicator"> <table class="table"> <thead> <tr> <th>First Name</th> <th>Last Name</th> <th>Email</th> </tr> </thead> <tbody id="search-results"> </tbody> </table> </body> </html>
如果里面的标签不太明白可以看一下他的官网介绍,htmx 官网虽然是英文的,但是写的还是很清晰的,一般都是可以看得懂的,
- 上面那段代码执行结果如图:
当然不用看样式,我只是试用了一下,会发现我点击 put to message 的时候 右侧直接进行了发送请求,一会之后他就直接返回了对应的内容,同时帮我渲染上去了,但是我的数据格式是 json 的,所以就显的比较不合理,大家可以忽略,因为我只是演示一下他是可以正常返回渲染的
它提供了哪些便利
- 请求不需要封装函数
- 防抖节流直接通过属性进行配置
- 请求方式直接通过属性进行配置
- 回参渲染到某个元素可以指定
- 指定的方式很多(css 选择器、元素选择器等)
- 局部内容替换成本很低
- 前端代码量极少
- 浏览器渲染速度很快
他有哪些劣势
- 项目体量不可以过大,这样对服务器的压力太大
- 过于复杂的操作不太可行,毕竟他都是通过配置的,配置就意味着定制化的需求满足程度不会太高
- 过于依赖服务器,前端只是进行配置
- 对Django的依赖也比较大,因为他就是配合他用的(这里我也问了一下我身边使用Django的朋友,他给的回复是:jango 内置了 web 开发工具,可以用 {} 直接获取 response 对象属性。在前后端不分离年代还是挺厉害。现在不行了)
个人推荐程度,我想说几句
可以用,可以学,但是因为适用场景不太多,所以了解即可,当有对应的业务出现的时候可以使用即可!个人还是推荐使用像 vue、react 等相对全面的框架,他是不挑场景的,几乎所有的web应用他都是可以胜任的,技术发展好不容易发展到前后分离的一个阶段,现在又想回去,不是不行,是不强烈推荐,前后端分离的好处我这里不做赘述,开发几年的人都可以体会的到。
这里吐槽一句,在中国做开发是一件很痛苦的事情,因为最新的技术一般都是国外传过来的,另外技术文档第一份都是英文的,很少有中文的,即使后面翻译之后也是不准确的,我们使用着不准确的文档用着国外人开发的语言进行使用,还可以用的很好就已经是一件很了不起的事情了,但是不代表无脑跟风就是对的,比如这个 htmx,我们明明知道他是一个炒冷饭的东西,但是奈何还是有很多人大肆的无脑宣传,只讲好的,不讲坏的,好像只要紧跟国外的脚步就一定是最新的技术,这里我是不赞成的,对技术的探索是好的,但是重复造轮子,轮子出来起个名字就按照新东西学习,除了徒增学习成本之外我想不到什么好的理由,希望这种情况以后可以少发生或者不发生,我对 htmx 没有恶意,我觉得他确实解决了一部分的应用场景,人家发布会的时候也是说了如果你的应用是需要这种场景的,我是推荐你用的,但是复杂的一些我们是不推荐的,你可以继续使用你认为好的技术栈 即可,但是传到国内就变成了了不起的新技术,对此我是无力吐槽的!但是学习本身这件事是没错的,因为只有你对所有的不同的技术栈都了解了一些,才更有可能融会贯通,技术的广度和深度都是很重要的,深度有助于研究出来新东西,广度有助于你识别技术本身的局限性和适用性,废话太多了,你们也看烦了,结束结束。
写在后面
看完这篇文章可能你们也感觉到了,这篇文章其实并没有过多的代码演示,只是说了一下他的基础用法和适用场景,因为我觉得和这个东西他本身就是解决了一部分前端的痛点,并不可以解决真正的问题,他其实就是解决了一些小而美的应用不用使用 vue 或者 react 等相对来说讲比较重的框架,毕竟配置一套前端的项目架子还是需要一点技术水平的,那么这里 htmx 就可以派上用场, 当然前期是你的后端足够支持你们返回对应的 html 代码