如何包含部分但仅在尚未包含的情况下?

How to include a Partial but only if it wasn't yet included?

我使用 ASP.NET MVC5knockout.js。我有几个 knockout.js 模板,组织成局部视图。当我在视图或局部视图中有一个组件需要一个或多个特定模板时,我将相应的模板包含在 Html.Partial 中。但是,我需要解决一个问题:这样,如果一个组件本身是局部的,而我在一个视图中包含两个或多个组件,模板将被包含两次或更多次,这是不可取的。

我想实现的是,每当我需要包含部分模板时,我都不必担心它们是否已经包含在内。我可以在模板中包含相同的部分两次或三次,但最后,它只会在呈现的视图中出现一次。

这个问题有任何内置或第三方解决方案吗?

据我所知,Razor/partial 视图没有解决此问题的方法。

您应该看看 Knockout Components(在版本 3.2 中引入),它旨在解决这个问题。

Knockout 组件可以以多种方式呈现模板和 viewModel。模板和视图模型仅定义一次,并根据需要多次重复使用。

如果您使用像 requireJS 这样的模块加载器(Knockout 允许使用任何加载器),它还可以按需动态加载模板和脚本。组件也可以嵌套和重复使用。这应该能满足您的要求。

我遇到了类似的问题。我就是这样解决的。我不喜欢这个解决方案,但它确实有效。如果有更好的方法我很想听听。

public static class PartialExtension
    {
        public static void AddPartial(this HtmlHelper html, string partialLocation)
        {
            //Get a name for the template.  This is used to identify the template and
            //to ensure that a blank location has not been sent it.
            var partialName = Path.GetFileNameWithoutExtension(partialLocation);
            if (partialName == null)
                throw new Exception("The partial location can not be null");

            //Get the extension and directory.  If the location doesn't specify
            //a directory, like the location is in the current directory, then
            //we need to remove the extension.  Not sure why, but html.Partial()
            //throws an exception if you don't.
            var extension = Path.GetExtension(partialLocation);
            var dir = Path.GetDirectoryName(partialLocation);
            if (string.IsNullOrWhiteSpace(dir) && string.IsNullOrWhiteSpace(extension) == false)
                partialLocation = partialLocation.Replace(extension, "");

            var tmpBag = html.ViewBag;
            tmpBag.TbdTemplates = tmpBag.TbdTemplates as Dictionary<string, MvcHtmlString> ?? new Dictionary<string, MvcHtmlString>();

            //Only add this template once.
            if (((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates).ContainsKey(partialName)) return;

            //FYI: because html.Partial can call this recursively, we want to set the item in the dictionary
            //as soon as possible.  Then we call Partial().  The final call to that method will be what is 
            //set as the value in the dictionary.
            ((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates)[partialName] = MvcHtmlString.Create("");

            var tmpHtml = html.Partial(partialLocation, html.ViewData);
            ((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates)[partialName] = tmpHtml;
        }

        public static MvcHtmlString WritePartials(this HtmlHelper html)
        {
            var tmpBag = html.ViewBag;
            tmpBag.TbdTemplates = tmpBag.TbdTemplates as Dictionary<string, MvcHtmlString> ?? new Dictionary<string, MvcHtmlString>();

            if (tmpBag.TbdTemplates == null) return MvcHtmlString.Create("");

            var builder = new StringBuilder();
            foreach (var value in tmpBag.TbdTemplates.Values)
            {
                builder.Append(value);
            }

            return MvcHtmlString.Create(builder.ToString());
        }
    }

然后在我的_Layout.cshtml。 (向底部)

<div id="Partials" style="display: none;">
        @Html.WritePartials()
    </div>