2009-05-26 39 views
69

Tôi tự hỏi thực hành tốt nhất là bao gồm tệp javascript bên trong một phần lượt xem. Khi kết xuất này sẽ kết thúc dưới dạng thẻ js bao gồm ở giữa trang html của tôi. Theo quan điểm của tôi, đây không phải là cách hay để làm điều này. Chúng thuộc về thẻ head và như vậy không nên ngăn trình duyệt hiển thị html trong một lần.Bao gồm tệp JavaScript trong một phần lượt xem

Ví dụ: Tôi đang sử dụng plugin jquery picturegallery bên trong chế độ xem một phần 'PictureGallery' vì chế độ xem một phần này sẽ được sử dụng trên một số trang. Plugin này chỉ cần được tải khi chế độ xem này được sử dụng và Tôi không muốn phải biết plugin nào từng phần đang sử dụng ...

Cảm ơn câu trả lời của bạn.

+20

Cách tốt nhất là thực sự có javascript bao gồm ở cuối trang html, để tăng hiệu suất của trình duyệt trong khi hiển thị trang. –

+2

Tôi chưa bao giờ nghe về điều này ... Bạn có thể đưa ra một số nguồn để sao lưu tuyên bố này không? – Peter

+0

2Eduardo Scoz - Chính xác –

Trả lời

28

vẻ rất giống với câu hỏi này: Linking JavaScript Libraries in User Controls

tôi sẽ repost câu trả lời của tôi cho câu hỏi đó ở đây.

Tôi chắc chắn sẽ khuyên bạn không nên đặt chúng bên trong partials cho chính xác lý do bạn đề cập. Có khả năng cao là một lượt xem có thể kéo theo hai phần chia tách mà cả hai đều có tham chiếu đến cùng một tệp js. Bạn cũng đã đạt được hiệu suất của tải js trước khi tải phần còn lại của html.

Tôi không biết cách thực hành tốt nhất nhưng tôi chọn bao gồm bất kỳ tệp js phổ biến nào trong trang chủ và sau đó xác định một ContentPlaceHolder riêng cho một số tệp js bổ sung dành riêng cho một số lượt xem cụ thể hoặc nhỏ.

Đây là trang cái mẫu - nó khá tự giải thích.

<%@ 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 rõ ràng phần mở rộng của riêng tôi nhưng một lần nữa, họ tự giải thích trong những gì họ làm.

Sau đó, trong tiếng nói một cái nhìn SignUp.aspx tôi sẽ phải

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

HTHs, Charles

Ps. Dưới đây là một câu hỏi theo dõi tôi hỏi về rút gọn và concatenating file js: Concatenate & Minify JS on the fly OR at build time - ASP.NET MVC

EDIT: Theo yêu cầu về câu trả lời khác của tôi, thực hiện của tôi .JSBlock (a, b) theo yêu cầu

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); 
} 

Và sau đó, nơi sự kỳ diệu sẽ xảy ra ...

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); 
    } 
+0

Cảm ơn bạn đã giải thích chi tiết. Tối qua, tôi đã nghĩ về việc ghi đè trang cơ sở và thêm thuộc tính bộ sưu tập Scripts/Css mà sau đó sẽ được lấp đầy bởi một số trình trợ giúp html. Sau đó, trang sẽ nhổ chúng ra trong một trình giữ chỗ giống như của bạn. Điều này có tác dụng hay bạn sẽ tư vấn chống lại nó? – Peter

+0

Xin lỗi, tôi không làm theo ý bạn. "Ghi đè trang cơ sở" - Bạn có nghĩa là ghi đè System.Web.Mvc.Controller hoặc System.Web.Mvc.ViewPage hoặc chỉ cần tạo mô hình chế độ xem tùy chỉnh của riêng mình? "điền bởi một số htmlhelpers" Điều đó ném tôi quá ... nếu bạn đang sử dụng HtmlHelpers tùy chỉnh (từ bên trong một lần xem) sau đó chỉ cần sử dụng phương pháp ContentPlaceHolder đã đề cập ở trên. Nếu không có thêm thông tin tôi sẽ khuyên bạn chỉ cần làm theo các ví dụ trên vì nó là ... ngay cả với thông tin nhiều hơn tôi có lẽ vẫn sẽ tư vấn cho bạn để làm ở trên. ;-D – Charlino

+0

Tôi sẽ xem liệu tôi có thể làm một ví dụ làm việc vào cuối ngày và đăng nó ở đây như một câu trả lời, nếu nó hoạt động, tôi muốn có ý kiến. Tôi sẽ ghi đè ViewPage và thêm một thuộc tính có tên Scripts là một bộ sưu tập. Bên trong một khung nhìn một phần, sau đó bạn sẽ gọi một htmlhelper để thêm một tập lệnh Html.JSBlock ("path/to/script.js" new {some options}). Trình trợ giúp này thêm tập lệnh vào bộ sưu tập Tập lệnh của trang cha. Trong khung nhìn của trang cha mẹ, bên trong trình giữ chỗ, nó gọi một htmlhelper khác để hiển thị các thẻ script từ thuộc tính Scripts. Hay đó là thiết kế xấu? – Peter

-1

Các nhà thiết kế MVC đã gặp rất nhiều khó khăn để ngăn chúng tôi sử dụng mã nguồn, nhưng bằng cách tạo tệp có tên < viewname> .aspx.cs và sửa đổi thuộc tính kế thừa của trang aspx cho phù hợp, nó vẫn là có thể nhận được chúng.

Tôi muốn nói, địa điểm tốt nhất để đưa vào bao gồm trong trình xử lý Page_Load trong codebehind (sử dụng Page.ClientScript.RegisterClientScriptInclude).

+0

Cảm ơn bạn đã đề xuất nhưng tôi thực sự muốn gắn bó với mẫu và không sử dụng mã nguồn. Chắc chắn phải có những cách khác để hoàn thành điều này? – Peter

+0

Tại sao tôi bị bỏ phiếu? Tôi nghĩ rằng tôi đã nói rõ rằng tôi biết rằng nó phá vỡ các quy tắc, nhưng tôi có thể biện minh cho lý do tại sao tôi đã làm điều đó. Phá vỡ các quy tắc là OK nếu bạn biết những gì bạn đang làm. – erikkallen

+0

Bạn không thể gọi 'RegisterClientScriptInclude' từ tệp .aspx? Hay nó phải được gọi trong 'PageLoad'? –

0

Điều này có vẻ giống như một câu hỏi tương tự (mặc dù không hoàn toàn). Is it bad practice to return partial views that contain javascript?

+0

Tôi đã đọc toàn bộ bài đăng, nhưng nó không trả lời câu hỏi của tôi. Đặt tất cả trong một tập tin js sẽ là một cơn ác mộng hiệu suất như một số kịch bản (hoặc plugin nếu bạn sẽ) sẽ được tải ngay cả khi họ không được sử dụng. – Peter

0

Tùy chọn của tôi sẽ là tạo trang plugin.master kế thừa từ Site.master chính của bạn. Ý tưởng là bạn đưa các plugin này vào plugin.master và làm cho 8 trang trở lên sẽ sử dụng chế độ xem một phần này để kế thừa từ plugin.master.

+1

Tôi cảm nhận được cơn ác mộng quản lý. Mỗi lần tôi quyết định xóa hoặc thêm một plugin vào một chế độ xem, tôi cần phải thay đổi trang chủ? – Peter

+0

Bạn tạo ra âm thanh thừa kế đối tượng như một điều khủng khiếp. Cách tiếp cận ngây thơ của việc sử dụng chỉ một MasterPage cho toàn bộ trang web thực sự là một tận dụng tối đa sức mạnh và mục đích của MasterPages. Một trang web phức tạp trung bình thường có tối đa 4 trang Chính vì lý do chính đáng, một trong số đó là loại nhu cầu bạn hiện có. Phải có một lý do khác khiến nó nghe như một vấn đề với bạn. Và BTW, cụm từ, "Mỗi lần tôi cần ..." rõ ràng nhấn mạnh sự hiểu lầm của bạn về đề xuất này. Hãy thử và thử nghiệm trang web của bạn, việc nhóm các nội dung lại với nhau theo cách đó dễ dàng hơn. –

0

Cách tiếp cận ưa thích là put scripts at the bottom, tuy nhiên, nếu bạn không thể tránh điều đó thì bạn nên đặt chúng ở giữa.

Trình duyệt thường tải các phần tử trang khác nhau song song, trong khi trình duyệt đang tải xuống tệp Javascript, trình duyệt sẽ không tải xuống bất kỳ phần tử trang nào khác song song cho đến khi tải xong Javascript. Điều này có nghĩa rằng hình ảnh của bạn và những gì sẽ không phải chờ đợi vì vậy nó thường được coi là tốt hơn để di chuyển kịch bản ở phía dưới, nhưng nếu kịch bản của bạn là nhỏ thì tôi sẽ không lo lắng về nó.

1

lý do bạn sẽ đặt một kịch bản ở dưới cùng của trang này là để đảm bảo các dom đã được tải trước khi thực hiện bất kỳ Manip ulation. Điều này cũng có thể đạt được trong một cái gì đó giống như $ (tài liệu) .ready (gọi lại); Phương pháp jQuery.

Tôi chia sẻ chế độ xem không đưa JavaScript được nhúng vào html. Thay vào đó, tôi sử dụng một trình trợ giúp Html để tạo một div trống để sử dụng như một lệnh máy chủ. Các sig helper là Html.ServerData (String name, Object data);

Tôi sử dụng phương pháp ServerData này để được hướng dẫn từ máy chủ cho máy khách. Thẻ div giữ nó sạch sẽ và thuộc tính "data-" là html5 hợp lệ.

Đối với hướng dẫn loadScript tôi có thể làm điều gì đó như thế này trong ascx hoặc aspx của tôi:

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

Hoặc thêm một helper để làm điều này mà trông hơi bụi:

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

Sản lượng html sẽ là:

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

Sau đó, tôi có phương pháp jQuery có thể tìm thấy bất kỳ thẻ dữ liệu máy chủ nào: $ (containsElement) .serverData ("loadScript"); // trả về một mảng jQuery giống như các đối tượng json được giải mã.

Các khách hàng có thể tìm kiếm một cái gì đó như thế này:

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

Kỹ thuật này là rất tốt cho người dùng điều khiển hoặc các kịch bản đó cần phải được nạp vào trong nội dung ajax nạp. Phiên bản tôi viết có liên quan nhiều hơn đến việc xử lý các tập lệnh lưu vào bộ nhớ đệm để chúng chỉ tải một lần cho mỗi lần tải trang đầy đủ và chứa các lời gọi và trình kích hoạt jQuery để bạn có thể móc vào khi nó sẵn sàng.

Nếu có ai quan tâm đến phiên bản đầy đủ của điều này (từ phần mở rộng MVC đến jQuery), tôi sẽ vui lòng thể hiện kỹ thuật này chi tiết hơn. Nếu không - hy vọng nó sẽ mang lại cho ai đó một cách mới để tiếp cận vấn đề khó khăn này.

+0

Người đàn ông Tôi rất thích có một thức uống với bạn và nói chuyện này hơn :) Ý tưởng của bạn có vẻ thực sự tốt đẹp. Nó không giữ dữ liệu (giống như scriptpaths) trong codebehind, nhưng nó giữ chúng trong html chờ đợi để được tải bởi jquery. Thực tế là bạn đã cải thiện phương thức getScript sẽ chỉ tải cùng một tập lệnh một lần và thậm chí bạn có thể móc vào một trình chỉnh sửa! Các anh đào trên bánh sẽ được làm cho mã jquery tải các kịch bản, một chút minh bạch hơn vì vậy nó sẽ tự render ;-) Quá xấu, chúng tôi không thể thực sự sử dụng các bộ dữ liệu html5 chỉ được nêu ra, tuy nhiên, xem http: // tinyurl.com/2vfeunh – Peter

+0

Cảm ơn, tôi đồng ý. Tôi sử dụng phương thức như $ .scriptLoaded được sử dụng trên máy khách dưới dạng gọi lại. Nó cũng có một mảng tùy chọn phụ thuộc để tải. Kịch bản lệnh hoạt động tương tự cho các bảng định kiểu. Kỹ thuật máy chủData có thể được sử dụng để không chỉ tải tập lệnh - thực sự cho bất kỳ lệnh máy chủ nào cho máy khách. Tôi sử dụng nó để khởi tạo plugin cơ bản. Phương thức khách hàng truy xuất dữ liệu máy chủ sẽ loại bỏ phần tử đó khỏi dom sau khi lấy ra để giữ cho nó sạch sẽ. – jhorback

+0

Lý do để đặt chúng ở dưới cùng của trang không phải là để đảm bảo dom đã tải. Lý do là vì họ chặn tải xuống song song như được nêu rõ trong hướng dẫn của Yahoo. Việc đặt các tập lệnh ở cuối trang sẽ không đảm bảo rằng nhà quảng cáo đã tải đúng cách. – mattmanser

1

Hôm nay tôi đã tạo giải pháp của riêng mình phù hợp với hóa đơn một cách hoàn hảo. Cho dù đó là thiết kế tốt hay không, là dành cho bạn tất cả để quyết định nhưng nghĩ rằng tôi nên chia sẻ một trong hai cách!

Dưới đây là lớp HtmlExtensions của tôi mà cho phép bạn làm điều này trong masterpage của bạn:

<%=Html.RenderJScripts() %> 

HtmlExtensions My lớp:

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 

} 

là gì đang xảy ra?
Lớp ở trên sẽ mở rộng HtmlHelper bằng các phương pháp để thêm liên kết javascript vào bộ sưu tập đang được lưu trữ bởi bộ sưu tập HtmlHelper.ViewContext.TempData. Vào cuối trang chủ tôi đặt <%=Html.RenderJScripts() %> sẽ lặp lại bộ sưu tập jscripts bên trong HtmlHelper.ViewContext.TempData và hiển thị chúng cho đầu ra.

Tuy nhiên, có một nhược điểm, .. Bạn phải đảm bảo rằng bạn không hiển thị tập lệnh trước khi thêm chúng. Nếu bạn muốn làm điều này cho các liên kết css chẳng hạn, nó sẽ không hoạt động vì bạn phải đặt chúng trong thẻ <head> của trang của bạn và htmlhelper sẽ hiển thị đầu ra trước khi bạn thậm chí thêm một liên kết.

+1

Có phải tempdata là nơi thích hợp cho việc này không? Tôi tempdata là nơi lưu trữ dữ liệu sẽ tồn tại chuyển hướng. Tôi không nghĩ rằng bạn sẽ cần dữ liệu này trên bất kỳ yêu cầu trang tiếp theo nào –

+0

Điểm tốt, không phải vậy. Thực sự tò mò về những gì sẽ là một nơi tốt sau đó. – Peter

+0

Có vẻ như đây là tùy chọn tốt nhất, vì câu trả lời có nhiều phiếu bầu nhất không hoạt động trong chế độ xem một phần (asp: nội dung không được cho phép trong một phần lượt xem -> Kiểm soát nội dung phải là các điều khiển cấp cao nhất trong trang nội dung hoặc trang chủ lồng nhau tham chiếu đến trang cái.) Tuy nhiên, tôi muốn có chúng trong tiêu đề, nhưng chúng tôi cần một cơ chế đăng ký trước như trình quản lý tập lệnh ajax khủng khiếp cho điều đó. –

0

hejdig.

Chơi xung quanh với Aspnetmvc3 tôi quyết định, bây giờ, chỉ cần bao gồm tôi javascript tập tin trong phần

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

Tệp js này sau đó dành riêng cho tệp /user/List.schtml của tôi.

/OF

Các vấn đề liên quan