Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

สร้างการนำทางย่อยโดยอัตโนมัติจาก H2s ใน Jekyll

สร้างการนำทางย่อยโดยอัตโนมัติจาก H2s ใน Jekyll

ฉันกำลังสร้างไซต์เอกสารของเราขึ้นใหม่โดยใช้ Jekyll เนื่องจากหน้าเอกสารของเราค่อนข้างใหญ่ เราจึงต้องมีการนำทางย่อยบางประเภทนอกเหนือจากการนำทางระดับบนสุด

ในโพสต์นี้ เราจะพูดถึงวิธีสร้างปลั๊กอิน Jekyll แบบง่ายๆ ที่สามารถสร้างลิงก์การนำทางย่อยจากส่วนหัวในโพสต์หรือหน้าของคุณ

ภาพรวม

ฉันได้แบ่งโปรเจ็กต์นี้เป็นงานต่อไปนี้:

  1. สร้างตัวสร้าง Jekyll ซึ่งทำงานกับทุกหน้าในไซต์
  2. สอนตัวสร้างวิธีการแสดงหน้าล่วงหน้าเพื่อให้สามารถดึงข้อมูลส่วนหัวได้
  3. ใช้ nokogiri เพื่อแยกวิเคราะห์หน้า HTML แยกส่วนหัวและเนื้อหาที่เกี่ยวข้อง
  4. แสดงการนำทางย่อย

ในตัวอย่างด้านล่าง ลิงก์การนำทางย่อยทั้งหมดเป็นลิงก์สมอ เพื่อให้วิธีนี้ใช้งานได้ คุณจะต้องแน่ใจว่าตัวประมวลผล markdown ของคุณสร้าง ID สำหรับส่วนหัว RedCarpet กับ with_toc_data ตัวเลือกใช้งานได้ดี

ตัวสร้าง Jekyll พื้นฐาน

มีปลั๊กอินสองสามประเภทที่คุณสามารถสร้างสำหรับ Jekyll ได้ เรากำลังจะสร้างเครื่องกำเนิดไฟฟ้า

ตัวสร้างเป็นเพียงคลาสที่สืบทอดมาจาก Jekyll::Generator และมีวิธีที่เรียกว่า generate .

ตัวสร้างจะทำงานหลังจาก Jekyll โหลดไฟล์ markdown ทั้งหมด แต่ก่อนที่ไฟล์เหล่านั้นจะถูกแปลงเป็น HTML site ออบเจ็กต์ถูกส่งผ่านไปยังวิธีสร้าง และคุณสามารถใช้ออบเจ็กต์ไซต์เพื่อเข้าถึงหน้าไซต์ โพสต์ และแหล่งข้อมูลอื่นๆ ทั้งหมดของคุณ

ในตัวอย่างด้านล่าง เราสร้างตัวสร้างที่วนซ้ำทุกหน้าและพิมพ์ชื่อออกมา

class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    site.pages.each do |page|
      puts page.data["title"]
    end
  end
end

นอกจากนี้เรายังสามารถแก้ไขข้อมูลหน้าและไซต์ภายในเครื่องกำเนิดไฟฟ้า -- ข้อมูลที่โหลดจากส่วนหน้าและจากไฟล์การกำหนดค่าเว็บไซต์

   page.data["title"] += " - modified!"
   site.data["tagline"]

การมาร์กดาวน์ล่วงหน้าเป็น HTML

เราต้องการแยกหัวเรื่องออกจากเอกสารการลดราคาของเรา วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการแปลง markdown เป็น HTML จากนั้นแยกวิเคราะห์ HTML โดยใช้เครื่องมือเช่น nokogiri

สิ่งนี้ทำให้ฉันรู้สึกสกปรกเล็กน้อยหรือไม่? ใช่. มันจะช้าไปหน่อยมั้ย? อย่างแน่นอน. แต่เนื่องจาก Jekyll เป็นเครื่องมือสร้างไซต์แบบสแตติก ฉันจึงไม่ต้องกังวลเกี่ยวกับประสิทธิภาพแบบเรียลไทม์ ฉันก็เลยเอาจมูกมาปิดไว้

ที่นี่ เราใช้ตัวตัดมาร์กดาวน์ในตัวของ Jekyll เพื่อแปลงทุกหน้ามาร์กดาวน์เป็น HTML

class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    parser = Jekyll::Converters::Markdown.new(site.config)

    site.pages.each do |page|
      if page.ext == ".md"
        html = parser.convert(page['content'])
        # Do something with the html here
      end
    end
  end
end

การแยกส่วนหัว

สำหรับไซต์เอกสารใหม่ของเรา ฉันตัดสินใจว่าทุกแท็ก H2 ควรมีลิงก์การนำทางย่อยที่สอดคล้องกัน ดังนั้นฉันจะใช้ nokogiri เพื่อแยกวิเคราะห์ HTML ของแต่ละหน้า จากนั้นฉันจะดึงแท็ก H2 ออกจากหน้า

สำหรับตอนนี้ เราจะพิมพ์เนื้อหาและรหัสของ H2 ไปที่หน้าจอ:

require "nokogiri"

class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    parser = Jekyll::Converters::Markdown.new(site.config)

    site.pages.each do |page|
      if page.ext == ".md"
        doc = Nokogiri::HTML(parser.convert(page['content']))
        doc.css('h2').each do |heading|
          puts "#{ heading.text }: #{ heading['id'] }"
        end
      end
    end
  end
end

การสร้างเมนูการนำทางย่อย

ตอนนี้เรามีข้อความส่วนหัวและรหัสแล้ว เราจึงสามารถสร้างรายการลิงก์การนำทางย่อยได้

เราจะจัดเก็บรายการลิงก์นี้เป็นแอตทริบิวต์ข้อมูลของหน้านั้นเอง ด้วยวิธีนี้ เราสามารถเข้าถึงลิงก์จากเทมเพลตหน้าเว็บของเราได้

require "nokogiri"

class MySubnavGenerator < Jekyll::Generator
  def generate(site)
    parser = Jekyll::Converters::Markdown.new(site.config)

    site.pages.each do |page|
      if page.ext == ".md"
        doc = Nokogiri::HTML(parser.convert(page['content']))
        page.data["subnav"] = []
        doc.css('h2').each do |heading|
          page.data["subnav"] << { "title" => heading.text, "url" => [page.url, heading['id']].join("#") }
        end
      end
    end
  end
end

ในเทมเพลตของคุณ คุณสามารถวนซ้ำผ่านการนำทางย่อยและแสดงแต่ละลิงก์:

{% for item in page.subnav %}
  <a href="{{ item.url }}">{{ item.title }}</a>
{% endfor %}

การแก้ไขปัญหา

อย่างที่ฉันได้กล่าวไว้ก่อนหน้านี้ ทั้งหมดนี้ขึ้นอยู่กับตัวประมวลผล markdown ของคุณที่สร้าง ID เฉพาะสำหรับแต่ละหัวข้อ นี่คือการตั้งค่า markdown ของฉันจาก _config.yml :

# Use the redcarpet Markdown renderer
markdown: redcarpet
redcarpet:
    extensions: [
        'no_intra_emphasis',
        'fenced_code_blocks',
        'autolink',
        'strikethrough',
        'superscript',
        'with_toc_data',
        'tables',
        'hardwrap'
    ]

ถัดไป...

วิธีการข้างต้นใช้ได้ดีหากคุณต้องการการนำทางย่อยเพียงระดับเดียวเท่านั้น แต่ถ้าคุณต้องการมากกว่านี้ล่ะ? เช่น หากคุณต้องการให้แท็ก H3 ทั้งหมด "อยู่ภายใน" ของ H2 เพื่อสร้างลิงก์การนำทางย่อยในเมนูของคุณ

เราจะกล่าวถึงสิ่งนั้นและอื่น ๆ ในโพสต์บล็อกในอนาคต คอยติดตาม!