在 Django 包中添加对 Alpine.js 的支持

Posted

技术标签:

【中文标题】在 Django 包中添加对 Alpine.js 的支持【英文标题】:Adding support for Alpine.js to a Django package 【发布时间】:2021-11-09 18:04:32 【问题描述】:

我正在使用一个包,它添加了一个 SVG 模板标签,以便在我的 Django 模板中内联我的 SVG。我分叉了该项目并添加了对将 html 属性传递给 SVG 的支持。所以,现在我可以像下面这样使用它:

    % load svg %

    <a class="font-semibold text-gray-850 href="#0">
       % svg 'icon-chevron-down' class="inline -mb-0.5 w-4 h-4 ml-0.5 transition-transform duration-200 transform fill-current text-gray-400" %
    </a>

但是当我想在 svg 中使用 Alpine.js 时遇到了问题。我希望能够做这样的事情:

% svg 'icon-chevron-down' :class="'rotate-180': open, 'rotate-0': !open" class="inline -mb-0.5 w-4 h-4 ml-0.5 transition-transform duration-200 transform fill-current text-gray-400" %

我怎样才能让它工作?

我的包裹的回购: https://github.com/xshapira/django-simple-svg

svg.py

from __future__ import absolute_import
import logging
import os

from django import template
from django.conf import settings
from django.contrib.staticfiles import finders
from django.core.exceptions import ImproperlyConfigured
from django.utils.safestring import mark_safe

from simple_svg.exceptions import SVGNotFound

logger = logging.getLogger(__name__)
register = template.Library()


@register.simple_tag
def svg(filename, *args, **kwargs):
    SVG_DIRS = getattr(settings, "SVG_DIRS", [])

    if type(SVG_DIRS) != list:
        raise ImproperlyConfigured("SVG_DIRS setting must be a list")

    path = None

    if SVG_DIRS:
        for directory in SVG_DIRS:
            svg_path = os.path.join(
                directory, "filename.svg".format(filename=filename)
            )

            if os.path.isfile(svg_path):
                path = svg_path
    else:
        path = finders.find(
            os.path.join("svg", "filename.svg".format(filename=filename)), all=True
        )

    if not path:
        message = "SVG 'filename.svg' not found".format(filename=filename)

        # Raise exception if DEBUG is True, else just log a warning.
        if settings.DEBUG:
            raise SVGNotFound(message)
        else:
            logger.warning(message)
            return ""

    # Sometimes path can be a list/tuple if there's more than one file found
    if isinstance(path, (list, tuple)):
        path = path[0]

    with open(path) as svg_file:
        svg = svg_file.read()

    if kwargs:
        attributes = " ".join(['=""'.format(k, v) for k, v in kwargs.items()])
        svg = svg.replace("<svg", "<svg " + attributes)

    svg = mark_safe(svg)

    return svg

tests.py

import os
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.template import Context, Template
from django.test.testcases import SimpleTestCase

from simple_svg.exceptions import SVGNotFound


def test_should_support_attributes(self):
        svg_file = open(
            os.path.join(settings.BASE_DIR, "static", "svg", "django.svg")
        ).read()
        template = Template("% load svg %% svg 'django' id='logo' class='large' %")

        self.assertNotEqual(svg_file, template.render(Context()))
        self.assertIn('id="logo"', template.render(Context()))
        self.assertIn('class="large"', template.render(Context()))

【问题讨论】:

【参考方案1】:

一个简单的解决方案

我找到了一种更好的方法,无需更改 Django 包中的任何内容。我们可以简单地用div 包装svg 标记并将类和Alpine.js 表达式应用于它。这是一个例子:

<div :class="'rotate-180': open, 'rotate-0': !open" class="inline -mb-0.5 w-4 h-4 ml-0.5 transition-transform duration-200 transform fill-current text-gray-400">
  % svg 'icon-chevron-down' %
</div>

【讨论】:

以上是关于在 Django 包中添加对 Alpine.js 的支持的主要内容,如果未能解决你的问题,请参考以下文章

Alpine.js - 嵌套组件

如何在 TailwindCSS 和 Alpine.js 中构建没有重复标签内容的响应式手风琴标签?

在 Alpine.js 中将类绑定到 $el.value

[译] Vue.js 和 Alpine.js 比较

如何通过使用alpine js单击一个复选框来选中和取消选中所有复选框

在 alpine.js 中结合 x-show 和 x-text 切换