问题
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>
回答1:
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.
来源:https://stackoverflow.com/questions/62030856/how-to-keep-script-in-partial-view-from-loading-more-than-once-and-causing-error