Bootstrap为我们提供了十几种的可复用组件,包括字体图标、下拉菜单、导航、警告框、弹出框、输入框组等。在你的Web Application中使用这些组件,将为用户提供一致和简单易用的用户体验。

Bootstrap组件本质上是结合了各种现有Bootstrap元素以及添加了一些独特Class来实现。Bootstrap元素我在上一篇文章中涉及到,具体可以参考《ASP.NET MVC使用Bootstrap系列(2)——使用Bootstrap CSS和HTML元素》。

在这篇博客中,我将继续探索Bootstrap丰富的组件以及将它结合到ASP.NET MVC项目中。

Bootstrap 导航条

Bootstrap导航条作为"明星组件"之一,被使用在大多数基于Bootstrap Framework的网站上。为了更好的展示Bootstrap导航条,我在ASP.NET MVC的_Layout.cshtml布局页创建一个fixed-top导航条,当然它是响应式的——在小尺寸、低分辨率的设备上打开时,它将会只展示一个按钮并带有3个子菜单,当点击按钮时垂直展示他们。在网页上显示如下:

在移动设备上显示如下:

在ASP.NET MVC默认的_Layouts.cshtml布局页中已经帮我们实现了上述功能,打开它对其稍作修改,如下代码片段所示:

<div class="navbar navbar-inverse navbar-fixed-top">

    <div class="container">

        <div class="navbar-header">

            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

            </button>

            @Html.ActionLink("Northwind Traders", "Index", "Home", null, new { @class = "navbar-brand" })

        </div>

        <div class="navbar-collapse collapse">

            @Html.Partial("_BackendMenuPartial")

            @Html.Partial("_LoginPartial")

        </div>

    </div>

</div>

其中class为.navbar-fixed-top可以让导航条固定在顶部,还可包含一个 .container 或 .container-fluid 容器,从而让导航条居中,并在两侧添加内补(padding)

注意,我使用了2个局部视图(_BackendMenuPartial和LoginPartial)来生成余下的导航条(使用.navbar-collapse类在低分辨率设备中折叠),其中局部视图逻辑是基于当前访问的用户是否登陆来控制是否显示。

首先,添加如下代码在_BackendMenuPartial视图中,这将会在导航条中产生一个搜索框:

@using (Html.BeginForm("Index", "Search", FormMethod.Post, new { @class = "navbar-form navbar-left", role = "search" }))

{

    <div class="form-group">

        @Html.TextBox("searchquery", "", new { @id = "searchquery", @class = "form-control input-sm", placeholder = "Search" })

        @Html.Hidden("fromcontroller", @ViewContext.RouteData.Values["controller"], new { @id = "fromcontroller" })

    </div>

    <button type="submit" class="btn btn-default btn-xs">GO</button>

}

因为Bootstrap导航条作为整个网站的公共部分,要实现快速搜索那么必须要知道当前所处于哪个Controller,这样才能提高检索效率。所以上述代码中,增加了一个Id为fromcontroller隐藏字段,代表当前访问的Controller。

当点击搜索时,发送HTTP POST请求到Index Action下。然后根据传递过来的fromcontroller来swith到具体的Action来执行搜索,具体的搜索逻辑代码如下:

public ActionResult Index(string searchquery, string fromcontroller)

{

    switch (fromcontroller)

    {

        case "Products":

        return RedirectToAction("SearchProductsResult", new { query = searchquery });

        case "Customers":

        return RedirectToAction("SearchCustomersResult", new { query = searchquery });

        case "Employees":

        return RedirectToAction("SearchEmployeesResult", new { query = searchquery });

    }

    return View();

}

具体搜索的Action如下:

public ActionResult SearchProductsResult(string query)

{

    ViewBag.SearchQuery = query;

    var results = _context.Products.Where(p => p.ProductName.Contains(query)).ToList();

    return View(results);

}

public ActionResult SearchCustomersResult(string query)

{

    ViewBag.SearchQuery = query;

    var results = _context.Customers.Where(p => p.CompanyName.Contains(query)

    || p.ContactName.Contains(query)

    || p.City.Contains(query)

    || p.Country.Contains(query)).ToList();

    return View(results);

}

public ActionResult SearchEmployeesResult(string query)

{

    ViewBag.SearchQuery = query;

    var results = _context.Employees.Where(p => p.FirstName.Contains(query)

    || p.LastName.Contains(query)

    || p.Notes.Contains(query)).ToList();

    return View(results);

}

列表组

列表组是灵活又强大的组件,不仅能用于显示一组简单的元素,还能结合其他元素创建一组复杂的定制内容。上面的搜索为我们重定向到Result视图,在此视图中,它为我们显示了搜索结果,为了更好的展示结果,我们可以使用列表组来显示搜索到的产品,视图中的代码如下所示:

@model IEnumerable<Bootstrap.Data.Models.Products>

@{

    ViewBag.Title = "搜索产品";

}

<div class="container">

    <div class="page-header">

        <h1>产品结果 <small>搜索条件: "@ViewBag.SearchQuery"</small></h1>

    </div>

    <ul class="list-group">

        @foreach (var item in Model)

        {

        <a href="@Url.Action("Edit","Products", new { id=@item.ProductID})" class="list-group-item">@item.ProductName <span class="badge">@item.UnitsInStock</span></a>

        }

    </ul>

</div>

在上述代码中,为无序列表(<ul>)的class设置为list-group,并且每一个<li>的class为list-group-item,这是一个最简单的列表组。

徽章

徽章用来高亮条目,可以很醒目的显示新的或者未读的条目数量,为一个元素设置徽章仅仅只需要添加<span>元素并设置它的class为badge。所以,在上述代码的基础上稍作修改,添加徽章,表示库存个数,如下HTML所示:

<a href="@Url.Action("Edit","Products", new { id=@item.ProductID})" class="list-group-item">
@item.ProductName <span class="badge">@item.UnitsInStock</span>
</a>

显示的结果为如下截图:

媒体对象

媒体对象组件被用来构建垂直风格的列表比如博客的回复或者推特。在Northwind数据库中包含一个字段ReportTo表示Employee向另一个Employee Report。使用媒体对象可以直观来表示这种关系。在视图中的代码如下所示:

<div class="container">

<div class="page-header">

    <h1>员工搜索结果: <small>搜索条件: "@ViewBag.SearchQuery"</small></h1>

</div>

@foreach (var item in Model)

{

    <div class="media">

        <a class="pull-left" href="@Url.Action("Edit", "Employees", new { id = @item.EmployeeID })">

            <img class="media-object" src="@Url.Content("~/Images/employees/" + @item.EmployeeID + ".png")" alt="@item.FirstName" width="64" height="64">

        </a>

        <div class="media-body">

            <h4 class="media-heading">@item.FirstName @item.LastName</h4>

            @item.Notes

            @foreach (var emp in @item.ReportingEmployees)

            {

                <div class="media">

                    <a href="#" class="pull-left">

                        <img alt="@emp.FirstName" src="@Url.Content("~/Images/employees/" + @emp.EmployeeID + ".png")" class="media-object" width="64" height="64">

                    </a>

                    <div class="media-body">

                        <h4 class="media-heading">@emp.FirstName @emp.LastName</h4>

                        @emp.Title

                    </div>

                </div>

            }

        </div>

    </div>

}

</div>

显示结果如下:

可以看到,媒体对象组件是由一系列class为media、media-heading、media-body、media-object的元素组合而成,其中media-object用来表示诸如图片、视频、声音等媒体对象。

注:.pull-left 和 .pull-right 这两个类以前也曾经被用在了媒体组件上,但是,从 v3.3.0 版本开始,他们就不再被建议使用了。.media-left 和 .media-right 替代了他们,不同之处是,在 html 结构中, .media-right 应当放在 .media-body 的后面。

页头

当用户访问网页时,Bootstrap页头可以为用户提供清晰的指示。Bootstrap页头本质上是一个<h1>元素被封装在class为page-header的<div>元素中。当然你也可以利用<small>元素来提供额外的关于页面的信息,同时Bootstrap为页头添加了水平分隔线用于分隔页面,如下HTML即为我们构建了页头:

<div class="page-header">

    <h1>员工搜索结果: <small>搜索条件: "@ViewBag.SearchQuery"</small></h1>

</div>

路径导航

路径导航(面包屑)在Web 设计中被用来表示用户在带有层次的导航结构中当前页面的位置。类似于Windows资源管理器。如下HTML所示:

<ol class="breadcrumb">

    <li>@Html.ActionLink("Home", "Index", "Home")</li>

    <li>@Html.ActionLink("Manage", "Index", "Manage")</li>

    <li class="active">Products</li>

</ol>

在上面HTML代码中,通过指定有序列表(<ol>)的class为breadcrumb,每一个子路径用<li>来表示,其中通过设置<li>的class为active代表当前所处的位置。

各路径间的分隔符已经自动通过 CSS 的 :before 和 content 属性添加了。

分页

分页用来分隔列表内容,特别是显示大量数据时通过分页可以有效的减少服务器压力和提高用户体验,如下截图使用分页来显示产品列表:

要完成上述的分页,需要安装PagedList.Mvc程序包,在NuGet控制台中安装即可:Install-PackagePagedList.Mvc

然后修改Action,它需要接受当然的页码,它是一个可空的整数类型变量,然后设置PageSize等于5,表示每页显示5条记录,如下代码所示:

public ActionResult Index(int? page)

{

    var models = _context.Products.Project().To<ProductViewModel>().OrderBy(p => p.ProductName);

    int pageSize = 5;

    int pageNumber = (page ?? 1);

    return View(models.ToPagedList(pageNumber, pageSize));

}

在View中,使用PagedList动态生成分页控件:

<div class="container">

    <div class="page-header">

        <h1>Products <small>Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of @Model.PageCount</small></h1>

    </div>

    <ol class="breadcrumb">

        <li>@Html.ActionLink("Home", "Index", "Home")</li>

        <li>@Html.ActionLink("Manage", "Index", "Manage")</li>

        <li class="active">Products</li>

    </ol>

    <table class="table table-striped table table-hover">

        <thead>

        <tr>

            <th>

            Product Name

            </th>

            <th>

            Unit Price

            </th>

            <th>

            Units In Stock

            </th>

            <th>

            Discontinued

            </th>

            <th></th>

        </tr>

        </thead>

    <tbody>

    @foreach (var item in Model)

    {

    <tr class="@item.Status">

        <td>

            @Html.ActionLink(item.ProductName, "Edit", new { id = item.ProductID })

        </td>

        <td>

            @Html.DisplayFor(modelItem => item.UnitPrice)

        </td>

        <td>

            @Html.DisplayFor(modelItem => item.UnitsInStock)

        </td>

        <td>

            @Html.DisplayFor(modelItem => item.Discontinued)

        </td>

        <td>

            @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })

        </td>

    </tr>

    }

    </tbody>

    </table>

    @Html.PagedListPager(Model, page => Url.Action("Index", new { page }), PagedListRenderOptions.ClassicPlusFirstAndLast)

    <p>

        <a href="@Url.Action("Create","Products")" class="btn btn-sm btn-primary" role="button">Create New</a>

    </p>

</div>

输入框组

输入框组为用户在表单输入数据时可以提供更多的额外信息。Bootstrap的输入框组为我们在Input元素的前面或者后面添加指定class的块,这些块可以是文字或者字体图标,如下所示:

<div class="form-group">

    <div class="col-sm-2 input-group">

        <span class="input-group-addon">

            <span class="glyphicon glyphicon-phone-alt"></span>

        </span>

        @Html.TextBox("txtPhone","1194679215",new { @class = "form-control" })

    </div>

</div>

上面的输入框组合中,在Textbox的左边放置了一个带有字体图标Phone的灰色块,结果如下所示:

不仅可以使用字体图标,还可以使用纯文本来显示信息,如下所示在Textbox右边放置了固定的邮箱域名:

<div class="form-group">

    <div class="col-sm-4 input-group">

        @Html.TextBox("txtEmail","1194679215", new { @class = "form-control" })

        <span class="input-group-addon">@@qq.com</span>

    </div>

</div>

当然也可以在Input元素的两边同时加上块,如下代码所示:

<div class="form-group">

    <div class="col-sm-2 input-group">

        <span class="input-group-addon">¥</span>

            @Html.TextBox("txtMoney","100",new { @class = "form-control" })

        <span class="input-group-addon">.00</span>

    </div>

</div>

按钮式下拉菜单

按钮式下拉菜单顾名思义,一个按钮可以执行多种action,比如既可以Save,也可以Save之后再打开一个新的Form继续添加记录,如下所示:

<div class="form-group">

    <div class="col-sm-offset-2 col-sm-10">

        <div class="btn-group">

            <button type="submit" class="btn btn-primary btn-sm">Save</button>

            <button type="button" class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">

                <span class="caret"></span>

                <span class="sr-only">Toggle Dropdown</span>

            </button>

            <ul class="dropdown-menu" role="menu">

                <li><a href="#" id="savenew">Save & New</a></li>

                <li class="divider"></li>

                <li><a href="#" id="duplicate">Duplicate</a></li>

            </ul>

        </div>

    </div>

</div>

警告框

Bootstrap警告组件通常被用作给用户提供可视化的反馈,比如当用户Save成功后显示确认信息、错误时显示警告信息、以及其他的提示信息。

Bootstrap提供了4中不同风格的警告,如下所示:

<div class="container">

    <div class="page-header">

        <h1>Alerts </h1>

    </div>

    <ol class="breadcrumb">

        <li>@Html.ActionLink("Home", "Index", "Home")</li>

        <li>Bootstrap</li>

        <li class="active">Alerts</li>

    </ol>

    <div class="alert alert-success"><strong>Success. </strong></div>

    <div class="alert alert-info"><strong>Info.</strong></div>

    <div class="alert alert-warning"><strong>Warning!</strong></div>

    <div class="alert alert-danger"><strong>Danger!</strong></div>

</div>

可关闭的警告框可以让用户点击右上角的X来关闭,你可以使用alter-dismissible 类:

<div class="alert alert-warning alert-Dismissible" role="alert">

    <button type="button" class="close" data-dismiss="alert">

        <span aria-hidden="true">&times;</span><span class="sr-only">Close</span>

    </button>

    <strong>Alert!</strong>这是可关闭的Alter

</div>

进度条

进度条在传统的桌面应用程序比较常见,当然也可以用在Web上。通过这些简单、灵活的进度条,可以为当前工作流程或动作提供实时反馈。Bootstrap为我们提供了许多样式的进度条。

  • 基本进度条

基本进度条是一种纯蓝色的进度条,添加一个class 为sr-only 的<span>元素在进度条中是比较好的实践,这样能让屏幕更好的读取进度条的百分比。

<div class="row">

<    h4>基本进度条</h4>

    <div class="progress">

        <div class="progress-bar" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width: 80%;">

            <span class="sr-only">80%完成</span>

        </div>

    </div>

</div>

  • 上下文情景变化进度条

上下文情景变化进度条组件使用与按钮和警告框相同的类,根据不同情境展现相应的效果。

  • progress-bar-success
  • progress-bar-info
  • progress-bar-warning
  • progress-bar-danger

  • 条纹动画效果进度条

为了让进度条更加生动,可以为其添加条纹效果,在进度条<div>中添加class为progress-striped。当然让进度条看起来有动画,可以再为其指定active的class在<div>上,如下所示:

<div class="progress progress-striped active">

    <div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100" style="width: 40%">

        <span class="sr-only">40% 完成 (success)</span>

    </div>

</div>

  • 使用SignalR动态更新进度条

SignalR是ASP.NET的库,可以用来双向实时通信,在ASP.NET MVC项目中使用SignalR:1.首先通过NuGet来安装SignalR Nuget Package:

Install-Package Microsoft.AspNet.SignalR

2.在项目里新建一个名为Hubs的文件夹,并添加ProgressbarHub类,如下代码所示:

public class ProgressbarHub : Hub

{

    public void SendProgress()

    {

        for (int i = 0; i <= 100; i++)

        {

            Thread.Sleep(50);

            Clients.Caller.sendMessage(i + "%");

        }

    }

}

SendProgress方法很简单,向客户端发送消息(通过自增变量输出0—100)

3.在布局页添加对SignalR虚拟路径的引用:

<script src="~/signalr/hubs"></script>

4.在打包文件中,包含 SignalR.js

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(

"~/Scripts/jquery-{version}.js",

"~/Scripts/jquery.signalR-2.2.0"

));

5.在客户端建立与服务端的双向通信:

@section scripts

{

<script type="text/javascript" language="javascript">

    $(document).ready(function () {

    //$(".progress-bar").width('0%');

    });

    $("#start").click(function () {

        $(".progress-bar").width('0%');

        var progressNotifier = $.connection.progressbarHub;

        progressNotifier.client.sendMessage = function (message) {

            updateProgress(message);

        };

        $.connection.hub.start().done(function () {

            progressNotifier.server.sendProgress();

        });

    });

    function updateProgress(message) {

        $(".progress-bar").width(message);

        $("#progressbarTitle").html(message + ' Complete');

    }

</script>

}

你可以看到,上述代码先初始化和服务端的连接,然后设置被服务端调用的客户端方法updateProgress。

最后,我们建立了和服务端的连接并且启动了服务端的操作,你可以看到,我们调用了sendProgress方法——这已经在ProgressbarHub类中定义好了。这样当点击ID为start的按钮时动态为进度条更新了0-100的数值。

小结

在这篇博客中,探索了Bootstrap中丰富的组件,并将它结合到ASP.NET MVC项目中。通过实例可以发现,这类组件本质上是结合了各种现有Bootstrap元素以及添加了一些独特Class来实现。

更多的Bootstrap组件请参见:http://v3.bootcss.com/components/

源代码下载

本博客为木宛城主原创,基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。

ASP.NET MVC使用Bootstrap系列(3)——使用Bootstrap 组件的更多相关文章

  1. Asp.net Mvc模块化开发系列(目录)

    模块化开发是非常重要的,模块化开发是个系统性问题,为此我觉得有必须要写一个系列的文章才能基本说的清楚 那又为什么要写一个目录呢? 其一.是对我昨天承诺写一个系列新的文章的回应 其二.是先写出一个大纲, ...

  2. ASP.NET MVC框架开发系列课程 (webcast视频下载)

    课程讲师: 赵劼 MSDN特邀讲师 赵劼(网名“老赵”.英文名“Jeffrey Zhao”,技术博客为http://jeffreyzhao.cnblogs.com),微软最有价值专家(ASP.NET ...

  3. 开篇ASP.NET MVC 权限管理系列

    开篇 [快乐编程系列之ASP.NET MVC 权限管理系列]一.开篇   用了好长一段时间的ASP.NET MVC,感觉MVC真的是很好用,最近一年左右做了两个中小型项目,觉得还是很多地方不是很熟悉的 ...

  4. ASP.NET MVC(C#)和Quartz.Net组件

    ASP.NET MVC(C#)和Quartz.Net组件 在之前的文章<推荐一个简单.轻量.功能非常强大的C#/ASP.NET定时任务执行管理器组件–FluentScheduler>和&l ...

  5. ASP.NET MVC框架开发系列教程

    本系列教程是自己在工作中使用到而记录的,如有错误之处,请给与指正 文章目录 MVC4 开篇 第一章 初识MVC4 第二章 下山遇虎(@helper) 第三章 Models模块属性详解 第四章 在MVC ...

  6. 基于ASP.NET MVC(C#)和Quartz.Net组件实现的定时执行任务调度

    http://www.cnblogs.com/bobositlife/p/aspnet-mvc-csharp-quartz-net-timer-task-scheduler.html 在之前的文章&l ...

  7. ASP.NET MVC使用Bootstrap系列(1)——开始使用Bootstrap

    阅读目录 Bootstrap结构介绍 在ASP.NET MVC 项目中添加Bootstrap文件 为网站创建Layout布局页 使用捆绑打包和压缩来提升网站性能 在Bootstrap项目中使用捆绑打包 ...

  8. ASP.NET MVC Bootstrap极速开发框架

    前言 每次新开发项目都要从头开始设计?有木有一个通用的快速开发框架?并且得是ASP.NET MVC  And Bootstrap?数据库不要手工创建?框架对未来业务支持的扩展性好?这么简单的功能还需要 ...

  9. ASP.NET MVC 入门系列教程

    ASP.NET MVC 入门系列教程 博客园ASP.NET MVC 技术专题 http://kb.cnblogs.com/zt/mvc/ 一个居于ASP.NET MVC Beta的系列入门文章,有朋友 ...

随机推荐

  1. Day_6作业_模拟人生

    as #!/usr/bin/env python # encoding: utf-8 class wisdom(object): def __init__(self,n,g): self.n = n ...

  2. Numpy 用法小结

    1.  asarray 函数 可以将输入数据转化为矩阵格式. 输入数据可以是(列表,元组,列表的列表,元组的元组,元组的列表等这些数组形式). >>> asarray([(1,2,3 ...

  3. BZOJ 1853: [Scoi2010]幸运数字

    1853: [Scoi2010]幸运数字 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 2117  Solved: 779[Submit][Status] ...

  4. 【BZOJ-3589】动态树 树链剖分 + 线段树 + 线段覆盖(特殊的技巧)

    3589: 动态树 Time Limit: 30 Sec  Memory Limit: 1024 MBSubmit: 405  Solved: 137[Submit][Status][Discuss] ...

  5. 【BZOJ-3675】序列分割 DP + 斜率优化

    3675: [Apio2014]序列分割 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 1420  Solved: 583[Submit][Statu ...

  6. BZOJ2426 [HAOI2010]工厂选址

    Description 某地区有m座煤矿,其中第i号矿每年产量为ai吨,现有火力发电厂一个,每年需用煤b吨,每年运行的固定费用(包括折旧费,不包括煤的运费)为h元,每吨原煤从第i号矿运到原有发电厂的运 ...

  7. Uva1398 Meteor

    扫描线法. 将流星出现在相机里的时间转化成线段,离散化端点后,扫描何时出现的流星最多.注意边界的不算,所以要先减右端点再加左端点 /*By SilverN*/ #include<iostream ...

  8. HDU 2795 Billboard

    Description 在学校的入口处有一个巨大的矩形广告牌,高为h,宽为w.所有种类的广告都可以贴,比如ACM的广告啊,还有餐厅新出了哪些好吃的,等等..   在9月1号这天,广告牌是空的,之后广告 ...

  9. 三角形问题的解决复杂度O(n^3)和O(nlogn)的比较

    问题描述: n条棍子组成一个三角形,使得三角形周少最大. 方法一: 暴力解则算法复杂度为O(n^3) #include<stdio.h> const int MAX_N=105 int m ...

  10. Java垃圾收集学习笔记

    (1)除了释放不再被引用的对象,垃圾收集器还要处理 堆碎块 .请求分配新对象时可能不得不增大堆空间的大小,虽然可以使用的空闲空间是足够的,但是堆中没有没有连续的空间放得下新对象.可能会导致虚拟机产生不 ...