การสร้างไลบรารีรูปแบบด้วย Shadow DOM ใน Markdown
เผยแพร่แล้ว: 2022-03-10เวิร์กโฟลว์ทั่วไปของฉันที่ใช้โปรแกรมประมวลผลคำบนเดสก์ท็อปมีลักษณะดังนี้:
- เลือกข้อความที่ฉันต้องการคัดลอกไปยังส่วนอื่นของเอกสาร
- โปรดทราบว่าแอปพลิเคชันได้เลือกมากกว่าหรือน้อยกว่าที่ฉันบอกไปเล็กน้อย
- ลองอีกครั้ง.
- ยอมแพ้และแก้ไขเพื่อเพิ่มส่วนที่ขาดหายไป (หรือลบส่วนพิเศษ) ของการเลือกของฉันในภายหลัง
- คัดลอกและวางส่วนที่เลือก
- โปรดทราบว่าการจัดรูปแบบของข้อความที่วางจะแตกต่างจากต้นฉบับ
- พยายามค้นหาการตั้งค่าสไตล์ที่ตรงกับข้อความต้นฉบับ
- ลองใช้พรีเซ็ต
- เลิกใช้ตระกูลฟอนต์และขนาดด้วยตนเอง
- โปรดทราบว่ามีช่องว่างเหนือข้อความที่วางมากเกินไป และกด "Backspace" เพื่อปิดช่องว่าง
- โปรดทราบว่าข้อความที่เป็นปัญหาได้ยกระดับตัวเองหลายบรรทัดพร้อมกัน รวมข้อความส่วนหัวด้านบนและใช้การจัดรูปแบบ
- ไตร่ตรองถึงความตายของฉัน
เมื่อเขียนเอกสารทางเทคนิคเกี่ยวกับเว็บ (อ่าน: ไลบรารีรูปแบบ) โปรแกรมประมวลผลคำไม่ใช่แค่ไม่เชื่อฟัง แต่ไม่เหมาะสม ตามหลักการแล้ว ฉันต้องการโหมดการเขียนที่ช่วยให้ฉันสามารถรวมส่วนประกอบที่ฉันจัดทำเอกสารแบบอินไลน์ได้ และไม่สามารถทำได้เว้นแต่เอกสารประกอบเองจะประกอบด้วย HTML, CSS และ JavaScript ในบทความนี้ ฉันจะแบ่งปันวิธีการรวมการสาธิตโค้ดใน Markdown อย่างง่ายดาย โดยใช้รหัสย่อและการห่อหุ้ม Shadow DOM
CSS และ Markdown
พูดในสิ่งที่คุณต้องการเกี่ยวกับ CSS แต่แน่นอนว่าเป็นเครื่องมือเรียงพิมพ์ที่สม่ำเสมอและเชื่อถือได้มากกว่าโปรแกรมแก้ไข WYSIWYG หรือโปรแกรมประมวลผลคำในตลาด ทำไม? เนื่องจากไม่มีอัลกอริธึมกล่องดำระดับสูงที่พยายามเดาว่าคุณ ตั้งใจ จะไปที่สไตล์ไหน แต่มีความชัดเจนมาก: คุณกำหนดว่าองค์ประกอบใดใช้รูปแบบใดในสถานการณ์ใด และเป็นไปตามกฎเหล่านั้น
ปัญหาเดียวของ CSS คือคุณต้องเขียน HTML ที่เป็นคู่กัน แม้แต่ผู้ชื่นชอบ HTML ที่ดีก็มักจะยอมรับว่าการเขียนด้วยตนเองนั้นยากลำบากเมื่อคุณต้องการสร้างเนื้อหาร้อยแก้ว นี่คือที่มาของ Markdown ด้วยรูปแบบการเขียนที่สั้นและชุดคุณสมบัติที่ลดลง ทำให้มีโหมดการเขียนที่เรียนรู้ได้ง่ายแต่ยังคงสามารถ — เมื่อแปลงเป็น HTML โดยทางโปรแกรม — ใช้ประโยชน์จากคุณสมบัติการเรียงพิมพ์ที่มีประสิทธิภาพและคาดการณ์ได้ของ CSS มีเหตุผลว่าทำไมมันถึงกลายเป็นรูปแบบที่ แท้จริง สำหรับเครื่องสร้างเว็บไซต์แบบคงที่และแพลตฟอร์มบล็อกที่ทันสมัยเช่น Ghost
ในกรณีที่ต้องการมาร์กอัปแบบสั่งทำที่ซับซ้อนมากขึ้น ตัวแยกวิเคราะห์ Markdown ส่วนใหญ่จะยอมรับ HTML ดิบในอินพุต อย่างไรก็ตาม ยิ่งอาศัยมาร์กอัปที่ซับซ้อนมากเท่าใด ระบบการเขียนที่เข้าถึงได้น้อยกว่าก็จะยิ่งสำหรับผู้ที่ใช้เทคนิคน้อยกว่า หรือผู้ที่มีเวลาและความอดทนน้อย นี่คือที่มาของรหัสย่อ
รหัสย่อใน Hugo
Hugo คือเครื่องมือสร้างไซต์แบบสแตติกที่เขียนด้วยภาษา Go ซึ่งเป็นภาษาที่รวบรวมเอนกประสงค์ซึ่งพัฒนาขึ้นที่ Google เนื่องจากการทำงานพร้อมกัน (และไม่ต้องสงสัยเลยว่าคุณสมบัติภาษาระดับต่ำอื่น ๆ ที่ฉันไม่เข้าใจอย่างถ่องแท้) Go ทำให้ Hugo เป็นตัวสร้างเนื้อหาเว็บแบบคงที่ได้อย่างรวดเร็ว นี่เป็นหนึ่งในหลายเหตุผลที่ทำให้ Hugo ได้รับเลือกให้เข้าร่วม Smashing Magazine เวอร์ชันใหม่
นอกจากประสิทธิภาพแล้ว มันทำงานในลักษณะเดียวกันกับตัวสร้างที่ใช้ Ruby และ Node.js ซึ่งคุณอาจคุ้นเคยอยู่แล้ว: Markdown บวกกับข้อมูลเมตา (YAML หรือ TOML) ที่ประมวลผลผ่านเทมเพลต Sara Soueidan ได้เขียนไพรเมอร์ที่ยอดเยี่ยมเกี่ยวกับการทำงานหลักของ Hugo
สำหรับฉัน คุณลักษณะนักฆ่าของ Hugo คือการใช้รหัสย่อ ผู้ที่มาจาก WordPress อาจคุ้นเคยกับแนวคิดนี้อยู่แล้ว: ไวยากรณ์แบบย่อที่ใช้เป็นหลักในการรวมรหัสฝังที่ซับซ้อนของบริการของบุคคลที่สาม ตัวอย่างเช่น WordPress มีรหัสสั้น Vimeo ที่ใช้เพียง ID ของวิดีโอ Vimeo ที่เป็นปัญหา
[vimeo 44633289]
วงเล็บแสดงว่าเนื้อหาควรได้รับการประมวลผลเป็นรหัสสั้นและขยายเป็นมาร์กอัปการฝัง HTML แบบเต็มเมื่อแยกวิเคราะห์เนื้อหา
การใช้ฟังก์ชันเทมเพลต Go ทำให้ Hugo มี API ที่ง่ายมากสำหรับการสร้างรหัสย่อที่กำหนดเอง ตัวอย่างเช่น ฉันได้สร้างรหัสย่อ Codepen ง่ายๆ เพื่อรวมไว้ในเนื้อหา Markdown ของฉัน:
Some Markdown content before the shortcode. Aliquam sodales rhoncus dui, sed congue velit semper ut. Class aptent taciti sociosqu ad litora torquent. {{<codePen VpVNKW>}} Some Markdown content after the shortcode. Nulla vel magna sit amet dui lobortis commodo vitae vel nulla sit amet ante hendrerit tempus.
Hugo จะค้นหาเทมเพลตที่ชื่อ codePen.html
โดยอัตโนมัติในโฟลเดอร์ย่อยของรหัส shortcodes
เพื่อแยกวิเคราะห์รหัสย่อระหว่างการคอมไพล์ การใช้งานของฉันมีลักษณะดังนี้:
{{ if .Site.Params.codePenUser }} <iframe height='300' scrolling='no' title="code demonstration with codePen" src='//codepen.io/{{ .Site.Params.codepenUser | lower }}/embed/{{ .Get 0 }}/?height=265&theme-id=dark&default-tab=result,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true'> <div> <a href="//codepen.io/{{ .Site.Params.codePenUser | lower }}/pen/{{ .Get 0 }}">See the demo on codePen</a> </div> </iframe> {{ else }} <p class="site-error"><strong>Site error:</strong> The <code>codePenUser</code> param has not been set in <code>config.toml</code></p> {{ end }}
เพื่อให้ได้แนวคิดที่ดีขึ้นเกี่ยวกับวิธีการทำงานของแพ็คเกจเทมเพลต Go คุณจะต้องปรึกษา "Go Template Primer" ของ Hugo ในระหว่างนี้ ให้สังเกตสิ่งต่อไปนี้:
- มันค่อนข้างขี้ขลาดแต่ก็ยังทรงพลัง
- ส่วน
{{ .Get 0 }}
ใช้สำหรับดึงอาร์กิวเมนต์แรก (และในกรณีนี้เท่านั้น) ที่ให้มา — Codepen ID Hugo ยังสนับสนุนการตั้งชื่ออาร์กิวเมนต์ ซึ่งมีให้เหมือนกับแอตทริบิวต์ HTML -
.
ไวยากรณ์หมายถึงบริบทปัจจุบัน ดังนั้น .Get.Get 0
หมายความว่า “รับอาร์กิวเมนต์แรกที่ให้มาสำหรับรหัสย่อปัจจุบัน”
ไม่ว่าในกรณีใด ฉันคิดว่ารหัสย่อเป็นสิ่งที่ดีที่สุดตั้งแต่ขนมชนิดร่วน และการใช้งาน Hugo สำหรับการเขียนรหัสย่อที่กำหนดเองนั้นน่าประทับใจ ฉันควรสังเกตจากการวิจัยของฉันว่า เป็นไปได้ที่จะใช้ Jekyll รวมถึงเอฟเฟกต์ที่คล้ายกัน แต่ฉันพบว่ามันมีความยืดหยุ่นและทรงพลังน้อยกว่า
การสาธิตโค้ดที่ไม่มีบุคคลที่สาม
ฉันมีเวลามากมายสำหรับ Codepen (และโค้ด Playground อื่นๆ ที่พร้อมใช้งาน) แต่มีปัญหาโดยธรรมชาติในการรวมเนื้อหาดังกล่าวในไลบรารีรูปแบบ:
- มันใช้ API ดังนั้นจึงไม่สามารถทำงานแบบออฟไลน์ได้อย่างง่ายดายหรือมีประสิทธิภาพ
- ไม่เพียงแค่แสดงรูปแบบหรือส่วนประกอบเท่านั้น มันเป็นอินเทอร์เฟซที่ซับซ้อนของตัวเองที่ห่อหุ้มด้วยการสร้างแบรนด์ของตัวเอง สิ่งนี้จะสร้างเสียงรบกวนและเบี่ยงเบนความสนใจโดยไม่จำเป็นเมื่อควรเน้นที่ส่วนประกอบ
ในบางครั้ง ฉันพยายามฝังการสาธิตคอมโพเนนต์โดยใช้ iframes ของฉันเอง ฉันจะชี้ iframe ไปยังไฟล์ในเครื่องที่มีตัวอย่างเป็นหน้าเว็บของตัวเอง เมื่อใช้ iframe ฉันสามารถสรุปรูปแบบและพฤติกรรมโดยไม่ต้องพึ่งพาบุคคลที่สาม
น่าเสียดายที่ iframe ค่อนข้างเทอะทะและปรับขนาดแบบไดนามิกได้ยาก ในแง่ของความซับซ้อนในการเขียน ยังรวมถึงการรักษาไฟล์แยกกันและต้องลิงก์ไปยังไฟล์เหล่านั้น ฉันต้องการเขียนส่วนประกอบของฉันให้เข้าที่ รวมถึงเพียงโค้ดที่จำเป็นในการทำให้มันทำงาน ฉันต้องการเขียนการสาธิตในขณะที่เขียนเอกสารประกอบ
รหัสย่อ demo
โชคดีที่ Hugo อนุญาตให้คุณสร้างรหัสย่อที่มีเนื้อหาระหว่างแท็กเปิดและปิดรหัสย่อ เนื้อหามีอยู่ในไฟล์รหัสย่อโดยใช้ {{ .Inner }}
สมมติว่าฉันใช้รหัสย่อ demo
ดังนี้:
{{<demo>}} This is the content! {{</demo>}}
“นี่คือเนื้อหา!” จะพร้อมใช้งานเป็น {{ .Inner }}
ในเทมเพลต demo.html
ที่แยกวิเคราะห์ นี่เป็นจุดเริ่มต้นที่ดีสำหรับการสนับสนุนการสาธิตโค้ดแบบอินไลน์ แต่ฉันต้องแก้ไขการห่อหุ้ม
การห่อหุ้มสไตล์
เมื่อพูดถึงรูปแบบการห่อหุ้ม มีสามสิ่งที่ต้องกังวล:
- ลักษณะที่สืบทอดโดยองค์ประกอบจากหน้าหลัก
- เพจหลักที่สืบทอดสไตล์จากคอมโพเนนต์
- มีการใช้รูปแบบร่วมกันโดยไม่ได้ตั้งใจระหว่างส่วนประกอบต่างๆ
ทางออกหนึ่งคือการจัดการตัวเลือก CSS อย่างระมัดระวังเพื่อไม่ให้คอมโพเนนต์และหน้าทับซ้อนกัน นี่จะหมายถึงการใช้ตัวเลือกลึกลับต่อส่วนประกอบ และไม่ใช่สิ่งที่ฉันสนใจที่จะต้องพิจารณาเมื่อฉันสามารถเขียนโค้ดที่สั้นและอ่านง่าย ข้อดีอย่างหนึ่งของ iframes คือรูปแบบถูกห่อหุ้มไว้โดยค่าเริ่มต้น ดังนั้นฉันจึงสามารถเขียน button { background: blue }
และมั่นใจว่าจะใช้เฉพาะใน iframe เท่านั้น
วิธีที่เข้มข้นน้อยกว่าในการป้องกันไม่ให้คอมโพเนนต์สืบทอดสไตล์จากเพจคือการใช้คุณสมบัติ all
ที่มีค่า initial
ในองค์ประกอบหลักที่เลือก ฉันสามารถตั้งค่าองค์ประกอบนี้ในไฟล์ demo.html
:
<div class="demo"> {{ .Inner }} </div>
จากนั้น ฉันต้องใช้ all: initial
กับอินสแตนซ์ขององค์ประกอบนี้ ซึ่งแพร่กระจายไปยังลูกของแต่ละอินสแตนซ์
.demo { all: initial }
พฤติกรรมของ initial
ค่อนข้าง… แปลกประหลาด ในทางปฏิบัติ องค์ประกอบที่ได้รับผลกระทบทั้งหมดกลับไปใช้เฉพาะรูปแบบตัวแทนผู้ใช้ (เช่น display: block
for <h2>
องค์ประกอบ) อย่างไรก็ตาม องค์ประกอบที่ใช้ — class=“demo”
— จำเป็นต้องมีรูปแบบตัวแทนผู้ใช้บางอย่างที่ได้รับการคืนสถานะอย่างชัดเจน ในกรณีของเรา นี่เป็นเพียง display: block
เนื่องจาก class=“demo”
เป็น <div>
.demo { all: initial; display: block; }
หมายเหตุ: all
ยังไม่ได้รับการสนับสนุนใน Microsoft Edge แต่อยู่ระหว่างการพิจารณา การสนับสนุนนั้นกว้างมากจนทำให้มั่นใจได้ สำหรับจุดประสงค์ของเรา ค่าการ revert
จะมีประสิทธิภาพและเชื่อถือได้มากกว่า แต่ยังไม่รองรับในทุกที่
Shadow DOM กำลังใช้รหัสย่อ
การใช้ all: initial
ไม่ได้ทำให้องค์ประกอบแบบอินไลน์ของเราไม่มีภูมิคุ้มกันต่ออิทธิพลภายนอกอย่างสมบูรณ์ (ยังคงใช้ความจำเพาะ) แต่เราสามารถมั่นใจได้ว่ารูปแบบจะไม่ถูกตั้งค่า เนื่องจากเรากำลังจัดการกับชื่อคลาส demo
สงวนไว้ ส่วนใหญ่เพียงแค่สไตล์ที่สืบทอดมาจากตัวเลือกที่มีความจำเพาะต่ำ เช่น html
และ body
จะถูกตัดออก
อย่างไรก็ตาม สิ่งนี้เกี่ยวข้องกับสไตล์ที่มาจากพาเรนต์ไปสู่ส่วนประกอบเท่านั้น เพื่อป้องกันไม่ให้รูปแบบที่เขียนขึ้นสำหรับส่วนประกอบส่งผลต่อส่วนอื่นๆ ของหน้า เราจำเป็นต้องใช้ Shadow DOM เพื่อสร้างแผนผังย่อยที่ห่อหุ้ม
ลองนึกภาพว่าฉันต้องการบันทึกองค์ประกอบ <button>
ที่มีสไตล์ ฉันต้องการเขียนสิ่งต่อไปนี้ได้ง่ายๆ โดยไม่ต้องกลัวว่าตัวเลือกองค์ประกอบ button
จะนำไปใช้กับองค์ประกอบ <button>
ในไลบรารีรูปแบบเองหรือในส่วนประกอบอื่นๆ ในหน้าไลบรารีเดียวกัน
{{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}}
เคล็ดลับคือการใช้ส่วน {{ .Inner }}
ของเทมเพลตรหัสย่อและรวมไว้เป็น innerHTML
ของ ShadowRoot
ใหม่ ฉันอาจใช้สิ่งนี้ดังนี้:
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div class="demo"></div> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); root.innerHTML = '{{ .Inner }}'; })(); </script>
-
$uniq
ถูกตั้งค่าเป็นตัวแปรเพื่อระบุคอนเทนเนอร์ส่วนประกอบ มันไพพ์ในฟังก์ชันเทมเพลต Go เพื่อสร้างสตริงเฉพาะ… หวังว่า (!) — นี่ไม่ใช่วิธีการกันกระสุน มันเป็นเพียงภาพประกอบ -
root.attachShadow
ทำให้คอนเทนเนอร์คอมโพเนนต์เป็นโฮสต์ DOM เงา - ฉันเติม
innerHTML
ของShadowRoot
โดยใช้{{ .Inner }}
ซึ่งรวมถึง CSS ที่ห่อหุ้มในขณะนี้
การอนุญาตพฤติกรรม JavaScript
ฉันต้องการรวมพฤติกรรม JavaScript ในส่วนประกอบของฉันด้วย ตอนแรกฉันคิดว่ามันจะง่าย ขออภัย JavaScript ที่แทรกผ่าน innerHTML
ไม่ได้แยกวิเคราะห์หรือดำเนินการ ซึ่งสามารถแก้ไขได้โดยการนำเข้าจากเนื้อหาของ <template>
องค์ประกอบ ฉันแก้ไขการใช้งานของฉันตามนั้น
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} <div class="demo"></div> <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>
ตอนนี้ ฉันสามารถรวมการสาธิตแบบอินไลน์ของ พูด ปุ่มสลับที่ใช้งานได้:
{{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } [aria-pressed="true"] { box-shadow: inset 0 0 5px #000; } </style> <script> var toggle = document.querySelector('[aria-pressed]'); toggle.addEventListener('click', (e) => { let pressed = e.target.getAttribute('aria-pressed') === 'true'; e.target.setAttribute('aria-pressed', !pressed); }); </script> {{</demo>}}
หมายเหตุ: ฉันได้เขียนเชิงลึกเกี่ยวกับปุ่มสลับและการช่วยสำหรับการเข้าถึงสำหรับส่วนประกอบที่รวมไว้
การห่อหุ้ม JavaScript
ฉันประหลาดใจที่ JavaScript ไม่ได้ถูกห่อหุ้มโดยอัตโนมัติเหมือน CSS ที่อยู่ใน Shadow DOM นั่นคือ หากมีปุ่ม [aria-pressed]
อื่นในหน้าหลักก่อนตัวอย่างของคอมโพเนนต์นี้ ดังนั้น document.querySelector
จะกำหนดเป้าหมายไปที่นั้นแทน
สิ่งที่ฉันต้องการเทียบเท่ากับ document
สำหรับทรีย่อยของการสาธิตเท่านั้น สิ่งนี้กำหนดได้แม้ว่าจะค่อนข้างละเอียด:
document.getElementById('demo-{{ $uniq }}').shadowRoot;
ฉันไม่ต้องการเขียนนิพจน์นี้ทุกครั้งที่ต้องกำหนดเป้าหมายองค์ประกอบภายในคอนเทนเนอร์สาธิต ดังนั้นฉันจึงคิดวิธีการแฮ็กโดยกำหนดนิพจน์ให้กับตัวแปร demo
ในเครื่องและสคริปต์นำหน้าที่ให้มาผ่านรหัสย่อของงานนี้:
if (script) { script.textContent = `(function() { var demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true));
ด้วยสิ่งนี้ demo
จึงเทียบเท่ากับ document
สำหรับโครงสร้างย่อยของส่วนประกอบใดๆ และฉันสามารถใช้ demo.querySelector
เพื่อกำหนดเป้าหมายปุ่มสลับของฉันได้อย่างง่ายดาย
var toggle = demo.querySelector('[aria-pressed]');
โปรดทราบว่าฉันได้แนบเนื้อหาสคริปต์ของการสาธิตในนิพจน์ฟังก์ชันที่เรียกใช้ทันที (IIFE) เพื่อให้ตัวแปร demo
และตัวแปรดำเนินการทั้งหมดที่ใช้สำหรับส่วนประกอบนั้นไม่อยู่ในขอบเขตส่วนกลาง ด้วยวิธีนี้ สามารถใช้ demo
ในสคริปต์ของรหัสย่อใดก็ได้ แต่จะอ้างอิงถึงรหัสย่อที่อยู่ในมือเท่านั้น
ในกรณีที่ ECMAScript6 พร้อมใช้งาน เป็นไปได้ที่จะบรรลุการแปลเป็นภาษาท้องถิ่นโดยใช้ "การกำหนดขอบเขตบล็อก" โดยเพียงแค่วงเล็บปีกกาที่ล้อมรอบคำสั่ง let
หรือ const
อย่างไรก็ตาม คำจำกัดความอื่น ๆ ทั้งหมดภายในบล็อกจะต้องใช้ let
หรือ const
(หลีกเลี่ยง var
) เช่นกัน
{ let demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; // Author script injected here }
รองรับ Shadow DOM
แน่นอน สิ่งที่กล่าวมาทั้งหมดเป็นไปได้เฉพาะเมื่อรองรับ Shadow DOM เวอร์ชัน 1 เท่านั้น Chrome, Safari, Opera และ Android ทั้งหมดดูค่อนข้างดี แต่เบราว์เซอร์ Firefox และ Microsoft นั้นมีปัญหา เป็นไปได้ที่จะตรวจหาการสนับสนุนคุณลักษณะและแสดงข้อความแสดงข้อผิดพลาดที่ attachShadow
:
if (document.head.attachShadow) { // Do shadow DOM stuff here } else { root.innerHTML = 'Shadow DOM is needed to display encapsulated demos. The browser does not have an issue with the demo code itself'; }
หรือคุณสามารถรวม Shady DOM และส่วนขยาย Shady CSS ซึ่งหมายถึงการพึ่งพาที่ค่อนข้างใหญ่ (60 KB+) และ API อื่น Rob Dodson ใจดีพอที่จะให้ตัวอย่างพื้นฐานแก่ฉัน ซึ่งฉันยินดีที่จะแบ่งปันเพื่อช่วยคุณในการเริ่มต้น
คำบรรยายสำหรับส่วนประกอบ
ด้วยฟังก์ชันการสาธิตแบบอินไลน์พื้นฐาน การเขียนการสาธิตการทำงานแบบอินไลน์ด้วยเอกสารประกอบอย่างรวดเร็วจึงตรงไปตรงมา สิ่งนี้ทำให้เราสามารถถามคำถามอย่างฟุ่มเฟือยได้ เช่น "จะเกิดอะไรขึ้นหากฉันต้องการใส่คำบรรยายใต้ภาพเพื่อติดป้ายกำกับการสาธิต" สิ่งนี้เป็นไปได้อย่างสมบูรณ์ตั้งแต่ - ตามที่ระบุไว้ก่อนหน้านี้ - Markdown รองรับ HTML แบบดิบ
<figure role="group" aria-labelledby="caption-button"> {{<demo>}} <button>My button</button> <style> button { background: blue; padding: 0.5rem 1rem; text-transform: uppercase; } </style> {{</demo>}} <figcaption>A standard button</figcaption> </figure>
อย่างไรก็ตาม ส่วนใหม่เพียงส่วนเดียวของโครงสร้างที่แก้ไขนี้คือถ้อยคำของคำอธิบายภาพเอง ดีกว่าที่จะจัดให้มีอินเทอร์เฟซที่เรียบง่ายสำหรับการจัดหามันให้กับผลลัพธ์ ช่วยตัวเองในอนาคต — และใครก็ตามที่ใช้รหัสย่อ — เวลาและความพยายาม และลดความเสี่ยงของการพิมพ์รหัสผิด สามารถทำได้โดยระบุพารามิเตอร์ที่ระบุชื่อให้กับชอร์ตโค้ด ในกรณีนี้ ให้ตั้งชื่อแบบง่ายๆ ว่า caption
:
{{<demo caption="A standard button">}} ... demo contents here... {{</demo>}}
พารามิเตอร์ที่มีชื่อสามารถเข้าถึงได้ในเทมเพลต เช่น {{ .Get "caption" }}
ซึ่งง่ายพอสมควร ฉันต้องการคำอธิบายภาพ ดังนั้น <figure>
และ <figcaption>
โดยรอบเป็นตัวเลือก เมื่อใช้ if
clause ฉันสามารถระบุเนื้อหาที่เกี่ยวข้องได้เฉพาะในกรณีที่รหัสย่อให้อาร์กิวเมนต์คำอธิบายภาพ:
{{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }}
ต่อไปนี้คือรูปลักษณ์ของเทมเพลต demo.html
แบบเต็ม (เป็นที่ยอมรับว่าค่อนข้างเลอะเทอะ แต่ก็ใช้กลอุบายได้):
{{ $uniq := .Inner | htmlEscape | base64Encode | truncate 15 "" }} {{ if .Get "caption" }} <figure role="group" aria-labelledby="caption-{{ $uniq }}"> {{ end }} <div class="demo"></div> {{ if .Get "caption" }} <figcaption>{{ .Get "caption" }}</figcaption> {{ end }} {{ if .Get "caption" }} </figure> {{ end }} <template> {{ .Inner }} </template> <script> (function() { var root = document.getElementById('demo-{{ $uniq }}'); root.attachShadow({mode: 'open'}); var template = document.getElementById('template-{{ $uniq }}'); var script = template.content.querySelector('script'); if (script) { script.textContent = `(function() { var demo = document.getElementById(\'demo-{{ $uniq }}\').shadowRoot; ${script.textContent} })()` } root.shadowRoot.appendChild(document.importNode(template.content, true)); })(); </script>
หมายเหตุสุดท้าย: ฉันควรสนับสนุนไวยากรณ์มาร์กดาวน์ในค่าคำอธิบายภาพหรือไม่ ฉันสามารถไพพ์ผ่านฟังก์ชัน markdownify
ของ Hugo ได้ ด้วยวิธีนี้ ผู้เขียนสามารถใส่ markdown (และ HTML) ได้ แต่ก็ไม่ได้ถูกบังคับให้ทำเช่นนั้น
{{ .Get "caption" | markdownify }}
บทสรุป
สำหรับประสิทธิภาพและคุณสมบัติที่ยอดเยี่ยมมากมาย ขณะนี้ Hugo เหมาะสมกับฉันเมื่อพูดถึงการสร้างไซต์แบบคงที่ แต่การรวมรหัสย่อเป็นสิ่งที่ฉันคิดว่าน่าสนใจที่สุด ในกรณีนี้ ฉันสามารถสร้างอินเทอร์เฟซที่เรียบง่ายสำหรับปัญหาเอกสารที่ฉันพยายามแก้ไขมาระยะหนึ่งแล้ว
ในองค์ประกอบของเว็บ ความซับซ้อนของมาร์กอัปจำนวนมาก (บางครั้งรุนแรงขึ้นด้วยการปรับการช่วยสำหรับการเข้าถึง) สามารถซ่อนไว้หลังรหัสย่อได้ ในกรณีนี้ ฉันกำลังหมายถึงการรวม role="group"
ของฉันและความสัมพันธ์ aria-labelledby
ซึ่งให้ "ป้ายกำกับกลุ่ม" ที่ได้รับการสนับสนุนที่ดีกว่าสำหรับ <figure>
ไม่ใช่สิ่งที่ใคร ๆ ชื่นชอบในการเขียนโค้ดมากกว่าหนึ่งครั้ง โดยเฉพาะ โดยจะต้องพิจารณาค่าแอตทริบิวต์ที่ไม่ซ้ำกันในแต่ละอินสแตนซ์
ฉันเชื่อว่ารหัสย่อคือ Markdown และเนื้อหาว่าองค์ประกอบของเว็บเป็น HTML และฟังก์ชันการทำงานอย่างไร: วิธีที่จะทำให้การประพันธ์ง่ายขึ้น เชื่อถือได้มากขึ้น และสอดคล้องกันมากขึ้น ฉันหวังว่าจะมีวิวัฒนาการเพิ่มเติมในด้านเล็กๆ น้อยๆ ของเว็บที่น่าสนใจนี้
ทรัพยากร
- เอกสารฮิวโก้
- “เทมเพลตแพ็คเกจ” ภาษาการเขียนโปรแกรม Go
- “รหัสย่อ” Hugo
- “ทั้งหมด” (คุณสมบัติชวเลข CSS), Mozilla Developer Network
- “เริ่มต้น (คำหลัก CSS), Mozilla Developer Network
- “Shadow DOM v1: ส่วนประกอบของเว็บในตัวเอง” Eric Bidelman, ความรู้พื้นฐานด้านเว็บ, Google Developers
- “แนะนำองค์ประกอบเทมเพลต” เออิจิ คิตามูระ, WebComponents.org
- “รวม” เจคิล