如何防止脚本在局部视图中加载多次并在同一页面中多次使用局部时导致错误 [英] How to keep script in partial view from loading more than once and causing errors when partial is used more than once in the same page

查看:18
本文介绍了如何防止脚本在局部视图中加载多次并在同一页面中多次使用局部时导致错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 ASP.NET MVC 中工作时,我创建了一个在同一页面上呈现 2 次的局部视图.我的问题是 JavaScript 被包含的次数与局部视图一样多 并且 JavaScript 不喜欢重新定义类.

我的问题是:如何在局部视图中包含 JavaScript 以使其保持模块化,但只在页面中包含一次?我对需要将 .js 文件与局部视图的内容分开包含的解决方案不感兴趣,例如

@Html.Partial("some/partial.cshtml")@Html.Partial("some/partial.cshtml")

但是我可以使用包含在局部视图中的单独 .js 文件.局部视图应包含使其工作所需的一切.

我的代码结构如下:

<脚本>类我的类{构造函数(divName){this._divId = divId;}做一点事(){/* 对 id 为 divId 的元素进行处理 */}}

然后,在调用文件中,我有

@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })<脚本>$().ready(function(){id1Functionality = new MyClass("id_1");//请原谅糟糕的命名:-)id2Functionality = new MyClass("id_2");id1Functionality.doSomething();id2Functionality.doSomething();})

解决方案

一个解决方案是实现一个 Html helper 扩展函数,它只会加载一个脚本一次.见下文.(这也适用于 CSS 和其他包含的文件).

为 HtmlHelper 类和私有支持类实现一个扩展,作为每个 HttpContext 的单例.

public static class YourHtmlHelperExtensionClass{私有类 TagSrcAttrTracker{私人 TagSrcAttrTracker() { }公共字典<字符串,字符串>来源{得到;} = new Dictionary();公共静态 TagSrcAttrTrackerInstance {得到 {IDictionary items = HttpContext.Current.Items;const string instanceName = "YourClassInstanceNameMakeSureItIsUniqueInThisDictionary";if(!items.Contains(instanceName))items[instanceName] = new TagSrcAttrTracker();将 items[instanceName] 作为 TagSrcAttrTracker 返回;}}}公共静态 MvcHtmlString IncludeScriptOnlyOnce(这个 HtmlHelper 助手,字符串 urlOfScript){if(TagSrcAttrTracker.Instance.sources.ContainsKey(urlOfScript))返回空;TagSrcAttrTracker.Instance.sources[urlOfScript] = urlOfScript;TagBuilder script = new TagBuilder("script");scriptTag.MergeAttribute("src", urlOfScript);返回 MvcHtmlString.Create(script.ToString());}}

然后,将 JavaScript 和其他代码分离到单独的文件中.

示例 .js 文件内容

class MyClass{我的功能(){构造函数(divId){this._divId = divId}做一点事() {//用 id == divId 的 div 做一些事情}}}

部分视图的示例 .cshtml 文件内容

<div id="@ViewBag.id">一些内容!耶!

@Html.IncludeScriptOnlyOnce("/Scripts/CustomScripts/MyPartialView.js")

使用局部视图的示例 .cshtml 文件

<代码>...<身体><h1>这是一些内容!</h1>@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })@Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_3"} })<脚本>$(). 准备好(const id1Functionality = new MyClass("id_1")//原谅糟糕的命名 :-)const id2Functionality = new MyClass("id_3")const id3Functionality = new MyClass("id_2")id1Functionality.doSomething();id2Functionality.doSomething();id3Functionality.doSomething();)

局部视图可能被多次包含,JavaScript 与局部视图一起打包,但 .js 文件只包含在页面中一次,因此浏览器不会抱怨 MyClass 被多次声明.

Working in ASP.NET MVC, I created a partial view which is rendered on the same page 2 times. My problem is the JavaScript is included as many times as the partial view is and JavaScript does not like classes to be redefined.

My question is: How do I include the JavaScript in the partial view so it remains modular, but only have it included in the page once? I am not interested in solutions which require including the .js file separately from the content of the partial view, like

<script src="some.js"></script>
@Html.Partial("some/partial.cshtml")
@Html.Partial("some/partial.cshtml")

but I am okay with a separate .js file that is included inside the partial view. The partial view should include within it everything that is needed to make it work.

My code is structured something like this:

<div id=@ViewBag.id></div>
<script>
    class MyClass{ 
        constructor(divName){
            this._divId = divId;
        }

        doSomething(){
            /* do stuff with element that has id of divId */ 
        }
    }
</script>

Then, in the calling file, I have

<body>
    @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
    @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
</body>
<script>
    $().ready(function(){
        id1Functionality = new MyClass("id_1"); // please forgive the poor naming :-)
        id2Functionality = new MyClass("id_2");

        id1Functionality.doSomething();
        id2Functionality.doSomething();
    })
</script>

解决方案

One solution is to implement an Html helper extension function which will only load a script once. See below. (this can work for CSS and other included files, too).

Implement an extension for the HtmlHelper class and a private backing class as a singleton per HttpContext.

public static class YourHtmlHelperExtensionClass 
{
    private class TagSrcAttrTracker
    {
        private TagSrcAttrTracker() { }

        public Dictionary<string, string> sources { get; } = new Dictionary<string, string>();

        public static TagSrcAttrTrackerInstance {
            get {
                IDictionary items = HttpContext.Current.Items;
                const string instanceName = "YourClassInstanceNameMakeSureItIsUniqueInThisDictionary";

                if(!items.Contains(instanceName)) 
                    items[instanceName] = new TagSrcAttrTracker();

                return items[instanceName] as TagSrcAttrTracker;
            }
        }
    }

    public static MvcHtmlString IncludeScriptOnlyOnce(this HtmlHelper helper, string urlOfScript) 
    {
        if(TagSrcAttrTracker.Instance.sources.ContainsKey(urlOfScript))
            return null;

        TagSrcAttrTracker.Instance.sources[urlOfScript] = urlOfScript;

        TagBuilder script = new TagBuilder("script");
        scriptTag.MergeAttribute("src", urlOfScript);

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

Then, separate the JavaScript and other code into separate files.

Example .js file contents

class MyClass{
    myFunction() {
        constructor(divId){
            this._divId = divId
        }

        doSomething() {
            // do something with a div with id == divId
        }
    }
}

Example .cshtml file contents for partial view

<link rel="stylesheet" type="text/css" href="~/Content/CustomCSS/MyPartialView.css"/>

<div id="@ViewBag.id">
    Some content!  Yay!
</div>

@Html.IncludeScriptOnlyOnce("/Scripts/CustomScripts/MyPartialView.js")

Example .cshtml file that consumes the partial view

...
<body>
    <h1>Here is some content!</h1>
    @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_1"} })
    @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_2"} })
    @Html.Partial("/Views/MyPartial.cshtml", new ViewDataDictionary() { { "id", "id_3"} })
</body>
<script>
$().ready(
    const id1Functionality = new MyClass("id_1") // forgive the poor naming :-)
    const id2Functionality = new MyClass("id_3")
    const id3Functionality = new MyClass("id_2")

    id1Functionality.doSomething();
    id2Functionality.doSomething();
    id3Functionality.doSomething();
)
</script>

The partial view may have been included more than once and the JavaScript is packaged with the partial view, but the .js file is only included in the page once, hence no complaining by the browser that MyClass was declared more than once.

这篇关于如何防止脚本在局部视图中加载多次并在同一页面中多次使用局部时导致错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆