Populate a Razor Section From a Partial

前端 未结 12 1502
不知归路
不知归路 2020-11-27 11:23

My main motivation for trying to do this is to get Javascript that is only required by a partial at the bottom of the page with the rest of the Javascript and not in the mid

12条回答
  •  清酒与你
    2020-11-27 11:58

    [Updated version] Updated version following @Necrocubus question to Include inline scripts.

    public static class ScriptsExtensions
    {
        const string REQ_SCRIPT = "RequiredScript";
        const string REQ_INLINESCRIPT = "RequiredInlineScript";
        const string REQ_STYLE = "RequiredStyle";
    
        #region Scripts
        /// 
        /// Adds a script 
        /// 
        /// 
        /// 
        /// Ordered by decreasing priority 
        /// 
        /// 
        /// 
        public static string RequireScript(this IHtmlHelper html, string path, int priority = 1, bool bottom=false, params string[] options)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_SCRIPT] as List;
            if (requiredScripts == null) ctxt.Items[REQ_SCRIPT] = requiredScripts = new List();
            if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceToInclude() { Path = path, Priority = priority, Options = options, Type=ResourceType.Script, Bottom=bottom});
            return null;
        }
    
        /// 
        /// 
        /// 
        /// 
        /// 
        /// Ordered by decreasing priority 
        /// 
        /// 
        public static string RequireInlineScript(this IHtmlHelper html, string script, int priority = 1, bool bottom = false)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_INLINESCRIPT] as List;
            if (requiredScripts == null) ctxt.Items[REQ_INLINESCRIPT] = requiredScripts = new List();
            requiredScripts.Add(new InlineResource() { Content=script, Priority = priority, Bottom=bottom, Type=ResourceType.Script});
            return null;
        }
    
        /// 
        /// Just call @Html.EmitRequiredScripts(false)
        /// at the end of your head tag and 
        /// @Html.EmitRequiredScripts(true) at the end of the body if some scripts are set to be at the bottom.
        /// 
        public static HtmlString EmitRequiredScripts(this IHtmlHelper html, bool bottom)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_SCRIPT] as List;
            var requiredInlineScripts = ctxt.Items[REQ_INLINESCRIPT] as List;
            var scripts = new List();
            scripts.AddRange(requiredScripts ?? new List());
            scripts.AddRange(requiredInlineScripts ?? new List());
            if (scripts.Count==0) return null;
            StringBuilder sb = new StringBuilder();
            foreach (var item in scripts.Where(s=>s.Bottom==bottom).OrderByDescending(i => i.Priority))
            {
                sb.Append(item.ToString());
            }
            return new HtmlString(sb.ToString());
        }
        #endregion Scripts
    
        #region Styles
        /// 
        /// 
        /// 
        /// 
        /// 
        /// Ordered by decreasing priority 
        /// 
        /// 
        public static string RequireStyle(this IHtmlHelper html, string path, int priority = 1, params string[] options)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_STYLE] as List;
            if (requiredScripts == null) ctxt.Items[REQ_STYLE] = requiredScripts = new List();
            if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceToInclude() { Path = path, Priority = priority, Options = options });
            return null;
        }
    
        /// 
        /// Just call @Html.EmitRequiredStyles()
        /// at the end of your head tag
        /// 
        public static HtmlString EmitRequiredStyles(this IHtmlHelper html)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_STYLE] as List;
            if (requiredScripts == null) return null;
            StringBuilder sb = new StringBuilder();
            foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
            {
                sb.Append(item.ToString());
            }
            return new HtmlString(sb.ToString());
        }
        #endregion Styles
    
        #region Models
        public class InlineResource : Resource
        {
            public string Content { get; set; }
            public override string ToString()
            {
                return "";
            }
        }
    
        public class ResourceToInclude : Resource
        {
            public string Path { get; set; }
            public string[] Options { get; set; }
            public override string ToString()
            {
                switch(Type)
                {
                    case ResourceType.CSS:
                        if (Options == null || Options.Length == 0)
                            return String.Format("\n", Path);
                        else
                            return String.Format("\n", Path, String.Join(" ", Options));
                    default:
                    case ResourceType.Script:
                        if (Options == null || Options.Length == 0)
                            return String.Format("\n", Path);
                        else
                            return String.Format("\n", Path, String.Join(" ", Options));
                }
            }
        }
        public class Resource
        {
            public ResourceType Type { get; set; }
            public int Priority { get; set; }
            public bool Bottom { get; set; }
        }
        public enum ResourceType
        {
            Script,
            CSS
        }
        #endregion Models
    }
    

    My 2 cents, it is an old post, but still relevant, so here is an upgraded update of Mr Bell's solution which works with ASP.Net Core.

    It allows adding scripts and styles to the main layout from imported partial views and subviews, and possibility to add options to script/style imports (like async defer etc):

    public static class ScriptsExtensions
    {
        const string REQ_SCRIPT = "RequiredScript";
        const string REQ_STYLE = "RequiredStyle";
    
        public static string RequireScript(this IHtmlHelper html, string path, int priority = 1, params string[] options)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_SCRIPT] as List;
            if (requiredScripts == null) ctxt.Items[REQ_SCRIPT] = requiredScripts = new List();
            if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority, Options = options });
            return null;
        }
    
    
        public static HtmlString EmitRequiredScripts(this IHtmlHelper html)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_SCRIPT] as List;
            if (requiredScripts == null) return null;
            StringBuilder sb = new StringBuilder();
            foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
            {
                if (item.Options == null || item.Options.Length == 0)
                    sb.AppendFormat("\n", item.Path);
                else
                    sb.AppendFormat("\n", item.Path, String.Join(" ", item.Options));
    
            }
            return new HtmlString(sb.ToString());
        }
    
    
        public static string RequireStyle(this IHtmlHelper html, string path, int priority = 1, params string[] options)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_STYLE] as List;
            if (requiredScripts == null) ctxt.Items[REQ_STYLE] = requiredScripts = new List();
            if (!requiredScripts.Any(i => i.Path == path)) requiredScripts.Add(new ResourceInclude() { Path = path, Priority = priority, Options = options });
            return null;
        }
    
    
        public static HtmlString EmitRequiredStyles(this IHtmlHelper html)
        {
            var ctxt = html.ViewContext.HttpContext;
    
            var requiredScripts = ctxt.Items[REQ_STYLE] as List;
            if (requiredScripts == null) return null;
            StringBuilder sb = new StringBuilder();
            foreach (var item in requiredScripts.OrderByDescending(i => i.Priority))
            {
                if (item.Options == null || item.Options.Length == 0)
                    sb.AppendFormat("\n", item.Path);
                else
                    sb.AppendFormat("\n", item.Path, String.Join(" ", item.Options));
            }
            return new HtmlString(sb.ToString());
        }
    
    
        public class ResourceInclude
        {
            public string Path { get; set; }
            public int Priority { get; set; }
            public string[] Options { get; set; }
        }
    }
    

提交回复
热议问题