图解 BootstrapBlazor 组件库的使用02:布局组件 Layout 的使用示例(示例使用 BootstrapBlazor 模板修改而成)

一、创建 .NET 8.0 的 Blazor Web App 项目,并引用 BootstrapBlazor

操作步骤参见“图解 BootstrapBlazor 组件库的使用01”:http://t.csdnimg.cn/jUhzR

二、在 Components 文件夹中创建 BBLayout 文件夹,并在此文件夹中保存 布局组件 Layout 的 7 个相关文件

图2-1:BBLayout 文件夹及 7 个相关文件

1.  菜单文件 BBLayoutMenu.cs:将菜单操作独立出来,方便后期更换菜单

using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components.Routing;

namespace BlazorWebAppWithBB.Components.BBLayout;

/// <summary>
/// 定义生成菜单的静态方法
/// </summary>
public class BBLayoutMenu
{
    /// <summary>
    /// 菜单全部折叠、展开
    /// </summary>
    /// <param name="menus"></param>
    /// <param name="ExpandAll"></param>
    private static void ExpandAllFun(List<MenuItem> menus, int ExpandAll)
    {
        if (ExpandAll == 1)
        {
            menus.ForEach(m => m.IsCollapsed = true);
        }
        if (ExpandAll == 2)
        {
            menus.ForEach(m => m.IsCollapsed = false);
        }
    }

    /// <summary>
    /// 获取测试菜单01
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<MenuItem> GetIconSideMenuItemsTest01(int ExpandAll)
    {
        return new List<MenuItem>
        {
            new () { Text = "Home", Icon = "fa-fw fa-solid fa-house", Url = "/" },
            new () { Text = "counter", Icon = "fa-fw fa-solid fa-desktop", Url = "/counter" },
            new () { Text = "weather", Icon = "fa-fw fa-solid fa-laptop", Url = "/weather" }
        };

    }

    /// <summary>
    /// 获取测试菜单02
    /// </summary>
    /// <returns></returns>
    public static IEnumerable<MenuItem> GetIconSideMenuItemsTest02(int ExpandAll)
    {
        var menus = new List<MenuItem>
        {
            new MenuItem() { Text = "Index", Icon = "fa-solid fa-fw fa-home", Url = "/" , Match = NavLinkMatch.All},
            new MenuItem("模板自带",icon:"fa-solid fa-fw fa-table")
            {
                Items=new List<MenuItem>
                {
                    new("counter","/counter","fa-solid fa-fw fa-check-square"),
                    new("weather","/weather","fa-solid fa-fw fa-database"),
                }
            },
            new MenuItem("一级菜单01",icon:"fa-solid fa-fw fa-flag")
            {
                Match = NavLinkMatch.All,
                Items=new List<MenuItem>
                {
                    new("二级菜单0101","/yj01/yj01ej01","fa-solid fa-fw fa-check-square")
                    {
                        Match=NavLinkMatch.All
                    },
                    new("二级菜单0102","/yj01/yj01ej02","fa-solid fa-fw fa-database"),
                    new("二级菜单0103","/yj01/yj01ej03","fa-solid fa-fw fa-database"),
                }
            },
            new MenuItem("一级菜单02",icon:"fa-solid fa-fw fa-table")
            {
                Items=new List<MenuItem>
                {
                    new("二级菜单0201","/yj02/yj02ej01","fa-solid fa-fw fa-check-square"),
                    new("二级菜单0202","/yj02/yj02ej02","fa-solid fa-fw fa-database"),
                    new("二级菜单0203","/yj02/yj02ej04","fa-solid fa-fw fa-database"),
                }
            },
            new MenuItem("一级菜单03", icon: "fas fa-dog")
            {
                Items=new List<MenuItem>
                {
                    new("二级菜单0301","/yj03/yj03ej01","fa-solid fa-fw fa-check-square"),
                    new("二级菜单0302","/yj03/yj03ej02","fa-solid fa-fw fa-database"),
                    new("二级菜单0303",icon: "fa-solid fa-fw fa-database")
                    {
                        Items=new List<MenuItem>
                        {

                            new("三级菜单030301" ,"/yj03/yj03ej03/yj03ej03sj01","fa-solid fa-fw fa-database"),
                            new("三级菜单030302" ,"/yj03/yj03ej03/yj03ej03sj02","fa-solid fa-fw fa-database"),
                            new("三级菜单030303" ,"/yj03/yj03ej03/yj03ej03sj03","fa-solid fa-fw fa-database"),
                        }
                    }
                }
            },
            new MenuItem("操作日志", "/czrz/rz01",icon: "fa-solid fa-fw fa-heart fa-beat"),
        };

        ExpandAllFun(menus, ExpandAll);

        return menus;

    }

}
代码2-1:菜单文件

2. 参数类 BBLayoutParameters.cs:将 Layout 的参数对象化,方便后期使用

namespace BlazorWebAppWithBB.Components.BBLayout;

public class BBLayoutParameters
{
    //打开抽屉
    public bool IsOpen { get; set; }

    //使用多标签
    public bool UseTabSet { get; set; } = true;

    //主题配色 名称
    public string Theme { get; set; } = "";

    //固定调整(不随滚动条滚动):固定页头、固定页脚、固定标签
    public bool IsFixedHeader { get; set; } = true;
    public bool IsFixedFooter { get; set; } = true;
    public bool IsFixedTab { get; set; }

    //布局调整:上下结构、左右结构(侧边栏是否占满整个左边)
    public bool IsFullSide { get; set; } = true;

    //显示页脚
    public bool ShowFooter { get; set; } = true;
    //显示返回顶端按钮(在页脚中)
    public bool ShowGotoTop { get; set; } = true;

    //显示收缩展开 Bar(收缩按钮)
    public bool ShowCollapseBar { get; set; } = true;

    //手风琴菜单
    public bool IsAccordion { get; set; } = true;

    //菜单全部折叠、展开
    public int ExpandAll { get; set; } = 0;

}
代码2-2:参数类文件

3. 抽屉组件 BBLayoutDrawer.razor(专用样式文件  BBLayoutDrawer.razor.css):将 Drawer 组件独立出来,方便后期使用

<Drawer Placement="Placement.Right" @bind-IsOpen="@LayoutParameters.IsOpen" IsBackdrop="true">
    <div class="layout-drawer-body">
        <div class="btn btn-info w-100" @onclick="@(e => LayoutParameters.IsOpen = false)">点击关闭</div>

        <GroupBox Title="布局调整">
            <div class="row">
                <div class="col-6">
                    <div class="layout-item @(LayoutParameters.IsFullSide ? "active d-flex" : "d-flex")" @onclick="@(async e =>{ LayoutParameters.IsFullSide = true;await UpdateParameters();})" data-toggle="tooltip" title="左右结构">
                        <div class="layout-left d-flex flex-column">
                            <div class="layout-left-header"></div>
                            <div class="layout-left-body flex-fill"></div>
                        </div>
                        <div class="layout-right d-flex flex-column flex-fill">
                            <div class="layout-right-header"></div>
                            <div class="layout-right-body flex-fill"></div>
                            <div class="layout-right-footer"></div>
                        </div>
                    </div>
                </div>
                <div class="col-6">
                    <div class="layout-item flex-column @(LayoutParameters.IsFullSide ? "d-flex" : "active d-flex")" @onclick="@(async e =>{ LayoutParameters.IsFullSide = false;await UpdateParameters();})" data-toggle="tooltip" title="上下结构">
                        <div class="layout-top">
                        </div>
                        <div class="layout-body d-flex flex-fill">
                            <div class="layout-left">
                            </div>
                            <div class="layout-right flex-fill">
                            </div>
                        </div>
                        <div class="layout-right-footer">
                        </div>
                    </div>
                </div>
            </div>
        </GroupBox>

        <GroupBox Title="固定调整">
            <div class="row">
                <div class="col-6 d-flex align-items-center">
                    <Switch IsDisabled="@(LayoutParameters.IsFixedTab)" @bind-Value="@LayoutParameters.IsFixedHeader" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Secondary" title="@fixTitle"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">固定页头</span>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col-6 d-flex align-items-center">
                    <Switch IsDisabled="@(!LayoutParameters.ShowFooter || LayoutParameters.IsFixedTab)" @bind-Value="@LayoutParameters.IsFixedFooter" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Secondary" title="@fixTitle"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">固定页脚</span>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col-6 d-flex align-items-center">
                    <Switch @bind-Value="@LayoutParameters.IsFixedTab" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">固定标签</span>
                </div>
            </div>
        </GroupBox>

        <GroupBox Title="显示设置">
            <div class="row">
                <div class="col-6 d-flex align-items-center">
                    <Switch IsDisabled="@(LayoutParameters.IsFixedTab)" @bind-Value="@LayoutParameters.ShowFooter" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Secondary" title=""></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">页脚</span>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col-6 d-flex align-items-center">
                    <Switch IsDisabled="@(!LayoutParameters.ShowFooter)" @bind-Value="@LayoutParameters.ShowGotoTop" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Secondary" title="该按钮默认位于在页脚中右侧"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">返回顶端按钮</span>
                </div>
            </div>
            <div class="row mt-3">
                <div class="col-6 d-flex align-items-center">
                    <Switch @bind-Value="@LayoutParameters.ShowCollapseBar" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">收缩按钮</span>
                </div>
            </div>
        </GroupBox>

        <GroupBox Title="主题配色">
            <div class="row">
                @for (int i = 0; i <= 5; i++)
                {
                    var current = i;
                    <div class="col-2">
                        <span class="color color@(i)"
                              @onclick="@(async e => {LayoutParameters.Theme = $"color{current}";await UpdateParameters();})">
                        </span>
                    </div>
                }
            </div>
        </GroupBox>

        <GroupBox Title="菜单设置">
            <div class="row">
                <div class="col-6 d-flex align-items-center">
                    <Switch @bind-Value="@LayoutParameters.IsAccordion" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
                </div>
                <div class="col-6 d-flex align-items-center justify-content-end">
                    <span class="cell-label bg-lightXXX">手风琴效果</span>
                </div>
            </div>
            <div class="row mt-3 d-flex justify-content-around">
                <Button IsDisabled="@(LayoutParameters.IsAccordion)" class="col-3" Size="Size.ExtraSmall" ButtonStyle="ButtonStyle.Round" Color="Color.Primary" OnClick="All02">全部展开</Button>
                <Button IsDisabled="@(LayoutParameters.IsAccordion)" class="col-3" Size="Size.ExtraSmall" ButtonStyle="ButtonStyle.Round" Color="Color.Primary" OnClick="All01">全部折叠</Button>
            </div>
        </GroupBox>

        <GroupBox Title="更多设置">
            <div class="row">
                <div class="col-6 d-flex align-items-center">
                    <Switch @bind-Value="@LayoutParameters.UseTabSet" @bind-Value:after="UpdateParameters" OnColor="@Color.Success" OffColor="@Color.Primary"></Switch>
                </div>
                <div class="col-6 text-right">
                    <span class="cell-label">@(LayoutParameters.UseTabSet ? "多标签" : "单页")</span>
                </div>
            </div>
        </GroupBox>
    </div>
</Drawer>

@code {
    string fixTitle = "固定标签时,默认固定页头、页脚";

    // 定义当前组件的“组件参数”,用于在父组件中使用  @bind-{PROPERTY} 将父组件中的“变量”绑定到本组件参数。
    // 使用 = new() 初始化,否则报 warning CS8618 非空警告。
    [Parameter]
    public BBLayoutParameters LayoutParameters { get; set; } = new();

    // 必须的:与“组件参数”配合使用,定义组件参数绑定事件,用于回传参数到父组件。
    // 事件命名语法:{PARAMETER NAME}Changed
    [Parameter]
    public EventCallback<BBLayoutParameters> LayoutParametersChanged { get; set; }

    // 响应组件中的事件,同时回传参数到父组件。
    private async Task UpdateParameters()
    {
        // 此处可以有当前组件的操作代码。
        // ......
        // 回传

        // System.Console.WriteLine(LayoutParameters.Theme);

        // 固定标签 时,必须固定 页头、页脚、显示页脚;
        // 不 显示页脚 时,固定页脚 选项不可用【<Switch IsDisabled="@(!LayoutParameters.ShowFooter)" 】;
        if (LayoutParameters.IsFixedTab)
        {
            LayoutParameters.IsFixedFooter = true;
            LayoutParameters.IsFixedHeader = true;
            LayoutParameters.ShowFooter = true;
        }
        // 目前,固定标签 时,返回顶端 无效:因为返回目标为 标签、此时顶端=标签??可能后面会修复 ??
        if (LayoutParameters.IsFixedTab)
        {
            LayoutParameters.ShowGotoTop = false;
        }

        if (LayoutParameters.IsAccordion)
        {
            LayoutParameters.ExpandAll = 0;
        }

        await LayoutParametersChanged.InvokeAsync(LayoutParameters);
    }

    // 全部展开、折叠
    private async void All01()
    {
        LayoutParameters.ExpandAll = 1;
        await UpdateParameters();
    }
    private async void All02()
    {
        LayoutParameters.ExpandAll = 2;
        await UpdateParameters();
    }


}
代码2-3:BBLayoutDrawer.razor 组件完整代码
.layout-drawer-body {
    padding: 1rem;
}

.layout-drawer-body ::deep .groupbox {
    margin-top: 1rem;
}

.layout-drawer-body ::deep .btn-info {
    margin-bottom: 1rem;
}

.cell-label {
    line-height: 35px;
}


.layout-item {
    /*--bb-layout-sidebar-bg: #f8f9fa;
    --bb-layout-footer-bg: #e9ecef;*/

    cursor: pointer;
    border: 2px solid #e9ecef;
    padding: 4px;
    border-radius: 4px;
    height: 80px;
    width: 120px;
    transition: border .3s linear;
}

    .layout-item:hover,
    .layout-item.active {
        border: 2px solid #28a745;
    }

    .layout-item .layout-left {
        width: 30%;
        /*border-right: 1px solid var(--bs-border-color);*/
    }

        .layout-item .layout-left .layout-left-header {
            height: 16px;
            /*background-color: var(--bb-header-bg);*/
            background-color: #367fa9;
        }

        .layout-item .layout-left .layout-left-body,
        .layout-item .layout-body .layout-left {
            /*background-color: var(--bb-layout-sidebar-bg);*/
            background-color: #2f4050;
        }

    .layout-item .layout-right .layout-right-header,
    .layout-item .layout-top {
        /*background-color: var(--bb-header-bg);*/
        background-color: #17a2b8;
        height: 16px;
    }

    .layout-item .layout-right .layout-right-footer,
    .layout-item .layout-right-footer {
        /*background-color: var(--bb-layout-footer-bg);*/
        background-color: #5b6e84;
        height: 12px;
    }

    .layout-item .layout-top,
    .layout-item .layout-body,
    .layout-item .layout-right-footer {
        width: 100%;
    }

/*原模板使用了 text-right 样式,但不存在,自己补写一个*/
.text-right {
    text-align: right;
}
代码2-4: BBLayoutDrawer.razor 组件专用样式文件

4. 布局文件 BBLayout.razor(专用样式文件 BBLayout.razor.css):作用等同于 MainLayout.razor,实现一个项目多种布局

@* 【BBLayout 使用方法】
    1.共涉及 7 个文件:
    BBLayout.razor            本组件
        BBLayout.razor.css
    BBLayoutDrawer.razor      抽屉组件
        BBLayoutDrawer.razor.css
    BBLayoutMenu.cs           获取菜单静态方法
    BBLayoutParameters.cs     参数类
    BBLayout.css              修改默认样式值

    2.在 Layout 组件中
    (1)定义参数对象
        private BBLayoutParameters layoutParameters = new BBLayoutParameters();
    (2)右侧抽屉,初始不显示
        <BBLayoutDrawer @bind-LayoutParameters="layoutParameters" />
    (3)单击显示右侧抽屉
        <div class="layout-drawer" @onclick="@(e => layoutParameters.IsOpen = !layoutParameters.IsOpen)"><i class="fa fa-gears"></i></div>

    3.在 App.razor 中
        <link rel="stylesheet" href="BBLayout.css" />

问题1:固定标签 时,返回顶端 无效 ??

注1:使用“多标签”时,全部标签关闭,默认显示 TabDefaultUrl 的标签;
     此时要求,TabDefaultUrl 要明确指定 Text、Icon 属性,否则标签的文本、图标会显示错误。
     TabDefaultUrl 的属性指定示例代码如下所示。
     @attribute [TabItemOption(Text = "Home", Icon = "fa-fw fa-solid fa-house")]


问题2:增加 以下两个参数的设置 ???
     SideWidth="0" IsPage="true"

*@


@inherits LayoutComponentBase

<BootstrapBlazorRoot>
    <Layout SideWidth="0" IsPage="true" AdditionalAssemblies="new[] { GetType().Assembly }"
            UseTabSet="@layoutParameters.UseTabSet"
            IsFixedHeader="@layoutParameters.IsFixedHeader"
            IsFixedFooter="@layoutParameters.IsFixedFooter"
            IsFullSide="@layoutParameters.IsFullSide"
            ShowFooter="@layoutParameters.ShowFooter"
            ShowGotoTop="@layoutParameters.ShowGotoTop"
            ShowCollapseBar="@layoutParameters.ShowCollapseBar"
            IsAccordion="@layoutParameters.IsAccordion"
            class="@LayoutClassString"
            Menus="@(BBLayoutMenu.GetIconSideMenuItemsTest01(layoutParameters.ExpandAll))"
            TabDefaultUrl="/">
        <Header>
            <span class="ms-3 flex-sm-fill d-none d-md-block">Blazor Web App 模板引用 BootstrapBlazor</span>
            <div class="ms-2 flex-fill d-md-none">项目简称</div>
            <span class="mx-3 d-none d-lg-block">实时提示信息</span>
            <span class="mx-3 d-none d-sm-block">登录用户名</span>
            <span class="mx-3 d-none d-lg-block">
                <Logout ImageUrl="favicon.png" DisplayName="超级管理员" UserName="Admin">
                    <LinkTemplate>
                        <a href="#"><i class="fa-solid fa-suitcase"></i>个人中心</a>
                        <a href="#"><i class="fa-solid fa-cog"></i>设置</a>
                        <a href="#"><i class="fa-solid fa-bell"></i>通知<span class="badge badge-pill badge-success"></span></a>
                        <LogoutLink />
                    </LinkTemplate>
                </Logout>
            </span>
            @* 单击显示右侧抽屉 *@
            <div class="layout-drawer" @onclick="@(e => layoutParameters.IsOpen = !layoutParameters.IsOpen)"><i class="fa fa-gears"></i></div>
        </Header>
        <Side>
            <div class="layout-banner">
                <img alt="logo" class="layout-logo" src="favicon.png" />
                <div class="layout-title">
                    <span>项目名称</span>
                </div>
            </div>
        </Side>
        <Main>
            <CascadingValue Value="this" IsFixed="true">
                @Body
            </CascadingValue>
        </Main>
        <Footer>
            <div class="text-center flex-fill">
                <a class="layout-footer-gray" target="_blank" href="">版权说明、使用说明</a>
            </div>
        </Footer>
        @* Blazor Web App 模式中弃用
        <NotFound>
            <p>Sorry, there's nothing at this address.</p>
        </NotFound> *@
    </Layout>

    @* 右侧抽屉,初始不显示 *@
    <BBLayoutDrawer @bind-LayoutParameters="layoutParameters" />
</BootstrapBlazorRoot>

<div id="blazor-error-ui">
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

@code {
    // 定义参数对象
    private BBLayoutParameters layoutParameters = new BBLayoutParameters();

    // 设置 IsFixedTab
    private string? LayoutClassString => CssBuilder.Default()
    .AddClass(layoutParameters.Theme)
    .AddClass("is-fixed-tab", layoutParameters.IsFixedTab)
    .Build();

    /* 获取菜单
    方法2:新方法,直接使用静态方法获取,使得菜单独立出去,示例如下。
    Menus="@(BBLayoutMenu.GetIconSideMenuItemsTest01(layoutParameters.ExpandAll))"
     
    方法1:定义 Menus,使用示例:<Layout Menus="Menus"></Layout>
    private IEnumerable<MenuItem>? Menus { get; set; }
    // 初始化时读取 菜单
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        Menus = BBLayoutMenu.GetIconSideMenuItemsTest01(layoutParameters.ExpandAll);
    }
    */

}
代码2-5:布局组件 Layout 完整代码
.layout-drawer {
    padding: 13px;
    margin-right: -1rem;
    cursor: pointer;
}

    .layout-drawer:hover {
        background-color: #1893a7;
    }

.layout-banner {
    border-bottom: 1px solid var(--bs-border-color);
}

    .layout-banner .layout-logo {
        border: 1px solid var(--bb-header-color);
    }


/*设置footor颜色*/
.layout-footer-gray {
    color: gray;
    cursor: pointer;
}

    .layout-footer-gray:hover {
        color: dimgrey;
    }


#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
代码2-6:布局组件 Layout.raror 专用样式文件

5. 默认样式文件 BBLayout.css,此文件需要存放在文件夹 wwwroot 中

/* ********** 以下 css 是从 BootstrapBlazor 中提取、修改的,供 BBLayout.razor 使用。 ********** */

/*  注1:本文件(BBLayout.css)需要存放在 wwwroot 文件夹中,
         并且在 App.razor 中使用 <link rel="stylesheet" href="BBLayout.css" /> 进行引用。
    注2:<Layout> 组件中自带的默认样式(.layout、.layout-header、.layout-side、......),
         只能在 本文件中 修改其值:在 BBLayout.razor.css 中进行修改,会因为 样式隔离 无效。*/

/*
:root {
    --bb-header-color: #e0e0e0;
    --bb-header-bg: #702cf8;

    --bb-font-weight: 500;
    --bb-title-color: #1f2f3d;
    --bb-sub-font-size: 1.2rem;
}

.navbar {
    --bs-navbar-color: rgba(255,255,255,.85);
    --bs-navbar-hover-color: rgb(255,255,255);
}

.bb-sub {
    margin-top: .25rem;
    font-size: 86%;
    color: #c0c4cc;
}
*/

@supports not selector(::-webkit-scrollbar) {
    .scroll {
        scrollbar-color: rgba(0,0,0,0.3) rgba(0,0,0,0);
        scrollbar-width: thin;
    }
}

.menu {
    --bb-menu-active-color: #702cf8;
    --bb-menu-bar-bg: #702cf8;
    --bb-menu-item-hover-bg: #702cf8;
    --bb-menu-item-hover-color: #fff;
}

.layout {
    /* 包含 Side 上部
    --bb-header-color: #e0e0e0;
    --bb-header-bg: #702cf8;*/

    --bb-layout-header-background: var(--bb-header-bg);
    --bb-layout-sidebar-banner-background: var(--bb-header-bg);
    --bb-layout-header-color: var(--bb-header-color);
    --bb-layout-title-color: var(--bb-header-color);

    /*以下 css 代码控制固定标签,IsFixedTab 使用*/
    --bb-footer-height: 0px;

    /*
    --bb-layout-header-height: 50px;
    --bb-layout-header-backgound: #17a2b8;
    --bb-layout-headerbar-backgound: #1ab394;
    --bb-layout-headerbar-border-color: #1ab394;
    --bb-layout-footer-backgound: #5b6e84;
    --bb-layout-footer-height: 40px;
    */

    /*  隐藏 user 部分:MainLayout.razor 中 layout-user 的默认高度:不显示,此处设置为 0 ;
        原值:65px,通过运行时按 F12 查看源码找到;
        侧边栏删除了“用户名”块,设置高度为 0,以便其它css计算时使用;
    --bb-layout-user-height: 0px;*/

    /*
    --bb-layout-sidebar-width: 214px;
    --bb-layout-sidebar-collapse-width: 70px;
    --bb-layout-sidebar-banner-background: #367fa9;
    --bb-layout-sidebar-scrollbar-background: #c1c1c1;
    --bb-layout-sidebar-backgound: #343a40;
    --bb-layout-sidebar-color: #c2c7d0;
    --bb-layout-title-color: #e9ecef;
    display: flex;
    height: 100%;
    width: 100%;
    flex-direction: column
    */
}

    .layout:not(.has-footer) {
        --bb-layout-footer-height: 0px;
    }

    .layout.has-footer {
        /*以下 css 代码控制固定标签,IsFixedTab 使用*/
        --bb-footer-height: 40px;
    }

    .layout.is-page .layout-right {
        background-color: #fff;
    }

.layout-header {
    border-bottom: 1px solid var(--bs-border-color);
}

.layout-side {
    border-right: 1px solid var(--bs-border-color);
}

.layout-footer {
    border-top: 1px solid var(--bs-border-color);
}

.dropdown-logout {
    --bb-logout-text-color: var(--bb-header-color);
}

.logout-avatar {
    border-radius: 50%;
}

.dropdown-user img {
    border-radius: 50%;
}

.is-fixed-tab .tabs-body {
    height: calc(100vh - var(--bb-layout-header-height) - var(--bb-tabs-item-height) - var(--bb-footer-height));
    overflow: auto;
    flex: initial;
}

    .is-fixed-tab .tabs-body .tabs-body-content {
        height: auto;
        min-height: 100%;
    }


/* ********** 以下 css 是从 BootstrapBlazor 中提取、修改的,供 BBLayoutDrawer.razor 中的 主题配色 使用。 ********** */
.color {
    width: 1.5rem;
    height: 1.5rem;
    display: block;
    cursor: pointer;
    border: 2px solid #e9ecef;
    border-radius: 4px;
    transition: border .3s linear;
}

    .color:hover {
        border: 2px solid #28a745;
    }

.color1,
.layout.is-page.color1 .layout-header {
    background-color: #409eff;
}

.layout.is-page.color1 .layout-side .layout-banner {
    background-color: #3e84d0
}

.layout.is-page.color1 .layout-side {
    background-color: #212529;
    color: #ebeef5;
}

.layout.is-page.color1 .layout-footer {
    background-color: #343a40;
}

.layout.is-page.color1 .layout-header-bar {
    background-color: #2b7cd0;
    border-color: #014186;
}

.layout.is-page.color1 .layout-drawer:hover {
    background-color: #3184dc;
}

.color2,
.layout.is-page.color2 .layout-header {
    background-color: #28a745;
}

.layout.is-page.color2 .layout-side .layout-banner {
    background-color: #24903d
}

.layout.is-page.color2 .layout-side {
    background-color: #212529;
    color: #ebeef5;
}

.layout.is-page.color2 .layout-footer {
    background-color: #343a40;
}

.layout.is-page.color2 .layout-header-bar {
    background-color: #258c3c;
    border-color: #014186;
}

.layout.is-page.color2 .layout-drawer:hover {
    background-color: #24903d;
}

.color3,
.layout.is-page.color3 .layout-header {
    background-color: #e83e8c;
}

.layout.is-page.color3 .layout-side .layout-banner {
    background-color: #c5417e
}

.layout.is-page.color3 .layout-side {
    background-color: #212529;
    color: #ebeef5;
}

.layout.is-page.color3 .layout-footer {
    background-color: #343a40;
}

.layout.is-page.color3 .layout-header-bar {
    background-color: #c73477;
    border-color: #014186;
}

.layout.is-page.color3 .layout-drawer:hover {
    background-color: #c5417e;
}

.color4,
.layout.is-page.color4 .layout-header {
    background-color: #ffc107;
}

.layout.is-page.color4 .layout-side .layout-banner {
    background-color: #e4af10
}

.layout.is-page.color4 .layout-side {
    background-color: #212529;
    color: #ebeef5;
}

.layout.is-page.color4 .layout-footer {
    background-color: #343a40;
}

.layout.is-page.color4 .layout-header-bar {
    background-color: #e2b221;
    border-color: #014186;
}

.layout.is-page.color4 .layout-drawer:hover {
    background-color: #e4af10;
}

.color5,
.layout.is-page.color5 .layout-header {
    background-color: #17a2b8;
}

.color6,
.layout.is-page.color6 .layout-header {
    background-color: #6610f2;
}

.layout.is-page.color6 .layout-side .layout-banner {
    background-color: #4b0cb3
}

.layout.is-page.color6 .layout-side {
    background-color: #212529;
    color: #ebeef5;
}

.layout.is-page.color6 .layout-footer {
    background-color: #343a40;
}

.layout.is-page.color6 .layout-header-bar {
    background-color: #4b0ab5;
    border-color: #014186;
}

.layout.is-page.color6 .layout-drawer:hover {
    background-color: #4b0cb3;
}
代码2-7:修改布局组件 Layout.razor 需要的默认样式

6. 修改 App.razor 文件,引用 BBLayout.css 样式文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />

    @* BootstrapBlazor 中已集成 Bootstrap 最新版,项目模板自带的则不再需要。
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" /> *@

    @* 引用 BootstrapBlazor 样式(已集成 Bootstrap 最新版)。 *@
    <link rel="stylesheet" href="_content/BootstrapBlazor/css/bootstrap.blazor.bundle.min.css" />
    @* FontAwesoem 字体样式 注意需要使用 NuGet 引用 BootstrapBlazor.FontAwesome 包。 *@
    <link rel="stylesheet" href="_content/BootstrapBlazor.FontAwesome/css/font-awesome.min.css" />
    @* 如果不使用 Motronic 样式,则下句不需要。 *@
    <link rel="stylesheet" href="_content/BootstrapBlazor/css/motronic.min.css" />

    @* 自动生成的当前项目的样式表文件,可以保存自定义样式。 *@
    <link rel="stylesheet" href="app.css" />
    @* 自动生成的隔离样式文件,不需要修改。 *@
    <link rel="stylesheet" href="BlazorWebAppWithBB.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    @* 创建 Blazor Web App 项目时选择的是 Server、Global 模式,则此处自动生成匹配说明:@rendermode="InteractiveServer"。 *@
    <HeadOutlet @rendermode="InteractiveServer" />

    @* 布局组件 Layout 使用的默认样式 *@
    <link rel="stylesheet" href="BBLayout.css" />
</head>

<body>
    @* 创建 Blazor Web App 项目时选择的是 Server、Global 模式,则此处自动生成匹配说明:@rendermode="InteractiveServer"。
    注1:此处指定 rendermode 后,则在其它 razor 组件中可以不再单独添加。
    注2:如果创建项目时选择 Server、Per page/component 模式,则需要在每个有动态更新操作的 razor 文件中单独指定 rendermode。 *@
    <Routes @rendermode="InteractiveServer" />

    @* BootstrapBlazor 引用 *@
    <script src="_content/BootstrapBlazor/js/bootstrap.blazor.bundle.min.js"></script>

    <script src="_framework/blazor.web.js"></script>
</body>

</html>
代码2-8:修改后的 App.razor 完整代码

三、使用 BBLayout 切换布局:在 Pages 文件夹中创建  _Imports.razor ,统一指定当前文件夹中 razor 文件使用的 Layout:原来 Componetns 文件夹中的 _Imports.razor 保存不变。

图3-1:Pages 文件夹专用的 _Imports.razor
@* 注:可以有多个 _Imports.razor,每个 _Imports.razor 对所在文件夹中的 razor 文件生效。*@

@* 统一指定当前文件夹中 razor 文件使用的 Layout。
   注:优先级低于 razor 文件中的 Layout 指定语句。*@
@* @layout BlazorWebAppWithBB.Components.Layout.BBLayout *@
@layout BlazorWebAppWithBB.Components.BBLayout.BBLayout
代码3-1:使用 Pages 文件夹专用的   _Imports.razor 统一指定布局组件 Layout
@page "/"

@* 指定使用 BBLayout
@layout BlazorWebAppWithBB.Components.Layout.BBLayout*@

@* 显示指定标签属性:如果不显示指定,在 Layout 组件中选择“关闭所有标签”时,
   默认打开 Home ,但是标签是关闭前的活动标签。*@
@attribute [TabItemOption(Text = "Home", Icon = "fa-fw fa-solid fa-house")]

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.
代码3-2:修改后的 Home.razor 完整代码,不再需要单独指定 Layout
@page "/counter"

@* 指定使用 BBLayout 
@layout BlazorWebAppWithBB.Components.Layout.BBLayout*@

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
代码3-3:修改后的 Counter.razor 完整代码,不再需要单独指定 Layout

四、运行程序,查看效果

图4-1:单击右上角按钮打开 设置 侧边栏
  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值