Angularjs实现mvvm式选项卡效果

选项卡是现代web网页中最常用的效果之一。
本文重点是用angularjs这个非常火mvvm框架,实现选项卡效果。在此之前,先搬出我们常用的jquery实现。

1、jquery实现简单粗暴的选项卡效果

var nav = $(".tabs");//tab切换
var box = $(".box");//容器
nav.on("click", function(){ //点击事件
  var this_index=$(this).index();
  $(this).addClass("active").siblings().removeClass("active");
  box.eq(this_index).show().siblings().hide();
});

在这里只给出js核心部分,html和css不做赘述。
以上代码,简单粗暴的实现了选项卡效果,用点击事件获得elem.index(), 把索引和容器串起来控制显示隐藏。

2、angularjs实现一个简单选项卡效果

Html部分

 <section ng-app="myApp">
       <div class="tabs tabs-style" ng-controller="TabController as tab">
         <nav>
           <ul>
             <li ng-class="{'current':tab.isSet(1)}">
               <a href="#" ng-click="tab.setCurrent(1)"><span>Home</span></a></li>
             <li ng-class="{'current':tab.isSet(2)}">
               <a href="#" ng-click="tab.setCurrent(2)"><span>Work</span></a></li>
             <li ng-class="{'current':tab.isSet(3)}">
               <a href="#" ng-click="tab.setCurrent(3)"><span>Blog</span></a></li>
             <li ng-class="{'current':tab.isSet(4)}">
               <a href="#" ng-click="tab.setCurrent(4)"><span>About</span></a></li>
             <li ng-class="{'current':tab.isSet(5)}">
               <a href="#" ng-click="tab.setCurrent(5)"><span>Contact</span></a></li>
           </ul>
         </nav>
         <div class="content">
           <section id="section-1"  ng-show="tab.isSet(1)">
             <p>1</p>
           </section>
           <section id="section-2"  ng-show="tab.isSet(2)">
             <p>2</p>
           </section>
           <section id="section-3" ng-show="tab.isSet(3)">
             <p>3</p>
           </section>
           <section id="section-4" ng-show="tab.isSet(4)">
             <p>4</p>
           </section>
           <section id="section-5" ng-show="tab.isSet(5)">
             <p>5</p>
           </section>
         </div>
       </div>
   </section>

css 部分(这里为了方便我们使用Less语法,童鞋们可以自定义css实现个性效果)

* {
  margin: 0;
  padding: 0;
}

body {
  background: #e7ecea;
  font-weight: 600;
  font-family: 'Raleway', Arial, sans-serif;
  text-align: center;
}

a {
    color: #2CC185;
    text-decoration: none;
    outline: none;
  
    &:hover {
    color: #74777b;
    }
}

.tabs {
  position: relative;
  width: 100%;
  margin: 30px auto 0 auto;

  nav {
    ul {
      position: relative;
      display: flex;
      max-width: 1200px;
      margin: 0 auto;
      list-style: none;
      flex-flow: row wrap;
      justify-content: center;
      
        li {
          flex: 1;
          
          &.current a {
            color: #74777b;
          }
        }
      }
    }  
    a {
      display: block;
      position: relative;
      overflow : hidden;
      line-height: 2.5;
      
      span {
        vertical-align: middle;
        font-size: 1.5em;
      }
    }
}

.content {
  position: relative; 
  
  section {
    /* display: none; */
    margin: 0 auto;
    max-width: 1200px;

    &.content-current {
      /* display: block; */
    }
    
    p {
      color: rgba(40,44,42, 0.4);
      margin: 0;
      padding: 1.75em 0;
      font-weight: 900;
      font-size: 5em;
      line-height: 1;
    }
  }
}

.tabs-style {
  nav {
    /* background: rgba(255,255,255,0.4); */
    
    ul li {
      a {
        overflow: visible; 
        border-bottom: 1px solid rgba(0,0,0,0.2);
        -webkit-transition: color 0.2s;
        transition: color 0.2s;
      }
    }
    
    ul li.current a{
      &:after, &:before {
        content: '';
        position: absolute;
        top: 100%;
        left: 50%;
        width: 0;
        height: 0;
        border: solid transparent;
        }
      &:after {
        margin-left: -10px;
        border-width: 10px;
        border-top-color: #e7ecea;
      }
      &:before {
        margin-left: -11px;
        border-width: 11px;
        border-top-color: rgba(0,0,0,0.2);
      }
    }
  }
}

js部分

angular.module('myApp', [])
  .controller('TabController', function() {
    this.current = 1;
  
  this.setCurrent = function (tab) {
    this.current = tab;
  };
  
  this.isSet = function(tab) {
    return this.current == tab;
  };
});

最后效果如下图所示:


angularjs-tabs.png

通过以上代码,我们可以发现实现的核心是angularjs内置的ng-class和ng-click,ng-show指令。通俗来讲:controller里定义了current 这条数据默认值为1,ng-click给点击事件自定义函数,改变current数据,ng-class通过获得current的值绑定条件,给当前选中的索引添加current样式,容器同样获得controller里的current数据通过ng-show控制显示隐藏。

3、angularjs实现一个稍微复杂的移动端选项卡效果

html部分

<script src="http://cdn.bootcss.com/angular.js/1.3.8/angular.min.js"></script>
<script src="http://cdn.bootcss.com/angular.js/1.3.8/angular-touch.min.js"></script>
//angularjs的一个移动端touch事件库

<div ng-app='myApp' ng-controller="myController">
  <div class="type-tabs">
      <div ng-repeat="item in [1,2,3,4]" ng-click="changeIndex($index)">Tab{{item}}</div>
    </div>
    <div class="guid-bar">
      <div class="guid-bar-content" style="left:{{ 25*activeIndex}}%"></div>
    </div>
    <div class="tab-content" ng-swipe-right="swipeRight()" ng-swipe-left="swipeLeft()">
      <div class="tab-content-inner" style="left:{{ -100*activeIndex}}%">
        <div class="tab-content-item" ng-repeat="item in [1,2,3,4]" >
          <br /><br /><br /><br />
          <h1>Tab{{item}}
          </h1></div>
      </div>
    </div>
</div>

css部分

*{
  padding:0;
  margin:0;
  font-family:'Arial';
}
.type-tabs{
    width: 100%;
    height: 40px;
}
.type-tabs div{
    float: left;
    width: 25%;
    line-height: 40px;
    text-align: center;
  cursor:pointer;
  user-select:none;  
  -webkit-user-select:none;

}
.guid-bar{
    position: relative;
    margin-top: -3px;
}
.guid-bar-content{
    width: 25%;
    height: 3px;
    background-color: #345;
    position: absolute;
    left: 50%;
    transition:all 400ms ease;
}
.tab-content{
    width: 100%;
    height: 500px;
    background-color: #ccc;
    overflow: hidden;
}
.tab-content-inner{
    width: 400%;
    position: relative;
    transition: all 400ms;
}
.tab-content-item{
    width: 25%;
    float: left;
  text-align:center;
}

js部分

var myApp=angular.module('myApp',['ngTouch']);
myApp.controller('myController',function($scope){
  $scope.activeIndex=0;
    $scope.changeIndex=function(index){
        $scope.activeIndex=index;
    };
  $scope.swipeLeft=function(){
      $scope.activeIndex=++$scope.activeIndex;
      $scope.check();
    };
 $scope.swipeRight=function(){
      $scope.activeIndex=--$scope.activeIndex;
      $scope.check();
 };
 $scope.check=function(){
      if($scope.activeIndex>3)
        $scope.activeIndex=0;
      if($scope.activeIndex<0)
        $scope.activeIndex=3;
    }
})

当当当当,效果如下:

ng-touch.png
好了,今天我们就给出这两个例子,对angularjs了解过的童鞋,直接看代码应该可以很快看懂。没了解过的童鞋,也能通过这两个例子,了解到mvvm的黑魔法,以及它的代码组织结构。

4、angularjs的mvvm模式比jquery的dom操作好在哪里?

1、从宏观上来说,一种是操作数据处理数据,一种是操作dom和ui交互。
一般网页项目的流程可以总结为三个流程:1) 你要获取界面上的数据 2)后台交换数据3)获取数据后,对界面重新进行渲染。这个过程中,你和后台数据交换怎么实现?jquery的ajax吧,如果数据交换的API假设20多个,那么$.get或者$.ajax你要写多少个才能全部包含进去?而且所有API链接都不在一个地方,管理起来相当麻烦。而angularjs只要配置一下route就行了。
获取了数据后,你又如何管理这些数据,如何把数据渲染到界面上去?
如何管理各种事件?jquery本身特性,也就是事件触发,很多时候,就是你在编写 触发事件->处理数据 的流程。很显然,功能一多,代码就会和面条一样,交织在一起了。身边不乏两三年的传统jquery前端,事件委托、dom操作、浏览器渲染过程、插件组件封装等等都没有去深入研究,可想而知代码质量有多烂。事实上jquery是一个类库,并不是一个开发框架,jq是对js原生api的进一步封装,让你更加愉快的进行dom操作、动画操作以及ajax,正是因为他太过灵活,所以更容易写出难以维护的代码。

2、性能方面:DOM操作慢,DOM对象本身也是一个js对象,所以严格来说,并不是操作这个对象慢,而是说操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint)。具体想了解的童鞋请点击链接查看详情:https://leozdgao.me/why-dom-slow/

结尾

随着web产品越来越复杂,分层架构是必不可少的,因此双向绑定作为解药,结合很早就流行的MVC框架,衍生出MVVM这神器。博主坚信,mvvm会是前端的终极解决方案。由DOM操作到数据操作需要一个过程去适应,但只要结果是好的,这些付出就都值得。在这个过程中,也是对你专业能力的一种提升。加油小伙伴们!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容

  • AngularJS是什么?AngularJs(后面就简称ng了)是一个用于设计动态web应用的结构框架。首先,它是...
    200813阅读 1,517评论 0 3
  • AngularJS AngularJS概述 介绍 简称:ng Angular是一个MVC框架 其他前端框架: Vu...
    我爱开发阅读 2,311评论 0 8
  • 个人博客搭建完成,欢迎大家来访问哦黎默丶lymoo的博客 博主最近了解学习了一下angularJS,记录一下心得给...
    黎默丶lymoo阅读 1,002评论 0 21
  • 1. 介绍 AngularJS是一款由Google公司开发维护的前端MVC框架,其克服了HTML在构建应用上的诸多...
    崔皓翔阅读 791评论 0 5
  • 什么都缺,什么都需要努力,我希望爱上这种感觉,而不是妥协
    糖馒头阅读 81评论 0 0