Rails使用Hotwire/Turbo实现分页时多Turbo Frame更新问题
turbo_frame_tag 多target支持说明
原生Turbo Frame 不支持配置多个target。Turbo Frame的核心设计逻辑是单次请求仅匹配、替换一个与响应内id完全一致的frame块:
- 链接位于哪个frame内部,默认就只替换当前所在frame,这就是初始场景下点击Next仅重载
#next元素的原因 - 为id为next的frame添加
target: "page"属性后,请求会定向匹配响应内id为page的frame,因此只会替换第一个turbo-frame块,属于框架的预期行为,并非异常。
分页需求的正确实现方案
方案1:合并frame(改造成本最低)
不需要拆分两个独立frame,将页码内容、下一页链接放到同一个turbo_frame内即可,适配现有代码的改动量极小:
修改初始页面代码:
<h1> Title </h1> <%# 将页码展示、下一页按钮统一放入id为pagination的frame %> <%= turbo_frame_tag "pagination" do %> <div id="page"> current page : <%= params[:page] || 1 %> </div> <p> other content </p> <div id="next"> <a href="?page=<%= (params[:page] || 1).to_i + 1 %>"> Next page </a> </div> <% end %>
控制器检测到page参数时,直接返回id为pagination的完整frame块作为局部视图内容即可。点击下一页时整个frame会被整体替换,页码和下一页链接同步更新,不会出现部分刷新的问题。
方案2:使用Turbo Stream做多区域更新(适合多独立区块更新场景)
如果业务上必须拆分两个独立更新区域,不要依赖Frame的target配置,改用Turbo Stream返回多段更新指令即可:
- 为下一页链接添加
data-turbo-stream属性,标记该请求期望返回Stream格式响应:<h1> Title </h1> <%= turbo_frame_tag "page" do %> current page : <%= params[:page] || 1 %> <% end %> <p> other content </p> <%= turbo_frame_tag "next" do %> <a href="?page=<%= (params[:page] || 1).to_i + 1 %>" data-turbo-stream> Next page </a> <% end %> - 控制器检测到page参数时,返回turbo_stream响应,同时替换两个目标区域的内容:
def index if params[:page] next_page = params[:page].to_i + 1 render turbo_stream: [ turbo_stream.replace("page", partial: "shared/page", locals: { current_page: params[:page] }), turbo_stream.replace("next", partial: "shared/next_page", locals: { next_page: next_page }) ] end end - 对应的局部视图不需要额外包裹turbo_frame_tag,直接写入内容即可:
<%# shared/_page.html.erb %> current page : <%= current_page %><%# shared/_next_page.html.erb %> <a href="?page=<%= next_page %>" data-turbo-stream> Next page </a>
该方案不受Frame单target规则限制,可以一次性更新页面上任意多个独立区块。
内容的提问来源于stack exchange,提问作者stani gam
相关产品推荐
相关产品推荐

