วิธีง่ายๆในการสร้างส่วนประกอบเทมเพลตที่นำกลับมาใช้ใหม่ได้ใน Django
คุณต้องลงทะเบียนส่วนประกอบของคุณก่อน
from django_web_components import component
@ component . register ( "card" )
class Card ( component . Component ):
template_name = "components/card.html"เทมเพลตของส่วนประกอบ:
# components/card.html
{% load components %}
< div class =" card " >
< div class =" card-header " >
{% render_slot slots.header %}
</ div >
< div class =" card-body " >
< h5 class =" card-title " >
{% render_slot slots.title %}
</ h5 >
{% render_slot slots.inner_block %}
</ div >
</ div >ตอนนี้คุณสามารถแสดงองค์ประกอบนี้ด้วย:
{% load components %}
{% card %}
{% slot header %} Featured {% endslot %}
{% slot title %} Card title {% endslot %}
< p > Some quick example text to build on the card title and make up the bulk of the card's content. </ p >
< a href =" # " class =" btn btn-primary " > Go somewhere </ a >
{% endcard %}ซึ่งจะส่งผลให้มีการแสดงผล HTML ต่อไปนี้:
< div class =" card " >
< div class =" card-header " >
Featured
</ div >
< div class =" card-body " >
< h5 class =" card-title " >
Card title
</ h5 >
< p > Some quick example text to build on the card title and make up the bulk of the card's content. </ p >
< a href =" # " class =" btn btn-primary " > Go somewhere </ a >
</ div >
</ div > pip install django-web-components
จากนั้นเพิ่ม django_web_components ลงใน INSTALLED_APPS ของคุณ
INSTALLED_APPS = [
...,
"django_web_components" ,
] เพื่อหลีกเลี่ยงการใช้ {% load components %} ในแต่ละเทมเพลตคุณสามารถเพิ่มแท็กลงในรายการใน builtins ภายในการตั้งค่าของคุณ
TEMPLATES = [
{
...,
"OPTIONS" : {
"context_processors" : [
...
],
"builtins" : [
"django_web_components.templatetags.components" ,
],
},
},
]ห้องสมุดรองรับ Python 3.8+ และ Django 3.2+
| เวอร์ชัน Python | เวอร์ชัน Django |
|---|---|
3.12 | 5.0 , 4.2 |
3.11 | 5.0 , 4.2 , 4.1 |
3.10 | 5.0 , 4.2 , 4.1 , 4.0 , 3.2 |
3.9 | 4.2 , 4.1 , 4.0 , 3.2 |
3.8 | 4.2 , 4.1 , 4.0 , 3.2 |
มีสองวิธีในการเขียนส่วนประกอบ: ส่วนประกอบตามคลาสและส่วนประกอบที่ใช้ฟังก์ชั่น
from django_web_components import component
@ component . register ( "alert" )
class Alert ( component . Component ):
# You may also override the get_template_name() method instead
template_name = "components/alert.html"
# Extra context data will be passed to the template context
def get_context_data ( self , ** kwargs ) -> dict :
return {
"dismissible" : False ,
} ส่วนประกอบจะแสดงผลโดยการเรียกใช้เมธอด render(context) ซึ่งโดยค่าเริ่มต้นจะโหลดไฟล์เทมเพลตและแสดงผล
สำหรับส่วนประกอบเล็ก ๆ อาจรู้สึกยุ่งยากในการจัดการทั้งคลาสส่วนประกอบและเทมเพลตของส่วนประกอบ ด้วยเหตุผลนี้คุณสามารถกำหนดเทมเพลตได้โดยตรงจากวิธี render :
from django_web_components import component
from django_web_components . template import CachedTemplate
@ component . register ( "alert" )
class Alert ( component . Component ):
def render ( self , context ) -> str :
return CachedTemplate (
"""
<div class="alert alert-primary" role="alert">
{% render_slot slots.inner_block %}
</div>
""" ,
name = "alert" ,
). render ( context ) ส่วนประกอบอาจถูกกำหนดเป็นฟังก์ชั่นเดียวที่ยอมรับ context และส่งคืนสตริง:
from django_web_components import component
from django_web_components . template import CachedTemplate
@ component . register
def alert ( context ):
return CachedTemplate (
"""
<div class="alert alert-primary" role="alert">
{% render_slot slots.inner_block %}
</div>
""" ,
name = "alert" ,
). render ( context )ตัวอย่างในคู่มือนี้ส่วนใหญ่จะใช้ส่วนประกอบที่ใช้ฟังก์ชั่นเนื่องจากมันง่ายกว่าที่จะเป็นแบบอย่างเมื่อรหัสส่วนประกอบและเทมเพลตอยู่ในสถานที่เดียวกัน แต่คุณมีอิสระที่จะเลือกวิธีที่คุณต้องการ
ไลบรารีใช้เทมเพลต Django ปกติซึ่งช่วยให้คุณสามารถโหลดเทมเพลตจากไฟล์หรือสร้างวัตถุเทมเพลตโดยตรงโดยใช้สตริงเทมเพลต ทั้งสองวิธีได้รับการสนับสนุนและทั้งสองมีข้อดีและข้อเสีย:
เกี่ยวกับการแคชไลบรารีจะจัดเตรียม CachedTemplate ซึ่งจะแคชและนำวัตถุ Template กลับมาใช้ใหม่ตราบใดที่คุณให้ name ซึ่งจะใช้เป็นคีย์แคช:
from django_web_components import component
from django_web_components . template import CachedTemplate
@ component . register
def alert ( context ):
return CachedTemplate (
"""
<div class="alert alert-primary" role="alert">
{% render_slot slots.inner_block %}
</div>
""" ,
name = "alert" ,
). render ( context ) ดังนั้นในความเป็นจริงการแคชไม่ควรเป็นปัญหาเมื่อใช้สตริงเทมเพลตเนื่องจาก CachedTemplate นั้นเร็วเท่ากับการใช้ตัวโหลดแคชกับไฟล์เทมเพลต
เกี่ยวกับการสนับสนุนการจัดรูปแบบและการเน้นไวยากรณ์ไม่มีทางออกที่ดีสำหรับสตริงเทมเพลต PyCharm รองรับการฉีดภาษาซึ่งช่วยให้คุณสามารถเพิ่มความคิดเห็น # language=html ก่อนที่จะใช้สตริงเทมเพลตและรับการเน้นไวยากรณ์อย่างไรก็ตามมันเน้นเฉพาะ HTML และไม่ใช่แท็ก Django และคุณยังขาดการสนับสนุนสำหรับการจัดรูปแบบ บางทีบรรณาธิการอาจเพิ่มการสนับสนุนที่ดีขึ้นสำหรับสิ่งนี้ในอนาคต แต่ในขณะที่คุณจะขาดการเน้นไวยากรณ์และการจัดรูปแบบหากคุณไปเส้นทางนี้ มีการสนทนาที่เปิดกว้างเกี่ยวกับเรื่องนี้เกี่ยวกับ repo django-components เครดิตกับ Emilstenstrom สำหรับการย้ายการสนทนาไปข้างหน้ากับทีม VSCODE
ในท้ายที่สุดมันเป็นการแลกเปลี่ยน ใช้วิธีการที่เหมาะสมที่สุดสำหรับคุณ
เช่นเดียวกับสัญญาณส่วนประกอบสามารถอยู่ได้ทุกที่ แต่คุณต้องแน่ใจว่า Django หยิบมันขึ้นมาเมื่อเริ่มต้น วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการกำหนดส่วนประกอบของคุณใน components.py submodule ของแอปพลิเคชันที่เกี่ยวข้องแล้วเชื่อมต่อภายในวิธีการ ready() ของคลาสการกำหนดค่าแอปพลิเคชันของคุณ
from django . apps import AppConfig
from django_web_components import component
class MyAppConfig ( AppConfig ):
...
def ready ( self ):
# Implicitly register components decorated with @component.register
from . import components # noqa
# OR explicitly register a component
component . register ( "card" , components . Card ) คุณอาจ unregister ส่วนประกอบที่มีอยู่หรือรับส่วนประกอบจากรีจิสทรี:
from django_web_components import component
# Unregister a component
component . registry . unregister ( "card" )
# Get a component
component . registry . get ( "card" )
# Remove all components
component . registry . clear ()
# Get all components as a dict of name: component
component . registry . all ()แต่ละองค์ประกอบที่ลงทะเบียนจะมีสองแท็กสำหรับใช้ในเทมเพลตของคุณ:
{% card %} ... {% endcard %}{% #user_profile %} สิ่งนี้มีประโยชน์สำหรับส่วนประกอบที่ไม่จำเป็นต้องมีร่างกายโดยค่าเริ่มต้นส่วนประกอบจะลงทะเบียนโดยใช้แท็กต่อไปนี้:
{% <component_name> %}{% end<component_name> %}{% #<component_name> %} พฤติกรรมนี้อาจเปลี่ยนแปลงได้โดยการจัดทำแท็กที่กำหนดเองในการตั้งค่าของคุณ ตัวอย่างเช่นในการเปลี่ยนแท็กบล็อกเป็น {% #card %} ... {% /card %} และแท็กแบบอินไลน์เป็น {% card %} (คล้ายกับรองเท้าแตะ) คุณสามารถใช้รูปแบบต่อไปนี้:
class ComponentTagFormatter :
def format_block_start_tag ( self , name ):
return f"# { name } "
def format_block_end_tag ( self , name ):
return f"/ { name } "
def format_inline_tag ( self , name ):
return name
# inside your settings
WEB_COMPONENTS = {
"DEFAULT_COMPONENT_TAG_FORMATTER" : "path.to.your.ComponentTagFormatter" ,
}คุณสามารถส่งข้อมูลไปยังส่วนประกอบโดยใช้อาร์กิวเมนต์คำหลักซึ่งยอมรับค่าฮาร์ดโค้ดหรือตัวแปร:
{% with error_message="Something bad happened!" %}
{% #alert type="error" message=error_message %}
{% endwith %} แอตทริบิวต์ทั้งหมดจะถูกเพิ่มใน attributes dict ซึ่งจะมีอยู่ในบริบทของเทมเพลต:
{
"attributes" : {
"type" : " error " ,
"message" : " Something bad happened! "
}
}จากนั้นคุณสามารถเข้าถึงได้จากเทมเพลตส่วนประกอบของคุณ:
< div class =" alert alert-{{ attributes.type }} " >
{{ attributes.message }}
</ div > คุณอาจแสดงแอตทริบิวต์ทั้งหมดโดยตรงโดยใช้ {{ attributes }} ตัวอย่างเช่นหากคุณมีองค์ประกอบต่อไปนี้
{% alert id="alerts" class="font-bold" %} ... {% endalert %}คุณสามารถแสดงแอตทริบิวต์ทั้งหมดโดยใช้
< div {{ attributes }} >
<!-- Component content -->
</ div >ซึ่งจะส่งผลให้มีการแสดงผล HTML ต่อไปนี้:
< div id =" alerts " class =" font-bold " >
<!-- Component content -->
</ div > นอกจากนี้คุณยังสามารถผ่านแอตทริบิวต์ที่มีอักขระพิเศษ ( [@:_-.] ) เช่นเดียวกับแอตทริบิวต์ที่ไม่มีค่า:
{% button @click="handleClick" data-id="123" required %} ... {% endbutton %}ซึ่งจะส่งผลให้มีการติดตาม dict ที่มีอยู่ในบริบท:
{
"attributes" : {
"@click" : "handleClick" ,
"data-id" : "123" ,
"required" : True ,
}
} และจะแสดงผลโดย {{ attributes }} เป็น @click="handleClick" data-id="123" required
บางครั้งคุณอาจต้องระบุค่าเริ่มต้นสำหรับแอตทริบิวต์หรือรวมค่าเพิ่มเติมเข้ากับแอตทริบิวต์ขององค์ประกอบบางส่วน ห้องสมุดมีแท็ก merge_attrs ที่ช่วยในเรื่องนี้:
< div {% merge_attrs attributes class =" alert " role =" alert " %} >
<!-- Component content -->
</ div >หากเราถือว่าส่วนประกอบนี้ถูกใช้เช่นนั้น:
{% alert class="mb-4" %} ... {% endalert %}HTML ที่แสดงผลสุดท้ายของส่วนประกอบจะปรากฏขึ้นดังต่อไปนี้:
< div class =" alert mb-4 " role =" alert " >
<!-- Component content -->
</ div > เมื่อการรวมแอตทริบิวต์ที่ไม่ใช่แอตทริบิวต์ class ค่าที่ให้กับแท็ก merge_attrs จะได้รับการพิจารณาค่า "เริ่มต้น" ของแอตทริบิวต์ อย่างไรก็ตามแตกต่างจากแอตทริบิวต์ class คุณลักษณะเหล่านี้จะไม่ถูกรวมเข้ากับค่าแอตทริบิวต์ที่ฉีด แต่พวกเขาจะถูกเขียนทับ ตัวอย่างเช่นการใช้งานส่วนประกอบของ button อาจมีลักษณะดังต่อไปนี้:
< button {% merge_attrs attributes type =" button " %} >
{% render_slot slots.inner_block %}
</ button > ในการแสดงส่วนประกอบปุ่มด้วย type ที่กำหนดเองอาจมีการระบุเมื่อใช้ส่วนประกอบ หากไม่ระบุประเภทประเภท button จะใช้:
{% button type="submit" %} Submit {% endbutton %} HTML ที่แสดงผลของส่วนประกอบ button ในตัวอย่างนี้คือ:
< button type =" submit " >
Submit
</ button > คุณอาจปฏิบัติต่อแอตทริบิวต์อื่น ๆ ว่า "ต่อท้าย" โดยใช้ตัวดำเนินการ += ตัวดำเนินการ:
< div {% merge_attrs attributes data-value+ =" some-value " %} >
<!-- Component content -->
</ div >หากเราถือว่าส่วนประกอบนี้ถูกใช้เช่นนั้น:
{% alert data-value="foo" %} ... {% endalert %}HTML ที่แสดงผลจะเป็น:
< div data-value =" foo some-value " >
<!-- Component content -->
</ div > โดยค่าเริ่มต้นแอตทริบิวต์ทั้งหมดจะถูกเพิ่มลงใน attributes dict ภายในบริบท อย่างไรก็ตามนี่อาจไม่ใช่สิ่งที่เราต้องการเสมอไป ตัวอย่างเช่นลองจินตนาการว่าเราต้องการมีองค์ประกอบ alert ที่สามารถยกเลิกได้ในขณะเดียวกันก็สามารถส่งผ่านแอตทริบิวต์พิเศษไปยังองค์ประกอบรูทเช่น id หรือ class เป็นการดีที่เราต้องการที่จะสามารถแสดงองค์ประกอบเช่นนี้:
{% alert id="alerts" dismissible %} Something went wrong! {% endalert %}วิธีที่ไร้เดียงสาในการใช้งานส่วนประกอบนี้จะเป็นสิ่งต่อไปนี้:
< div {{ attributes }} >
{% render_slot slots.inner_block %}
{% if attributes.dismissible %}
< button type =" button " class =" btn-close " data-bs-dismiss =" alert " aria-label =" Close " > </ button >
{% endif %}
</ div > อย่างไรก็ตามสิ่งนี้จะส่งผลให้แอตทริบิวต์ dismissible ถูกรวมอยู่ในองค์ประกอบรูทซึ่งไม่ใช่สิ่งที่เราต้องการ:
< div id =" alerts " dismissible >
Something went wrong!
< button type =" button " class =" btn-close " data-bs-dismiss =" alert " aria-label =" Close " > </ button >
</ div > เป็นการดีที่เราต้องการให้แอตทริบิวต์ dismissible แยกออกได้จาก attributes เนื่องจากเราต้องการใช้มันในตรรกะ แต่ไม่จำเป็นต้องแสดงผลกับส่วนประกอบ
เพื่อให้บรรลุเป้าหมายนี้คุณสามารถจัดการบริบทจากส่วนประกอบของคุณเพื่อให้ API ที่ดีขึ้นสำหรับการใช้ส่วนประกอบ มีหลายวิธีในการทำเช่นนี้เลือกวิธีที่เหมาะสมที่สุดสำหรับคุณเช่น:
get_context_data และลบแอตทริบิวต์ dismissible จาก attributes และส่งคืนในบริบทแทน from django_web_components import component
@ component . register ( "alert" )
class Alert ( component . Component ):
template_name = "components/alert.html"
def get_context_data ( self , ** kwargs ):
dismissible = self . attributes . pop ( "dismissible" , False )
return {
"dismissible" : dismissible ,
}render และจัดการบริบทที่นั่น from django_web_components import component
@ component . register ( "alert" )
class Alert ( component . Component ):
template_name = "components/alert.html"
def render ( self , context ):
context [ "dismissible" ] = context [ "attributes" ]. pop ( "dismissible" , False )
return super (). render ( context )โซลูชันทั้งสองข้างต้นจะใช้งานได้และคุณสามารถทำเช่นเดียวกันกับส่วนประกอบที่ใช้ฟังก์ชั่น เทมเพลตของส่วนประกอบนั้นมีลักษณะเช่นนี้:
< div {{ attributes }} >
{% render_slot slots.inner_block %}
{% if dismissible %}
< button type =" button " class =" btn-close " data-bs-dismiss =" alert " aria-label =" Close " > </ button >
{% endif %}
</ div >ซึ่งควรส่งผลให้มีการแสดงผล HTML ที่ถูกต้อง:
< div id =" alerts " >
Something went wrong!
< button type =" button " class =" btn-close " data-bs-dismiss =" alert " aria-label =" Close " > </ button >
</ div > คุณมักจะต้องผ่านเนื้อหาเพิ่มเติมไปยังส่วนประกอบของคุณผ่าน "สล็อต" ตัวแปรบริบท slots ถูกส่งผ่านไปยังส่วนประกอบของคุณซึ่งประกอบด้วยคำสั่งที่มีชื่อสล็อตเป็นคีย์และสล็อตเป็นค่า จากนั้นคุณสามารถแสดงผลสล็อตภายในส่วนประกอบของคุณโดยใช้แท็ก render_slot
ในการสำรวจแนวคิดนี้ลองจินตนาการว่าเราต้องการส่งเนื้อหาบางส่วนไปยังองค์ประกอบ alert :
{% alert %}
< strong > Whoops! </ strong > Something went wrong!
{% endalert %} โดยค่าเริ่มต้นเนื้อหานั้นจะพร้อมใช้งานกับส่วนประกอบของคุณในสล็อตเริ่มต้นซึ่งเรียกว่า inner_block จากนั้นคุณสามารถแสดงผลสล็อตนี้โดยใช้แท็ก render_slot ภายในส่วนประกอบของคุณ:
{% load components %}
< div class =" alert alert-danger " >
{% render_slot slots.inner_block %}
</ div >ซึ่งควรส่งผลให้มีการแสดงผล HTML ต่อไปนี้:
< div class =" alert alert-danger " >
< strong > Whoops! </ strong > Something went wrong!
</ div >นอกจากนี้คุณยังสามารถเปลี่ยนชื่อสล็อตเริ่มต้นได้โดยระบุในการตั้งค่าของคุณ:
# inside your settings
WEB_COMPONENTS = {
"DEFAULT_SLOT_NAME" : "inner_block" ,
}บางครั้งส่วนประกอบอาจจำเป็นต้องแสดงช่องหลายช่องที่แตกต่างกันในตำแหน่งที่แตกต่างกันภายในส่วนประกอบ มาปรับเปลี่ยนองค์ประกอบการแจ้งเตือนของเราเพื่อให้สามารถฉีดสล็อต "ชื่อ":
{% load components %}
< div class =" alert alert-danger " >
< span class =" alert-title " >
{% render_slot slots.title %}
</ span >
{% render_slot slots.inner_block %}
</ div > คุณสามารถกำหนดเนื้อหาของสล็อตชื่อโดยใช้แท็ก slot เนื้อหาใด ๆ ที่ไม่ได้อยู่ในแท็ก slot ที่ชัดเจนจะถูกเพิ่มลงในสล็อตค่าเริ่มต้น inner_block :
{% load components %}
{% alert %}
{% slot title %} Server error {% endslot %}
< strong > Whoops! </ strong > Something went wrong!
{% endalert %}HTML ที่แสดงผลในตัวอย่างนี้คือ:
< div class =" alert alert-danger " >
< span class =" alert-title " >
Server error
</ span >
< strong > Whoops! </ strong > Something went wrong!
</ div >คุณสามารถกำหนดสล็อตชื่อเดียวกันหลายครั้ง:
{% unordered_list %}
{% slot item %} First item {% endslot %}
{% slot item %} Second item {% endslot %}
{% slot item %} Third item {% endslot %}
{% endunordered_list %}จากนั้นคุณสามารถวนซ้ำผ่านสล็อตภายในส่วนประกอบของคุณ:
< ul >
{% for item in slots.item %}
< li > {% render_slot item %} </ li >
{% endfor %}
</ ul >ซึ่งจะส่งผลให้ HTML ต่อไปนี้:
< ul >
< li > First item </ li >
< li > Second item </ li >
< li > Third item </ li >
</ ul > เนื้อหาสล็อตจะสามารถเข้าถึงบริบทของส่วนประกอบได้ ในการสำรวจแนวคิดนี้ลองจินตนาการถึงองค์ประกอบรายการที่ยอมรับแอตทริบิวต์ entries ที่แสดงรายการของสิ่งต่าง ๆ ซึ่งจะทำซ้ำและแสดงผล inner_block สล็อตสำหรับแต่ละรายการ
from django_web_components import component
from django_web_components . template import CachedTemplate
@ component . register
def unordered_list ( context ):
context [ "entries" ] = context [ "attributes" ]. pop ( "entries" , [])
return CachedTemplate (
"""
<ul>
{% for entry in entries %}
<li>
{% render_slot slots.inner_block %}
</li>
{% endfor %}
</ul>
""" ,
name = "unordered_list" ,
). render ( context )จากนั้นเราสามารถแสดงส่วนประกอบดังนี้:
{% unordered_list entries=entries %}
I like {{ entry }}!
{% endunordered_list %} ในตัวอย่างนี้ตัวแปร entry มาจากบริบทขององค์ประกอบ ถ้าเราสมมติว่า entries = ["apples", "bananas", "cherries"] , html ผลลัพธ์จะเป็น:
< ul >
< li > I like apples! </ li >
< li > I like bananas! </ li >
< li > I like cherries! </ li >
</ ul > นอกจากนี้คุณยังสามารถผ่านอาร์กิวเมนต์ที่สองไปยัง render_slot ได้อย่างชัดเจน:
< ul >
{% for entry in entries %}
< li >
<!-- We are passing the `entry` as the second argument to render_slot -->
{% render_slot slots.inner_block entry %}
</ li >
{% endfor %}
</ ul > เมื่อเรียกใช้ส่วนประกอบคุณสามารถใช้แอตทริบิวต์พิเศษ :let ให้ใช้ค่าที่ส่งผ่านไปยัง render_slot และผูกกับตัวแปร:
{% unordered_list :let="fruit" entries=entries %}
I like {{ fruit }}!
{% endunordered_list %}สิ่งนี้จะทำให้ HTML เดียวกันกับด้านบน
คล้ายกับส่วนประกอบคุณสามารถกำหนดแอตทริบิวต์เพิ่มเติมให้กับสล็อต ด้านล่างนี้เป็นส่วนประกอบของตารางที่แสดงหลายช่องชื่อที่มีแอตทริบิวต์:
from django_web_components import component
from django_web_components . template import CachedTemplate
@ component . register
def table ( context ):
context [ "rows" ] = context [ "attributes" ]. pop ( "rows" , [])
return CachedTemplate (
"""
<table>
<tr>
{% for col in slots.column %}
<th>{{ col.attributes.label }}</th>
{% endfor %}
</tr>
{% for row in rows %}
<tr>
{% for col in slots.column %}
<td>
{% render_slot col row %}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
""" ,
name = "table" ,
). render ( context )คุณสามารถเรียกใช้ส่วนประกอบได้เช่นนั้น:
{% table rows=rows %}
{% slot column :let="user" label="Name" %}
{{ user.name }}
{% endslot %}
{% slot column :let="user" label="Age" %}
{{ user.age }}
{% endslot %}
{% endtable %} ถ้าเราสมมติว่า rows = [{ "name": "Jane", "age": "34" }, { "name": "Bob", "age": "51" }] html ต่อไปนี้จะแสดงผล:
< table >
< tr >
< th > Name </ th >
< th > Age </ th >
</ tr >
< tr >
< td > Jane </ td >
< td > 34 </ td >
</ tr >
< tr >
< td > Bob </ td >
< td > 51 </ td >
</ tr >
</ table >นอกจากนี้คุณยังอาจทำรังเพื่อให้ได้องค์ประกอบที่ซับซ้อนมากขึ้น นี่คือตัวอย่างของวิธีที่คุณอาจใช้ส่วนประกอบหีบเพลงโดยใช้ bootstrap:
from django_web_components import component
from django_web_components . template import CachedTemplate
import uuid
@ component . register
def accordion ( context ):
context [ "accordion_id" ] = context [ "attributes" ]. pop ( "id" , str ( uuid . uuid4 ()))
context [ "always_open" ] = context [ "attributes" ]. pop ( "always_open" , False )
return CachedTemplate (
"""
<div class="accordion" id="{{ accordion_id }}">
{% render_slot slots.inner_block %}
</div>
""" ,
name = "accordion" ,
). render ( context )
@ component . register
def accordion_item ( context ):
context [ "id" ] = context [ "attributes" ]. pop ( "id" , str ( uuid . uuid4 ()))
context [ "open" ] = context [ "attributes" ]. pop ( "open" , False )
return CachedTemplate (
"""
<div class="accordion-item" id="{{ id }}">
<h2 class="accordion-header" id="{{ id }}-header">
<button
class="accordion-button {% if not open %}collapsed{% endif %}"
type="button"
data-bs-toggle="collapse"
data-bs-target="#{{ id }}-collapse"
aria-expanded="{% if open %}true{% else %}false{% endif %}"
aria-controls="{{ id }}-collapse"
>
{% render_slot slots.title %}
</button>
</h2>
<div
id="{{ id }}-collapse"
class="accordion-collapse collapse {% if open %}show{% endif %}"
aria-labelledby="{{ id }}-header"
{% if accordion_id and not always_open %}
data-bs-parent="#{{ accordion_id }}"
{% endif %}}
>
<div class="accordion-body">
{% render_slot slots.body %}
</div>
</div>
</div>
""" ,
name = "accordion_item" ,
). render ( context )จากนั้นคุณสามารถใช้ดังนี้:
{% accordion %}
{% accordion_item open %}
{% slot title %} Accordion Item #1 {% endslot %}
{% slot body %}
< strong > This is the first item's accordion body. </ strong > It is shown by default.
{% endslot %}
{% endaccordion_item %}
{% accordion_item %}
{% slot title %} Accordion Item #2 {% endslot %}
{% slot body %}
< strong > This is the second item's accordion body. </ strong > It is hidden by default.
{% endslot %}
{% endaccordion_item %}
{% accordion_item %}
{% slot title %} Accordion Item #3 {% endslot %}
{% slot body %}
< strong > This is the third item's accordion body. </ strong > It is hidden by default.
{% endslot %}
{% endaccordion_item %}
{% endaccordion %} โครงการใช้ poetry เพื่อจัดการการพึ่งพา ตรวจสอบเอกสารเกี่ยวกับวิธีการติดตั้งบทกวีที่นี่: https://python-poetry.org/docs/#installation
ติดตั้งการอ้างอิง
poetry installเปิดใช้งานสภาพแวดล้อม
poetry shellตอนนี้คุณสามารถเรียกใช้การทดสอบ
python runtests.pyโครงการเกิดขึ้นหลังจากเห็นว่าภาษา / เฟรมเวิร์กอื่น ๆ จัดการกับส่วนประกอบอย่างไรและต้องการนำความคิดเหล่านั้นกลับไปที่ Django
django-components ที่มีอยู่นั้นยอดเยี่ยมอยู่แล้วและสนับสนุนคุณสมบัติส่วนใหญ่ที่โครงการนี้มี แต่ฉันคิดว่าไวยากรณ์สามารถปรับปรุงได้เล็กน้อยเพื่อให้รู้สึกถึงคำกริยาน้อยลงdjango-components นั้นดูเหมือน HTML <x-alert type="error">Server Error</x-alert> )ภาษา / เฟรมเวิร์กอื่น ๆ อีกมากมายใช้แนวคิดเดียวกันสำหรับการสร้างส่วนประกอบ (สล็อต, คุณลักษณะ) ดังนั้นความรู้มากมายจึงสามารถถ่ายโอนได้และมีไลบรารีส่วนประกอบที่มีอยู่มากมายอยู่แล้ว (เช่นการใช้ bootstrap, tailwind, การออกแบบวัสดุเป็นต้น) ฉันขอแนะนำให้ดูบางส่วนเพื่อรับแรงบันดาลใจในการสร้าง / โครงสร้างส่วนประกอบของคุณ นี่คือตัวอย่างบางส่วน: