如何使用 Alpine.js 组合 Django 模板片段来创建可重用的服务器渲染组件?

问题描述 投票:0回答:1

简而言之,我正在努力实现的是创建一个可重用的 Alpine 组件,其子组件在 Django 模板片段中定义。

代码未按预期工作的示例 — Carousel

我有这个模板结构:

cities_page.html
(模板)/
city.html
(片段)/
carousel.html
(片段+Alpine)/
carousel_item.html
(片段)。

cities_page
渲染许多
cities
,每个
carousel
渲染许多
carousel_items
。所有渲染都发生在服务器端。

cities_page.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Cities Page</title>
  <script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
</head>

<body>
{% for city in cities %}
  {% include "myapp/snippets/city.html" with city=city %}
{% endfor %}
</body>
</html>

city.html

<div>
  <h2>{{ city.name }}</h2>
  {% include "myapp/snippets/carousel.html" with images=city.images %}
</div>

carousel.html

<div x-data="carousel">
  <template x-for="item in items" :key="item">
    <div x-html="item.itemHtml"></div>
  </template>
</div>

<script>
  document.addEventListener('alpine:init', () => {
      Alpine.data(`carousel`, () => ({
        items: [
          {% for image in images %}
            {
              itemHtml: `{% include "myapp/snippets/carousel_item.html" with image=image %}`,
            },
          {% endfor %}
        ]
      }));
    });
</script>

carousel_item.html

<p>
  Item: {{ image }}
</p>

views.py

def cities_page(request):
    context = {
        "cities": [
            {
                "name": "London",
                "images": ["london1.jpg", "london2.jpg", "london3.jpg"]
            },
            {
                "name": "Paris",
                "images": ["paris1.jpg", "paris2.jpg", "paris3.jpg"]
            },
        ]
    }
    return render(request, "myapp/cities_page.html", context=context)

我希望 Alpine 管理我的轮播项目的原因是我想设计操纵这些项目的交互。这可以是像

reverseOrder
removeItem
这样的方法。

这样做的结果是:

伦敦

项目:paris1.jpg

项目:paris2.jpg

项目:paris3.jpg

巴黎

项目:paris1.jpg

项目:paris2.jpg

项目:paris3.jpg

请注意,伦敦有巴黎的图像。问题是为巴黎轮播定义的脚本覆盖了为伦敦定义的脚本。

我解决这个问题的最佳尝试是像这样重写轮播

<div>
  <template x-for="item in items" :key="item">
    <div x-html="item.itemHtml"></div>
  </template>
</div>

<script>
  (() => {
    const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16)).join('');

    const id = genRanHex(5)
    const currentScript = document.currentScript;
    const previousElement = currentScript.previousElementSibling;
    previousElement.setAttribute("x-data", `carousel${id}`)

    document.addEventListener('alpine:init', () => {
      Alpine.data(`carousel${id}`, () => ({
        items: [
          {% for image in images %}
            {
              itemHtml: `{% include "myapp/snippets/carousel_item.html" with image=image %}`,
            },
          {% endfor %}
        ]
      }));
    });
  })();
</script>

请注意,我

  • 已删除
    x-data
  • 生成一个随机ID并将其分配给Alpine组件名称以使其全局唯一
  • 使用脚本设置
    x-data
  • 通过匿名函数包装脚本,确保脚本中定义的所有内容不会污染全局范围(以及每个轮播实例中包含的该脚本的其他版本)

这感觉像是一种构建可重用组件的非常古怪的方法。

因此,我的问题是:编写此类组件的最佳实践是什么?我是否在 Alpine 上把事情推得太远了,我是否应该考虑使用 Vue/React 之类的东西来实现这样的功能?

感谢您提供任何帮助或分享任何相关资源。

django django-templates alpine.js
1个回答
0
投票

我这里也有类似的东西。它可能有也可能没有太大帮助。

https://github.com/tochy97/djangoAPI

我正在使用加载器根据路径需要调用每个 Js 内容。

https://github.com/tochy97/djangoAPI/blob/main/static/components/common/js/loader.js

index.js 充当一切的初始化程序。

https://github.com/tochy97/djangoAPI/blob/main/static/components/common/js/index.js

© www.soinside.com 2019 - 2024. All rights reserved.