我有一个格式如下的页面:
<h1>Header</h1>
<h2>Subheader</h2>
<h3>Subsubheader</h3>
<h1>Another header</h1>
是否可以像维基百科在其文章中所做的那样,在页面的开头在服务器端生成目录/大纲?我使用 Ruby on Rails。
编辑:没有 JavaScript!
我有一个格式如下的页面:
<h1>Header</h1>
<h2>Subheader</h2>
<h3>Subsubheader</h3>
<h1>Another header</h1>
是否可以像维基百科在其文章中所做的那样,在页面的开头在服务器端生成目录/大纲?我使用 Ruby on Rails。
编辑:没有 JavaScript!
我今天为此创建了一个类。它取决于http://www.nokogiri.org/,但该 gem 已经随 Rails 一起提供了。
把这个放在app/models/toc.rb
:
class Toc
attr_accessor :html
TOC_CLASS = "toc".freeze
TOC_ELEMENT = "p".freeze
TOC_ITEMS = "h1 | h2 | h3 | h4 | h5".freeze
UNIQUEABLE_ELEMENTS = "h1 | h2 | h3 | h4 | h5 | p".freeze
def initialize(content)
@html = Nokogiri::HTML.fragment content
end
def generate
clear
set_uniq_ids
toc = create_container
html.xpath(TOC_ITEMS).each { |node| toc << toc_item_tag(node) }
html.prepend_child toc
return html.to_s
end
private
def clear
html.search(".#{TOC_CLASS}").remove
end
def set_uniq_ids
html.xpath(UNIQUEABLE_ELEMENTS).
each { |node| node["id"] = rand_id }
end
def rand_id
(0...8).map { ('a'..'z').to_a[rand(26)] }.join
end
def create_container
toc = Nokogiri::XML::Node.new TOC_ELEMENT, html
toc["class"] = TOC_CLASS
return toc
end
def toc_item_tag(node)
"<a data-turbolinks='false' class=\"toc-link toc-link-#{node.name}\" href=\"##{node["id"]}\">#{node.text}</a>"
end
end
像这样使用它
toc = Toc.new article.body
body_with_toc = toc.generate
article.update body: body_with_toc
你需要从你的层次结构中生成数据源是这样的
@toc = [ ['header', 0], ['subheader', 1], ['subsubheader', 2],
['header2', 0], ['header3', 0], ['subheader2', 1]
]
比在模板中渲染它更容易,例如:
<%- @toc.each do |item, distance| %>
<%= (' ' * distance * 5).html_safe %>
<%= item %>
<br/>
<%- end %>
会给你:
header
subheader
subsubheader
header2
header3
subheader2
当然,您可以使用“距离”来确定样式大小而不是“深度”,但我希望您能理解主要思想。
是的,有可能。你真的不需要轨道;您还可以使用 javascript 生成目录。这是您可以使用的示例库。 http://www.kryogenix.org/code/browser/generated-toc/
您也可以在遍历 rails erb/haml 视图中的元素时创建锚链接。