使用Bootstrap和AngularJS构建类似Chrome的标签页

If you develop web applications you've probably used tabs at some point in your app to improve the layout and make it more organized and user friendly. Luckily today there are several libraries like Bootstrap and jQuery UI that do the job perfectly, so we don't need to code the tabs from scratch.

如果您开发Web应用程序,则可能在应用程序中的某些时候使用了选项卡来改善布局并使其更加井井有条,更易于使用。 幸运的是,今天有一些库(例如BootstrapjQuery UI)可以完美地完成工作,因此我们不需要从头开始编写选项卡。

For this tutorial we'll try to make the tabs not just to look like the one in Chrome browser but also maintain some of the functionality like dynamically shrinking and growing depending on the number of opened tabs. We'll use Bootstrap with AngularJS because they play well together, are very simple to use and are perfect fit for this tutorial.

在本教程中,我们将尝试使标签页不仅看起来像Chrome浏览器中的标签页,而且还维护某些功能,例如根据打开的标签页的数量动态缩小和增长。 我们将Bootstrap与AngularJS 结合使用,因为它们可以很好地协同工作 ,使用非常简单,并且非常适合本教程。

The final product will have this properties:

最终产品将具有以下属性:

  • Opening and closing of tabs

    标签的打开和关闭
  • Dynamic tabs width depending of the number of opened tabs

    动态选项卡的宽度取决于打开的选项卡的数量
  • Moving highlight for the inactive tabs when the mouse pointer is over them

    当鼠标指针悬停在非活动选项卡上时,将其突出显示
  • Chrome look & feel

    镀Chrome外观

What these tabs won't support is reordering and complex animations when opening and closing the tabs.

这些选项卡不支持的是打开和关闭选项卡时重新排序和复杂的动画。

The tabs will look like these:

Chrome-like tabs in action

选项卡如下所示:

The tutorial is updated to use angular directive for the tabs moving highlight, and removed the duplicated bootstrap reference. Thanks Ronnie Gardocki and Jesus Rodriguez for the tips!
本教程已更新为在选项卡移动突出显示中使用angular指令,并删除了重复的引导程序参考。 感谢Ronnie Gardocki和Jesus Rodriguez的提示!

To make it digestible we'll split the process of making the tabs in 5 sections:

为了使其易于消化,我们将制作标签的过程分为5个部分:

  1. Prepare project structure

    准备项目结构
  2. Automate it with Gulp

    用Gulp自动化
  3. Coding the HTML

    编码HTML
  4. Coding the AngularJS module

    编码AngularJS模块
  5. Coding the CSS with Compass (Sass)

    用Compass(Sass)编码CSS

This tutorial suppose you already have basic knowledge in NodeJS, AngularJS and Sass. Even the less experienced should be able to finish this tutorial by following the steps below.

本教程假定您已经具有NodeJS,AngularJS和Sass的基本知识。 即使是经验不足的人也应该可以按照以下步骤完成本教程。

Prerequisites

先决条件

In order to build this project you need to have Node.js and npm (Node Package Manager) installed on your system. To compile the Sass source to CSS, you'll need Ruby, Sass and Compass. Installing them is beyond the scope of this tutorial and will assume you already have them installed. In case you need any help you can always search the web, there're plenty of resources on the subject.

为了构建此项目,您需要在系统上安装Node.js和npm(节点程序包管理器)。 要将Sass源代码编译为CSS,您需要Ruby,Sass和Compass。 安装它们超出了本教程的范围,并且将假定您已经安装了它们。 如果您需要任何帮助,可以随时在网上搜索,则有很多关于此主题的资源。

1.准备项目 (1. Prepare the project)

Although this is small piece of work we'd like to keep things neat and clean that's why we'll use NodeJS for development as it fits perfectly for this kind of project. Let's start with the application folder structure:

尽管这只是一小部分工作,但我们希望保持整洁,整洁,这就是为什么我们将NodeJS用于开发的原因,因为它非常适合此类项目。 让我们从应用程序文件夹结构开始:

dist/              // holds the final files for distribution
|  js/             // concatenated (and minified) javascript
|  css/            // compiled css
source/            // holds all source files
|  javascript/     // javascript source
|  |  app.js
|  sass/           // sass source
|  |  style.scss
|  index.html
package.json
gulpfile.js

And the package.json file should look like this:

而且package.json文件应如下所示:

{
  "name": "chrome-tabs",
  "version": "1.0.0",
  "description": "Web chrome-like tabs made with Bootstrap and AngularJS",
  "engines": {
    "node": ">= 0.10"
  },
  "devDependencies": {
    "gulp": "^3.8.11",
    "gulp-compass": "^2.0.3",
    "gulp-concat": "^2.5.2",
    "gulp-jshint": "^1.9.2",
    "gulp-sourcemaps": "^1.3.0",
    "gulp-uglify": "^1.1.0",
    "gulp-util": "^3.0.4",
    "jshint-stylish": "^1.0.1"
  }
}

Make sure before you start developing you've installed all required dependencies from command line with npm install.

确保在开始开发之前,已使用npm install从命令行安装了所有必需的依赖项。

2.自动化一切 (2. Automate everything)

To automate tasks like compiling Sass sources we'll use Gulp. If you haven't tried it yet here's great intro on how to set it up.

为了自动化诸如编译Sass源之类的任务,我们将使用Gulp。 如果您还没有尝试过,这里是有关如何设置它的精彩介绍

Before we start with writing the gulpfile.js file, let's make sure we have Gulp installed globally with npm install --global gulp.

在开始编写gulpfile.js文件之前,让我们确保已通过npm install --global gulp全局npm install --global gulp

Next let's go with including all modules and define the input and output files:

接下来,让我们包括所有模块并定义输入和输出文件:

/* gulpfile.js */
var gulp  = require('gulp'),
    gutil = require('gulp-util'),

    jshint     = require('gulp-jshint'),
    compass    = require('gulp-compass'),
    concat     = require('gulp-concat'),
    uglify     = require('gulp-uglify'),
    sourcemaps = require('gulp-sourcemaps'),

    input  = {
      'html': 'source/*.html',
      'sass': 'source/sass/**/*.scss',
      'javascript': 'source/javascript/**/*.js'
    },

    output = {
      'html': 'dist',
      'stylesheets': 'dist/css',
      'javascript': 'dist/js'
    };

Than we'll define the JavaScript error checking and concatenating/minifying tasks:

然后,我们将定义JavaScript错误检查和连接/最小化任务:

/* run javascript through jshint */
gulp.task('jshint', function() {
  return gulp.src(input.javascript)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'));
});

/* concat javascript files, minify if --type production */
gulp.task('build-js', function() {
  return gulp.src(input.javascript)
    .pipe(sourcemaps.init())
      .pipe(concat('app.js'))
      //only uglify if gulp is ran with '--type production'
      .pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(output.javascript));
});

The Sass build task to compile our styles:

Sass构建任务来编译我们的样式:

/* compile scss files */
gulp.task('build-css', function() {
  return gulp.src(input.sass)
    .pipe(sourcemaps.init())
      .pipe(compass({
        css: 'dist/css',
        sass: 'source/sass'
        }))
    .pipe(sourcemaps.write())
    .pipe(gulp.dest(output.stylesheets));
});

The HTML copy task:

HTML复制任务:

/* copy any html files to dist */
gulp.task('copy-html', function() {
  return gulp.src(input.html)
    .pipe(gulp.dest(output.html));
});

The watch task that will automatically start the appropriate task when some of the files are changed:

更改某些文件后,监视任务将自动启动适当的任务:

/* Watch these files for changes and run the task on update */
gulp.task('watch', function() {
  gulp.watch(input.javascript, ['jshint', 'build-js']);
  gulp.watch(input.sass, ['build-css']);
  gulp.watch(input.html, ['copy-html']);
});

And finally the default Gulp task:

最后是默认的Gulp任务:

/* run the watch task when gulp is called without arguments */
gulp.task('default', ['jshint', 'build-js', 'build-css', 'copy-html', 'watch']);

To start the project we only need to run gulp on the command line. This will also watch for file changes thus making the project easier for development.

要启动项目,我们只需要在命令行上运行gulp 。 这还将监视文件更改,从而使项目更易于开发。

3.设置HTML (3. Set up the HTML)

The HTML file is quite simple because it will contains only the tabs directive and includes the required dependencies for jQuery, AngularJS, and Bootstrap. We'll begin with the skeleton of the HTML:

HTML文件非常简单,因为它将仅包含tabs指令,并包含jQuery,AngularJS和Bootstrap所需的依赖项。 我们将从HTML的框架开始:

<!-- file: source/index.html -->
<!DOCTYPE html>
<!-- tell angular this is chromeTabsApp -->
<html lang="en" ng-app="chromeTabsApp">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Chrome tabs with Bootstrap and AngularJS</title>
    <!-- include the Bootstrap CSS -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">
    <!-- include our compiled CSS -->
    <link href="css/style.css" rel="stylesheet">
  </head>
  <!-- this will be the only controller AppCtrl -->
  <body ng-controller="AppCtrl">

    <!-- PUT THE TABS DIRECTIVE HERE -->

    <!-- include the JavaScript dependencies: jQuery, AngularJS, AngularUI Bootstrap -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.13/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.12.1/ui-bootstrap-tpls.min.js"></script>
    <!-- include our JavaScript -->
    <script src="js/app.js"></script>
  </body>
</html>

If you're wondering why we're using jQuery in Angular app (which many consider it as bad practice) it's because we need more advanced DOM events for our moving highlight to work.

如果您想知道为什么我们在Angular应用程序中使用jQuery(许多人认为这是不好的做法),那是因为我们需要更高级的DOM事件才能使移动突出显示起作用。

The tabs directive looks like this:

tabs指令如下所示:

<!-- set our tabs with the AngularJS Bootstrap directive -->
<tabset class="tab-container">
  <tab ng-repeat="tab in tabs" active="tab.active" tab-highlight> <!-- the tab highlight directive -->
    <tab-heading>
      <span>{{tab.title}}</span> <i class="glyphicon glyphicon-remove" ng-click="removeTab($event, $index)"></i> <!-- the tab close button -->
    </tab-heading>
    <h1>{{tab.content}}</h1>
  </tab>
  <!-- this is the open new tab button -->
  <button class="btn btn-default" ng-click="addTab()"></button>
</tabset>

You can see that we iterate over collection of tabs which drastically simplifies our code. Also for each tab we include close button and open new tab to the right of the tabs. Next let's set the angular module.

您可以看到我们遍历选项卡的集合,从而大大简化了我们的代码。 同样,对于每个选项卡,我们都包含关闭按钮,并在选项卡右侧打开新的选项卡。 接下来,我们设置角度模块。

4.使用AngularJS使其动态 (4. Make it dynamic with AngularJS)

To manage the tabs we'll use simple array of objects in our angular controller. Here we'll also make our moving highlight directive and initialize the tabs to use it. Let's begin with declaring our module and controller with the tab highlight directive:

为了管理标签,我们将在角度控制器中使用简单的对象数组。 在这里,我们还将创建移动突出显示指令并初始化选项卡以使用它。 让我们开始使用tab highlight指令声明我们的模块和控制器:

/* file: source/javascript/app.js */
// Declare the chromeTabsApp module and its dependency 'ui.bootstrap'
var app = angular.module('chromeTabsApp', ['ui.bootstrap']);
// Declare the AppCtrl controller
app
  .controller('AppCtrl', ['$scope', function ($scope) {

    // PLACE THE TABS CODE HERE

  }])
  .directive('tabHighlight', [function () {

    // PLACE THE MOVING HIGHLIGHT CODE HERE

  }]);

After this we'll add our counter and tabs array:

之后,我们将添加我们的counter和tabs数组:

// Tab counter
var counter = 1;
// Array to store the tabs
$scope.tabs = [];

Next we'll add the functions for adding and removing tabs:

接下来,我们将添加用于添加和删除标签的功能:

// Add tab to the end of the array
var addTab = function () {
  $scope.tabs.push({ title: 'Tab ' + counter, content: 'Tab ' + counter });
  counter++;
  $scope.tabs[$scope.tabs.length - 1].active = true;
};

// Remove tab by index
var removeTab = function (event, index) {
  event.preventDefault();
  event.stopPropagation();
  $scope.tabs.splice(index, 1);
};

// Initialize the scope functions
$scope.addTab    = addTab;
$scope.removeTab = removeTab;

At the end of our controller we'll just add 10 tabs for demonstration purposes:

在控制器的最后,我们仅添加10个标签用于演示:

// For demonstration add 10 tabs
for (var i = 0; i < 10; i++) {
  addTab();
}

Next we'll add the moving highlight functionality. For this we'll use angular directive as this is best practice to use jQuery inside AngularJS applications.

接下来,我们将添加移动突出显示功能。 为此,我们将使用angular指令,因为这是在AngularJS应用程序中使用jQuery的最佳实践。

return {
  restrict: 'A',
  link: function (scope, element) {
    // Here is the major jQuery usage where we add the event
    // listeners mousemove and mouseout on the tabs to initalize
    // the moving highlight for the inactive tabs
    var x, y, initial_background = '#c3d5e6';

    element
      .removeAttr('style')
      .mousemove(function (e) {
        // Add highlight effect on inactive tabs
        if(!element.hasClass('active'))
        {
          x = e.pageX - this.offsetLeft;
          y = e.pageY - this.offsetTop;

          // Set the background when mouse moves over inactive tabs
          element
            .css({ background: '-moz-radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background })
            .css({ background: '-webkit-radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background })
            .css({ background: 'radial-gradient(circle at ' + x + 'px ' + y + 'px, rgba(255,255,255,0.4) 0px, rgba(255,255,255,0.0) 45px), ' + initial_background });
        }
      })
      .mouseout(function () {
        // Return the inital background color of the tab
        element.removeAttr('style');
      });
  }
};

Although the code looks complex, it's actually quite simple and it just replaces the tab background with radial gradient that starts at the current mouse pointer coordinates when placed over the tab.

尽管代码看起来很复杂,但实际上非常简单,它只是用径向渐变替换了选项卡背景,该渐变从放置在选项卡上时的当前鼠标指针坐标开始。

With finished angular module the next thing to do is to style the tabs.

完成角度模块后,接下来要做的就是设置标签的样式。

5.设置标签样式 (5. Styling the tabs)

To make sure the tabs look like the one in Chrome browser we'll have to override the default Bootstrap styles. This is not a straightforward task, so the best solution is to iterate several times through the design until we bring it closer to one similar to Chrome. For styling we'll be using Sass and Compass which includes collections of Sass mixins and functions that will help us in making the code cleaner. There's no simple way to separate the code into sections so below is the whole style for reference.

为了确保这些标签看起来像Chrome浏览器中的标签,我们必须覆盖默认的Bootstrap样式。 这不是一项简单的任务,因此最好的解决方案是遍历整个设计几次,直到我们更接近于与Chrome类似的设计为止。 在样式方面,我们将使用Sass和Compass ,其中包括Sass mixins和函数的集合,这些集合将有助于我们使代码更简洁。 没有简单的方法可以将代码分成几个部分,因此下面是供参考的整体样式。

// file: source/sass/style.scss
@import "compass";

// The main tab container
.tab-container {
  background: #8dc8fb; // Make the background blue
  margin: 0;
  padding: 0;
  max-height: 40px;

  ul {
    &.nav-tabs {
      margin: 0;
      list-style-type: none;
      line-height: 40px;
      max-height: 40px;
      overflow: hidden;
      display: inline-block;
      @include display-flex; // This is the magic that will dynamically expand/shrink the width tabs
      padding-right: 20px;
      border-bottom: 5px solid #f7f7f7;

      $color: #c3d5e6; // Color for the disabled files

      // Inactive tab styles
      > li {
        $raduis: 28px 145px; // Radius to make the tabs look like trapezoid

        // Apply the radius
        @include border-top-left-radius($raduis);
        @include border-top-right-radius($raduis);

        margin: 5px -14px 0;
        padding: 0 30px 0 25px;
        height: 170px;
        background: $color;
        position: relative;
        width: 200px;
        max-width: 200px;
        min-width: 20px;
        border:1px solid #aaa;

        @include box-shadow(0 4px 6px rgba(0,0,0,.5));

        &:first-child {
          margin-left: 0;
        }

        &:last-of-type {
          margin-right: 0;
        }

        > a {
          display: block;
          max-width:100%;
          text-decoration: none;
          color: #222;
          padding: 3px 7px;

          span {
            overflow: hidden;
            white-space: nowrap;
            display: block;
          }

          &:focus,
          &:hover {
            background-color: transparent;
            border-color: transparent;
          }

          // The remove button styles
          .glyphicon-remove {
            color: #777;
            display: inline-block;
            padding:3px;
            font-size: 10px;
            position:absolute;
            z-index: 10;
            top:7px;
            right: -10px;
            @include border-radius(50%);

            &:hover {
              background: #d39ea3;
              color: white;
              @include box-shadow(inset 0 1px 1px rgba(0,0,0,.25));
              @include text-shadow(0 1px 1px rgba(0,0,0,.25));
            }
          }
        }

        // Active tab style
        &.active {
          z-index: 2;
          @include background-image(linear-gradient(white, #f7f7f7 30px));

          > a {
            background-color: transparent;
            border-color: transparent;
            border-bottom-color: transparent;

            &:focus,
            &:hover {
              background-color: transparent;
              border-color: transparent;
              border-bottom-color: transparent;
            }
          }
        }
      }

      // The open new tab button
      .btn {
        float: left;
        height: 20px;
        width: 35px;
        min-width: 35px;
        max-width: 35px;
        margin: 10px 0 0 0;
        border-color: #71a0c9;
        outline: none;

        @include transform(skew(30deg));

        &.btn-default {
          background: $color;

          &:hover {
            background: #d2deeb;
          }

          &:active {
            background: #9cb5cc;
          }
        }
      }
    }
  }

  // Styling the tab containter
  .tab-pane {
    padding: 60px 40px;
    text-align: center;

    &.active {
      border-top:1px solid #ddd;
    }
  }
}

You can notice that using the CSS3 display flex for the tabs container will make the individual tabs dynamically expand and shrink depending on the number of opened tabs. You can read complete guide for the Flexbox Layout here.

您可能会注意到,对选项卡容器使用CSS3 display flex将根据打开的选项卡的数量使各个选项卡动态扩展和缩小。 您可以在此处阅读有关Flexbox布局的完整指南。

If you followed the steps above you should be able to build everything with running gulp from the command line. To see the fruits of your labor open dist/index.html file in your browser.

如果遵循上述步骤,则应该能够从命令行运行gulp来构建所有内容。 要查看您的工作成果,请在浏览器中打开dist/index.html文件。

现场演示 (Live demo)

Here's a live Codepen demo where you can test and play a bit with the tabs.

这是一个现场Codepen演示,您可以在其中使用这些标签进行测试和播放。

See the Pen Chrome Tabs by Dimitar (@justd) on CodePen.

见笔Chrome标签由贝尔巴托夫( @justd上) CodePen

翻译自: https://scotch.io/tutorials/build-chrome-like-tabs-with-bootstrap-and-angularjs

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值