繁体   English   中英

在部分视图中包含 JavaScript 文件

[英]Include JavaScript file in partial views

我想知道在部分视图中包含 javascript 文件的最佳实践是什么。 一旦呈现,这将最终成为我页面 html 中间的一个 js 包含标记。 从我的角度来看,这不是一个很好的方法。 它们属于 head 标签,因此不应阻止浏览器一次性渲染 html。

一个例子:我在“PictureGallery”部分视图中使用了一个 jquery 图片库插件,因为这个部分视图将在几个页面上使用。 这个插件只需要在使用这个视图时加载,我不想知道每个局部视图正在使用哪些插件......

感谢您的回答。

似乎与这个问题非常相似: Linking JavaScript Libraries in User Controls

我会在这里重新发布我对那个问题的回答。

由于您提到的原因,我绝对建议不要将它们放入部分中。 一个视图很可能会引入两个都引用同一个 js 文件的部分。 在加载其余 html 之前,您还获得了加载 js 的性能影响。

我不知道最佳实践,但我选择在母版页中包含任何常见的 js 文件,然后为一些特定于特定或少量视图的其他 js 文件定义一个单独的 ContentPlaceHolder。

这是一个示例母版页 - 它是不言自明的。

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<head runat="server">
    ... BLAH ...
    <asp:ContentPlaceHolder ID="AdditionalHead" runat="server" />
    ... BLAH ...
    <%= Html.CSSBlock("/styles/site.css") %>
    <%= Html.CSSBlock("/styles/ie6.css", 6) %>
    <%= Html.CSSBlock("/styles/ie7.css", 7) %>
    <asp:ContentPlaceHolder ID="AdditionalCSS" runat="server" />
</head>
<body>
    ... BLAH ...
    <%= Html.JSBlock("/scripts/jquery-1.3.2.js", "/scripts/jquery-1.3.2.min.js") %>
    <%= Html.JSBlock("/scripts/global.js", "/scripts/global.min.js") %>
    <asp:ContentPlaceHolder ID="AdditionalJS" runat="server" />
</body>

Html.CSSBlock 和 Html.JSBlock 显然是我自己的扩展,但同样,它们的作用是不言自明的。

然后在说一个 SignUp.aspx 视图我会有

<asp:Content ID="signUpContent" ContentPlaceHolderID="AdditionalJS" runat="server">
    <%= Html.JSBlock("/scripts/pages/account.signup.js", "/scripts/pages/account.signup.min.js") %>
</asp:Content>

HTH,查尔斯

附言。 这是我询问的有关缩小和连接 js 文件的后续问题: 即时连接和缩小 JS 或在构建时 - ASP.NET MVC

编辑:根据我的其他答案的要求,我按要求实现 .JSBlock(a, b)

public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName)
{
    return html.JSBlock(fileName, string.Empty);
}

public static MvcHtmlString JSBlock(this HtmlHelper html, string fileName, string releaseFileName)
{
    if (string.IsNullOrEmpty(fileName))
        throw new ArgumentNullException("fileName");

    string jsTag = string.Format("<script type=\"text/javascript\" src=\"{0}\"></script>",
                                 html.MEDebugReleaseString(fileName, releaseFileName));

    return MvcHtmlString.Create(jsTag);
}

然后魔法发生的地方......

    public static MvcHtmlString MEDebugReleaseString(this HtmlHelper html, string debugString, string releaseString)
    {
        string toReturn = debugString;
#if DEBUG
#else
        if (!string.IsNullOrEmpty(releaseString))
            toReturn = releaseString;
#endif
        return MvcHtmlString.Create(toReturn);
    }

您将脚本放在页面底部的原因是确保在尝试任何操作之前已加载 dom。 这也可以通过 $(document).ready(callback); 之类的东西来实现。 jQuery 方法。

我同意不将嵌入式 JavaScript 放入 html 的观点。 相反,我使用 Html helper 创建一个空 div 用作服务器指令。 helper sig 是 Html.ServerData(String name, Object data);

我使用这个 ServerData 方法来获取从服务器到客户端的指令。 div 标签保持干净,“data-”属性是有效的 html5。

对于 loadScript 指令,我可以在 ascx 或 aspx 中做这样的事情:

<%= Html.ServerData("loadScript", new { url: "pathTo.js" }) %>

或者添加另一个助手来执行此操作,它看起来更简洁:

<%= Html.LoadScript("~/path/to.js") %>

html 输出将是:

<div name="loadScript" data-server="encoded json string">

然后我有一个 jQuery 方法可以找到任何服务器数据标签: $( containsElement).serverData("loadScript"); // 返回一个类似 jQuery 的解码 json 对象数组。

客户端可能看起来像这样:

var script = $(containingelement").serverData("loadScript");
$.getScript(script.url, function () {
    // script has been loaded - can do stuff with it now
});

这种技术非常适合需要在 ajax 加载内容中加载的用户控件或脚本。 我编写的版本涉及处理缓存脚本,因此它们在每个完整页面加载时只加载一次,并包含回调和 jQuery 触发器,因此您可以在它准备好时挂钩。

如果有人对此的完整版本(从 MVC 到 jQuery 扩展)感兴趣,我很乐意更详细地展示这种技术。 否则 - 希望它给某人一种解决这个棘手问题的新方法。

今天,我创建了自己的解决方案,完全符合要求。 设计好不好,由你们决定,但我认为我应该分享两种方式!

下面是我的 HtmlExtensions 类,它允许您在母版页中执行此操作:

<%=Html.RenderJScripts() %>

我的 HtmlExtensions 类:

public static class HtmlExtensions
{
    private const string JSCRIPT_VIEWDATA = "__js";

    #region Javascript Inclusions

    public static void JScript(this HtmlHelper html, string scriptLocation)
    {
        html.JScript(scriptLocation, string.Empty);
    }

    public static void JScript(this HtmlHelper html, string scriptLocationDebug, string scriptLocationRelease)
    {
        if (string.IsNullOrEmpty(scriptLocationDebug))
            throw new ArgumentNullException("fileName");

        string jsTag = "<script type=\"text/javascript\" src=\"{0}\"></script>";

#if DEBUG
        jsTag = string.Format(jsTag, scriptLocationDebug);
#else
        jsTag = string.Format(jsTag, !string.IsNullOrEmpty(scriptLocationRelease) ? scriptLocationRelease : scriptLocationDebug);
#endif

        registerJScript(html, jsTag);
    }

    public static MvcHtmlString RenderJScripts(this HtmlHelper html)
    {
        List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
        string result = string.Empty; ;
        if(jscripts != null)
        {
            result = string.Join("\r\n", jscripts);
        }
        return MvcHtmlString.Create(result);
    }

    private static void registerJScript(HtmlHelper html, string jsTag)
    {
        List<string> jscripts = html.ViewContext.TempData[JSCRIPT_VIEWDATA] as List<string>;
        if(jscripts == null) jscripts = new List<string>();

        if(!jscripts.Contains(jsTag))
            jscripts.Add(jsTag);

        html.ViewContext.TempData[JSCRIPT_VIEWDATA] = jscripts;
    }

    #endregion

}

到底是怎么回事?
上面的类将使用方法扩展 HtmlHelper,以将 javascript 链接添加到由HtmlHelper.ViewContext.TempData集合存储的集合。 <%=Html.RenderJScripts() %>的末尾,我放置了<%=Html.RenderJScripts() %> ,它将在HtmlHelper.ViewContext.TempData循环 jscripts 集合并将它们呈现到输出。

但是,有一个缺点,.. 您必须确保在添加脚本之前不渲染它们。 例如,如果您想对 css 链接执行此操作,则它不会起作用,因为您必须将它们放在页面的<head>标记中,并且 htmlhelper 会在您添加链接之前呈现输出。

海迪格

玩弄 Aspnetmvc3 我决定,现在,只将我的 javascript 文件包含在部分

<script src="@Url.Content("~/Scripts/User/List.js")" type="text/javascript"></script>

这个 js 文件特定于我的 /user/List.schtml 文件。

/的

所以,这是一个老问题,但我在尝试解决最近的问题时发现了它。 在这里问了一个问题并回答了它。 这是该答案的副本。 它类似于 OP 的答案,但避免使用 TempData。

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

为 HtmlHelper 类和私有支持类实现一个扩展作为每个 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());
    }
}

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

示例 .js 文件内容

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

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

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

<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")

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

...
<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>

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

这似乎是一个类似(尽管不完全)的问题。 返回包含 javascript 的部分视图是不好的做法吗?

我的偏好是创建一个从您的主 Site.master 继承的 plugin.master 页面。 这个想法是你把这些插件塞进 plugin.master 并制作 8 个左右的页面,这些页面将使用这个部分视图从 plugin.master 继承。

首选方法是将脚本放在底部,但是,如果您无法避免这种情况,那么将它们放在中间是合理的。

浏览器通常并行加载各种页面元素,但是,当浏览器正在下载 Javascript 文件时,它不会并行下载任何其他页面元素,直到 Javascript 下载完成。 这意味着您的图像和其他内容将不得不等待,因此通常认为将脚本移动到底部会更好,但如果您的脚本很小,那么我不会担心。

MVC的设计者费了好大劲才阻止我们使用code-behinds,但是通过创建一个名为<viewname>.aspx.cs的文件,并相应地修改aspx页面的inherits属性,还是可以得到的.

我想说,放置包含的最佳位置是代码隐藏中的 Page_Load 处理程序(使用 Page.ClientScript.RegisterClientScriptInclude)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM