最被低估的Rails辅助工具:dom_id

172 阅读3分钟

这篇文章是Hotwire Summer的一部分:Boring Rails的新一季内容!

Rails中的dom_id 帮助器已有十多年历史,但在Hotwire中被证明是一个非常有价值的概念。

这个秘密的主力军为Rails中各种与HTML相关的行为提供动力。它有一项关键工作:使应用程序数据与DOM元素的关联变得容易。

dom_id 它需要两个参数:一个记录和一个可选的前缀。

record 可以是任何响应to_keymodel_name 的东西,但99%的情况下,你会传递给它一个 ActiveRecord 模型。prefix 可以是任何响应to_s 的东西,但99%的情况下它是一个符号。

来自文档

dom_id(Post.find(45))       # => "post_45"
dom_id(Post.new)            # => "new_post"

dom_id(Post.find(45), :edit) # => "edit_post_45"
dom_id(Post.new, :custom)    # => "custom_post"

这个助手之所以这么好,是因为它设定了一个惯例。Rails提供了一个标准,而不是定义你自己的标识方式,然后希望你记住这个模式;你不需要切换上下文来知道你是否将一个id设置为 "post_23_comments "或 "comments-post-23",或者等等,是 "post_23-comments"?

通过为你的元素提供稳定的id值,你可以避免脆弱的代码,比如针对第一个元素的孩子或根据文本值找到一个节点。

以下是在构建Hotwire应用程序时,你应该经常接触的地方dom_id

超级简洁的标签构建器

将HTML标记作为真理的来源意味着在渲染模板时要添加额外的属性和条件。虽然你可以在ERB模板中进行普通的字符串插值,但Rails有一套漂亮的标签生成器,可以帮助你避免淹没在大括号、小括号和八边形的海洋中。

<%= tag.div id: dom_id(@post, :comments), class: "flex flex-col divide-y" do %>
  <%= render @post.comments %>
<% end %>

当你更多地使用这些辅助工具时,请确保你查看这些提示。

深度链接锚点标签

由于Rails非常倚重本地浏览器的功能,所以要确保你利用链接上的锚定标签。你可以使用dom_id ,让浏览器直接滚动到具有相应id 的元素(或者生成一个用户可以分享的固定链接)。

<%= link_to "View comment", posts_path(@post, anchor: dom_id(@comment)) %>

你也可以使用这种模式进行重定向。例如,在一个列表中创建一个项目后,你可以重定向到索引页,但滚动到新的项目。

class CommentsController < ApplicationController
  def create
    @post.comments.create!(comment_params)

    redirect_to posts_path(@post, anchor: dom_id(@comment))
  end
end

还有一些与深度链接有关的提示。

  • 你可以使用:target 伪类,用一个与URL锚匹配的ID来设计元素。在Tailwind中,只需使用目标前缀(例如:target:bg-yellow-50 ,当元素与URL锚匹配时,为其添加一个微妙的黄色背景)
  • 另一个方便的CSS属性是scroll-margin-top :浏览器将把目标元素一直滚动到窗口的顶部。你可能想要一点额外的填充,但只有当你滚动到该元素时才需要。不要在你的设计中添加额外的边距或填充,也不要添加奇怪的包装div......scroll-margin-top (Tailwind class:scroll-mt )就是答案。

使用Turbo Frames

当你开始在你的应用程序中添加Turbo Frames时,你需要为框架标签提供一个id。Railsturbo_frame_tag 使用 - 你猜对了 -dom_id 在引擎盖下。但你也可以传入你自己的id。

turbo_frame_tag @post # => <turbo-frame id="post_123"></turbo-frame>
turbo_frame_tag dom_id(@post, :comments) # => <turbo-frame id="comments_post_123"></turbo-frame>

由于Turbo Frame需要在每个页面上都是唯一的,所以dom_id 是一种生成框架id的方便方法,特别是当你在页面上有多个框架时。

而且,由于你可以通过其他链接来浏览一个框架,这是一个很好的约定。

<%= turbo_frame_tag @comment, src: comment_path(@comment) %>

<!-- Elsewhere... -->
<%= link_to "Edit", edit_comment_path(@comment), data: { turbo_frame: @comment } %>

对Turbo Stream响应进行范围界定

用Turbo Streams在页面上做一些小的突变是非常强大的,但是由于你的流动作是在一个单独的turbo_stream.erb 文件中,所以在不同的视图中匹配你的id是很困难的。

再一次,dom_id 可以保持一致性。

<!-- app/views/plans/quick_edit/update.turbo_stream.erb -->
<%= turbo_stream.replace dom_id(@plan, :title), partial: "plans/title" %>
<%= turbo_stream.replace dom_id(@plan, :notes), partial: "plans/notes" %>
<%= turbo_stream.replace dom_id(@plan, :assigned), partial: "plans/assigned" %>

通过在你的标记中添加正确的ID,Turbo Stream的响应是非常干净的。

<!-- app/views/comments/destroy.turbo_stream.erb -->
<!-- Calls `dom_id(@comment)` under the hood -->
<%= turbo_stream.remove @comment %>

收尾工作

谁能想到,从你的应用程序模型中生成HTMLid 值的简单助手会是一个如此有用的概念,以至于在首次引入十多年后,它仍然被证明是有用的,甚至在Rails的最新和最闪亮的部分。

如果你以前没有使用过dom_id ,那么下次在你的Rails应用中编写视图时,可以考虑一下。你可能会惊讶地发现,当你不在HTML上乱写乱画时,创建HTML的过程是多么的愉快。

<div id='<%= "#{@post.id}-comments" %>'>
</div>