2013-02-08 76 views
14

我試圖呈現一組css文件,但輸出順序錯誤。我試過解決方案@MVC4 Beta Minification and Bundling: Ordering files and debugging in browser,但它沒有幫助。這裏是捆綁:MVC4 StyleBundle不以正確的順序呈現該分組

bundles.Add(new StyleBundle("~/stylesheet") 
    .Include("~/css/main.css") 
    .Include("~/css/mvc.css") 
    .Include("~/js/jquery.thickbox.css") 
    .Include("~/js/jquery.rating.css") 
    .Include("~/css/ProductListing.css") 
    .Include("~/css/dropdown/dropdown.css") 
    .Include("~/css/dropdown/dropdown.vertical.css") 
    .Include("~/js/fancybox/jquery.fancybox-1.3.1.css") 
    .Include("~/css/scartpopup.css") 
    .Include("~/css/ShoppingCart.css") 
    .Include("~/css/ceebox.css") 
    .Include("~/css/tooltip.css") 
    .Include("~/css/recent_blog_posts.css") 
    .Include("~/css/ProductDetail.css") 
    .Include("~/css/jquery-ui-1.7.3.custom.css") 
    .Include("~/css/filter_box.css") 
    .Include("~/css/custom_page.css") 
    .Include("~/css/Checkout.css") 
    .Include("~/css/CheckoutButton.css") 
); 

而這裏是結果,你可以看到jquery-ui到達頂端。

<link href="/css/jquery-ui-1.7.3.custom.css" rel="stylesheet"/> 
<link href="/css/main.css" rel="stylesheet"/> 
<link href="/css/mvc.css" rel="stylesheet"/> 
<link href="/js/jquery.thickbox.css" rel="stylesheet"/> 
<link href="/js/jquery.rating.css" rel="stylesheet"/> 
<link href="/css/ProductListing.css" rel="stylesheet"/> 
<link href="/css/dropdown/dropdown.css" rel="stylesheet"/> 
<link href="/css/dropdown/dropdown.vertical.css" rel="stylesheet"/> 
<link href="/js/fancybox/jquery.fancybox-1.3.1.css" rel="stylesheet"/> 
<link href="/css/scartpopup.css" rel="stylesheet"/> 
<link href="/css/ShoppingCart.css" rel="stylesheet"/> 
<link href="/css/ceebox.css" rel="stylesheet"/> 
<link href="/css/tooltip.css" rel="stylesheet"/> 
<link href="/css/recent_blog_posts.css" rel="stylesheet"/> 
<link href="/css/ProductDetail.css" rel="stylesheet"/> 
<link href="/css/filter_box.css" rel="stylesheet"/> 
<link href="/css/custom_page.css" rel="stylesheet"/> 
<link href="/css/Checkout.css" rel="stylesheet"/> 
<link href="/css/CheckoutButton.css" rel="stylesheet"/> 

如何確保樣式表按正確的順序呈現?

+0

我已經有過這種情況,當我有多個包中引用特定的CSS或直接將它包含在_Layout.cshtml中時。 – da7rutrak 2013-02-08 15:38:11

+0

它不在多個包中引用。必須把它放在_layout.cshtml中,它用在所有頁面中。奇怪的是,如果我將文件重命名爲其他內容,如jqui.css,問題就會消失。 – 2013-02-08 15:44:08

+0

我的意思是你直接在_Layout.cshtml中引用了CSS文件,並不是說你必須在文件中包含這個包。 – da7rutrak 2013-02-08 15:46:37

回答

21

捆綁不應該按照完全相同的順序呈現CSS文件,它遵循不同的邏輯。如果你需要使它們的定義,那麼你應該創建一個自定義IBundleOrderer並將其設置爲捆綁的要求訂貨:

public class AsDefinedBundleOrderer : IBundleOrderer 
{ 
    public IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files) 
    { 
     return files; 
    } 
} 

而且

var bundle = new StyleBundle("~/stylesheet"); 
bundle.Orderer = new AsDefinedBundleOrderer(); 
bundles.Add(bundle); 

,那麼這將做什麼用列表所以渲染將完全按照相同的順序渲染它們。在默認的排序

捆綁

更新使用的IBundleOrderer概念提升到一個Bundle內的項目進行排序。 的Bundle類都有它Orderer屬性,它看起來是這樣的:

public IBundleOrderer Orderer 
{ 
    get 
    { 
    if (this._orderer == null) 
     return (IBundleOrderer) DefaultBundleOrderer.Instance; 
    else 
     return this._orderer; 
    } 
    set 
    { 
    this._orderer = value; 
    this.InvalidateCacheEntries(); 
    } 
} 

所以默認訂貨實際上是一個DefaultBundleOrderer,直到你與你定製的訂貨覆蓋它。

IBundleOrderer具有以下特徵:

public interface IBundleOrderer 
{ 
    IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files); 
} 

DefaultBundleOrderer執行此訂單由BundleContext文件,這裏是從OrderFiles實施一個片段:

foreach (BundleFileSetOrdering ordering in (IEnumerable<BundleFileSetOrdering>) context.BundleCollection.FileSetOrderList) 
    DefaultBundleOrderer.AddOrderingFiles(ordering, (IEnumerable<FileInfo>) list, fileMap, foundFiles, result); 

所以不同結果發生,因爲這。這當然不是一個隨機排序算法:) 的規則在BUndleCollection類中定義:

public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list) 
{ 
    if (list == null) 
    throw new ArgumentNullException("list"); 
    BundleFileSetOrdering bundleFileSetOrdering1 = new BundleFileSetOrdering("css"); 
    bundleFileSetOrdering1.Files.Add("reset.css"); 
    bundleFileSetOrdering1.Files.Add("normalize.css"); 
    list.Add(bundleFileSetOrdering1); 
    BundleFileSetOrdering bundleFileSetOrdering2 = new BundleFileSetOrdering("jquery"); 
    bundleFileSetOrdering2.Files.Add("jquery.js"); 
    bundleFileSetOrdering2.Files.Add("jquery-min.js"); 
    bundleFileSetOrdering2.Files.Add("jquery-*"); 
    bundleFileSetOrdering2.Files.Add("jquery-ui*"); 
    bundleFileSetOrdering2.Files.Add("jquery.ui*"); 
    bundleFileSetOrdering2.Files.Add("jquery.unobtrusive*"); 
    bundleFileSetOrdering2.Files.Add("jquery.validate*"); 
    list.Add(bundleFileSetOrdering2); 
    BundleFileSetOrdering bundleFileSetOrdering3 = new BundleFileSetOrdering("modernizr"); 
    bundleFileSetOrdering3.Files.Add("modernizr-*"); 
    list.Add(bundleFileSetOrdering3); 
    BundleFileSetOrdering bundleFileSetOrdering4 = new BundleFileSetOrdering("dojo"); 
    bundleFileSetOrdering4.Files.Add("dojo.*"); 
    list.Add(bundleFileSetOrdering4); 
    BundleFileSetOrdering bundleFileSetOrdering5 = new BundleFileSetOrdering("moo"); 
    bundleFileSetOrdering5.Files.Add("mootools-core*"); 
    bundleFileSetOrdering5.Files.Add("mootools-*"); 
    list.Add(bundleFileSetOrdering5); 
    BundleFileSetOrdering bundleFileSetOrdering6 = new BundleFileSetOrdering("prototype"); 
    bundleFileSetOrdering6.Files.Add("prototype.js"); 
    bundleFileSetOrdering6.Files.Add("prototype-*"); 
    bundleFileSetOrdering6.Files.Add("scriptaculous-*"); 
    list.Add(bundleFileSetOrdering6); 
    BundleFileSetOrdering bundleFileSetOrdering7 = new BundleFileSetOrdering("ext"); 
    bundleFileSetOrdering7.Files.Add("ext.js"); 
    bundleFileSetOrdering7.Files.Add("ext-*"); 
    list.Add(bundleFileSetOrdering7); 
} 

所以,當你從Application_Start稱之爲:

BundleConfig.RegisterBundles(BundleTable.Bundles); 

其實你通過定義的默認BundleCollection在圖書館。

所以我們有BundleFileSetOrdering情況下,通過一個接一個到:

private static void AddOrderingFiles(BundleFileSetOrdering ordering, IEnumerable<FileInfo> files, Dictionary<string, HashSet<FileInfo>> fileMap, HashSet<FileInfo> foundFiles, List<FileInfo> result) 
{ 
    foreach (string key in (IEnumerable<string>) ordering.Files) 
    { 
    if (key.EndsWith("*", StringComparison.OrdinalIgnoreCase)) 
    { 
     string str = key.Substring(0, key.Length - 1); 
     foreach (FileInfo fileInfo in files) 
     { 
     if (!foundFiles.Contains(fileInfo) && fileInfo.Name.StartsWith(str, StringComparison.OrdinalIgnoreCase)) 
     { 
      result.Add(fileInfo); 
      foundFiles.Add(fileInfo); 
     } 
     } 
    } 
    else if (fileMap.ContainsKey(key)) 
    { 
     List<FileInfo> list = new List<FileInfo>((IEnumerable<FileInfo>) fileMap[key]); 
     list.Sort((IComparer<FileInfo>) FileInfoComparer.Instance); 
     foreach (FileInfo fileInfo in list) 
     { 
     if (!foundFiles.Contains(fileInfo)) 
     { 
      result.Add(fileInfo); 
      foundFiles.Add(fileInfo); 
     } 
     } 
    } 
    } 
} 

結論

如果我們要簡化程序,我們可以說,圖書館更喜歡某些類型的文件並在發現多種可能性時對其他文件進行一些排序。這是大多數情況下的預期行爲,但您可以看到它很容易被AsDefinedBundleOrderer覆蓋,因此它對給定的文件集沒有任何影響,因此順序仍然是原來的。

+0

完美,謝謝:) – 2013-02-08 15:49:47

+1

「捆綁不應該以完全相同的順序呈現CSS文件」。你從哪裏找到這些信息?我正在閱讀教程[這裏](http://www.asp.net/mvc/tutorials/mvc-4/bundling-and-minification),它使聽起來像首選的方法,以確保你得到正確的排序是按照您希望的順序顯式添加文件。 – bbak 2013-04-11 15:49:39

+0

爲了澄清,我遇到了同樣的問題,您的回答確實爲我解決了問題。我只想了解StyleBundles的排序是如何工作的以及爲什麼它的功能與ScriptBundles的排序不同。我的所有ScriptBundles都按我定義的方式排列文件,而無需使用自定義IBundleOrderer – bbak 2013-04-11 16:23:44