我最近在整理项目中一些 TailwindCSS 的常用的 HTML 片段,作为 erb partial‘组件’方便复用。在带有多个参数的情况下,默认的 render 方法用起来不是很方便,暂时不想引入 view_component 这类复杂一点的东西,就稍加改进了一下,现在页面中 render 方法用起来更方便了,可以将一些常用的 TailwindCSS HTML 代码复用起来。
Github README: https://github.com/qichunren/view_context#viewcontext
一般情况下,如下面这个 Tab 的 html 模板
# _tab.html.erb
<div class="px-4 flex items-center justify-between border-b-2 border-gray-400">
<ul class="flex px-4">
<!-- slot for tab links -->
<%= yield %>
</ul>
<!-- slot for right button -->
<%= side %>
</div>
使用的时候这样用:
<%= render "shared/tab", side: "<a href='/some' class='btn'></a>".html_safe do %>
<li><a href="/some">Tab 1</a></li>
<li><a href="/some">Tab 2</a></li>
<li><a href="/some">Tab 3</a></li>
<% end %>
这样用起来一点也不方便。现在稍微改进一点,同时没有带来太多复杂性,也没有带来破坏性。
# _tab.html.erb
<% _view_context = ViewContext.new(self) %>
<div class="px-4 flex items-center justify-between border-b-2 border-gray-400">
<ul class="tab px-4">
<%= yield _view_context %>
<%= _view_context.main %>
</ul>
<%= _view_context.secondary %>
</div>
Then, render tab template partial below:
<%= render "shared/tab" do |context| %>
<% context.set_main do %>
<li><a href="/some">Tab 1</a></li>
<li><a href="/some">Tab 2</a></li>
<li><a href="/some">Tab 3</a></li>
<% end %>
<% context.set_secondary do %>
<a href='/settings' class='btn'>Settings</a>
<% end %>
<% end %>
view_context.rb 的代码如下:
class ViewContext
attr_reader :main, :secondary
def initialize(action_view)
@view = action_view
end
def set_main(content = nil, &blk)
@main = if blk
@view.capture do
blk.call
end
else
content
end
nil
end
def set_secondary(content = nil, &blk)
@secondary = if blk
@view.capture do
blk.call
end
else
content
end
nil
end
def method_missing(name, *args, &blk)
m = name.match(/^set_([a-z]\w*)/)
if m
iv = m[1]
if blk
instance_variable_set("@#{iv}", @view.capture { blk.call })
else
instance_variable_set("@#{iv}", args.first)
end
self.class.class_eval { attr_reader iv.to_sym }
else
super
end
end
end
只需要把这个 view_context.rb 文件放在 lib 下,并设置config.eager_load_paths << Rails.root.join("lib")
就可以了。