Bootstrap transition.js 插件详解

Bootstrap transition.js 插件详解

时间 2015-01-27 12:12:00 博客园-原创精华区

原文  http://www.cnblogs.com/xyzhanjiang/p/4252513.html

主题 Bootstrap JavaScript

Bootstrap 自带的 JavaScript 插件的动画效果几乎都是使用 CSS 过渡实现的,而其中的 transition.js 就是为了判断当前使用的浏览器是否支持 CSS 过渡。下面先来简单了解下 CSS 过渡。

CSS 过渡

CSS 过渡是指在 CSS 属性发生改变时在一段时间内平滑地过渡,使用 CSS 伪类可以很方便地使用:

a {
  color: #333;
  transition: color 1s linear;
}

a:hover {
  color: #36f;
}

这里给链接设置了一个 1秒的颜色过渡效果,当鼠标经过链接激活链接 :hover 状态的时候文字的颜色会从黑色平滑地变化为蓝色,鼠标移开时又平滑地变回来。

仅仅依靠伪类来使用过渡显得太单调了,使用 JavaScript 来动态添加删除 class 才能尽情地玩弄过渡:

/* 这是一个圆 */
.circle {
  background-color: red;
  border-radius: 50%;
  height: 100px;
  margin-left: 220px;
  transition: transform 1s linear;
  width: 100px;
}

/* 添加 left 类水平向左偏移 200 像素 */
.circle.left {
  transform: translateX(-200px);
}

/* 添加 right 类水平向右偏移 200 像素 */
.circle.right {
  transform: translateX(200px);
}

JavaScript 的工作就是简单的删除和添加 class:

function toLeft() {
  $(‘.circle‘).removeClass(‘right‘).addClass(‘left‘);
}

function toRight() {
  $(‘.circle‘).removeClass(‘left‘).addClass(‘right‘);
}

你让它往左,它不敢往右! demo 上面的例子展示了当元素状态改变或者添加了某个 class 的时候过渡就开始发生了,那么如何知道过渡什么时候结束呢?

Transitionend 事件

想要知道过渡什么时候结束,就要监听 transitionend 事件(事件名称全是小写字母)。

$(‘.circle‘).one(‘transitionend‘, function() {
  alert(‘过渡结束啦!‘);
});

这里使用 one 方法而不是 on 方法是为了避免 transitionend 事件多次执行。 one 方法添加的事件回调只会执行一次,更多信息参考 官方 API

不过这只是标准的事件名称写法,在标准之前浏览器有各自的实现方式以及不同的事件名称(比如低版本的 Chrome 和 Safari 的该事件名称就叫 webkitTransitionEnd ),所以为了兼容更多的浏览器,一种比较笨拙的方式可以写成像下面这样:

$(‘.circle‘).one(‘transitionend webkitTransitionEnd oTransitionEnd otransitionend‘, function() {});

很长一串,而且这种写法还有一点问题!

在这里 可以看到为什么是上面这些事件名称,而没有 msTransitionEnd 之类。

为了根据浏览器更有针对性地添加 transitionend 事件回调,而不是像上面那样一骨碌地全加上,就需要先判断一下该浏览器到底支持哪种 transitionend 事件名称,判断方法则是根据浏览器支持 CSS 过渡的属性名称而定:

var el = document.createElement(‘bootstrap‘); // 创建一个元素用于测试

if (el.style.transition !== undefined) {
  // 判断元素的 style.transition 属性如果存在
  // 则以此类推该浏览器支持标准的 CSS transition 属性以及标准的 transitionend 事件
} else if (el.style.WebkitTransition !== undefined) {
  // 判断元素的 style.WebkitTransition 属性如果存在
  // 则该浏览器支持替代的 webkitTransitionEnd 事件
} else {...}

按照当前的主流浏览器趋势总共需要判断四种不同前缀的属性名称:

el.style.transition
el.style.WebkitTransition
el.style.MozTransition
el.style.OTransition

判断方式就是这样,废话就说到这里,直接上正牌代码,Bootstrap transition.js 内部的判断函数:

function transitionEnd() {
  // 创建一个元素用于测试
  var el = document.createElement(‘bootstrap‘);

  // 将所有主流浏览器实现方式整合成一个对象,用于遍历
  // key   是属性名称
  // value 是事件名称
  var transEndEventNames = {
    WebkitTransition : ‘webkitTransitionEnd‘,
    MozTransition    : ‘transitionend‘,
    OTransition      : ‘oTransitionEnd otransitionend‘,
    transition       : ‘transitionend‘
  };

  // 循环遍历上面那个对象,判断 CSS 属性是否存在
  for (var name in transEndEventNames) {
    if (el.style[name] !== undefined) {
      return { end: transEndEventNames[name] };
    }
  }

  return false;
}

执行该函数可以得到一个对象 {end: ‘transitionend‘} 或者 false (表示浏览器不支持 CSS 过渡),该对象的 end 属性保存着浏览器所支持的 transitionend 事件对应的名称:

var transition = transitionEnd();

比如我使用低版本的 Chrome 浏览器的话,那么得到的对象就是 {end: ‘webkitTransitionEnd‘} 这样;如果使用 IE 8 则是 false ,然后就可以添加该事件的回调函数了:

// 如果 transition 为 false 则不添加事件回调
transition && $(‘.circle‘).one(transition.end, function() {});

为了与 jQuery 保持一致,将该返回结果赋值到 $.support.transition 上:

$.support.transition = transitionEnd();

// 使用方式是类似的
$.support.transition && $(‘.circle‘).one($.support.transition.end, function() {});

EmulateTransitionEnd

事件名称的问题基本上解决了,但是这个事件有个问题就是有时根本不会触发,这是因为属性值没有发生变化或没有绘制行为发生。要确保每次回调都会被调用,我们增加一个定时器即可:

$.fn.emulateTransitionEnd = function(duration) {
  var called = false; // transitionend 事件是否已触发标识
  var $el = this;
  $(this).one($.support.transition.end, function () {
    called = true; // 表示已触发
  });
  var callback = function() {
    if (!called) {
      $($el).trigger($.support.transition.end); // 未触发,强制其触发
    }
  };
  setTimeout(callback, duration); // 一段时间后检测是否触发
  return this;
};

该方法的作用是一段时间(就是过渡持续的时间 transition-duration )过后如果 transitionend 事件没有发生则强制在该元素上触发这个事件。

$(‘.circle‘).one($.support.transition.end, function() {});
$(‘.circle‘).emulateTransitionEnd(1000); // 这个时间是过渡持续的时间

这样确保过渡之后一定会有回调。到这里,基本上就差不多了,不过 $.support.transition.end 好恶心啊!能不能像添加其它事件回调一样使用事件名称字符串的形式,比如 ‘click‘ ,当然可以。

自定义事件

$(function () {
  $.support.transition = transitionEnd();

  // 支持过渡的时候才执行后面的代码
  if (!$.support.transition) {return;}

  $.event.special.bsTransitionEnd = {
    bindType: $.support.transition.end,
    delegateType: $.support.transition.end,
    handle: function (e) {
      if ($(e.target).is(this)) {
        return e.handleObj.handler.apply(this, arguments);
      }
    }
  };
});

添加事件回调的时候就可以像这样:

$(‘.circle‘).one(‘bsTransitionEnd‘, function() {})
  .emulateTransitionEnd(1000);

其它

CSS 动画同样也有一个 animationend 事件,同时还有 animationstartanimationiteration 事件,可以参考这种方式自己写一个。

参考资料

时间: 2024-12-13 15:37:53

Bootstrap transition.js 插件详解的相关文章

开胃小菜——impress.js代码详解

README 友情提醒,下面有大量代码,由于网页上代码显示都是同一个颜色,所以推荐大家复制到自己的代码编辑器中看. 今天闲来无事,研究了一番impress.js的源码.由于之前研究过jQuery,看impress.js并没有遇到太大的阻碍,读代码用了一个小时,写这篇文章用了近三个小时,果然写文章比读代码费劲多了. 个人感觉impress.js的代码量(算上注释一共不到1000行)和难度(没有jQuery的各种black magic= =)都非常适合新手学习,所以写一个总结,帮助大家理解源码. 考

Node.js npm 详解

Node.js npm 详解 一.npm简介 安装npm请阅读前辈的文章,很详细的介绍. npm的全称:Node Package Manager. (1)通俗的理解 其实从字面意思就可以理解这个产品有什么作用翻译为"Node包管理器".对,就是Node的包的一个管理工具,目前我尝试的有 下载并安装包(npm install [pkg]) 升级安装包(npm update [pkg]) 卸载安装包(npm uninstall/rm [pkg]),可以指定卸载包的版本号 - 其实这些命令很

Bootstrap 各种进度条详解

一:默认的进度条 创建一个基本的进度条的步骤如下: 添加一个带有 class .progress 的 <div>. 接着,在上面的 <div> 内,添加一个带有 class .progress-bar 的空的 <div>. 添加一个带有百分比表示的宽度的 style 属性,例如 style="60%"; 表示进度条在 60% 的位置. 让我们看看下面的实例: <!DOCTYPE html> <html> <head>

jquery-ias插件详解

内容加载到底部的时候自动加载下一批的内容,如http://k.thea.cn/index.php?c=exam&a=visitor&tcid=640&classid=743,滚动条滚动到底部就加载下一部分的内容.要实现这样的效果,可以借助jquery-ias插件.具体用法参见:http://blog.csdn.net/wlm131127/article/details/12751803. jquery-ias插件详解,布布扣,bubuko.com

iOS插件详解之----CLangFormat(代码格式化管理插件)(2016.1.12王彬)

iOS插件详解之----CLangFormat(代码格式化管理)(2016.1.12王彬) 虽然在项目创建和团队组建的初期,我们就把公共约定以及一些规范定下来了,并且由于我们的代码是通过Git来做版本控制的,web上直接就支持Markdown格式的readme文件,可以随时看到最新的版本,但是这种规范只能依靠个人的意识,或者通过代码Review来解决,而且做代码Review的时候,你也不好意思总是写上一堆诸如“这里要加个空格”.“那里要加上换行”的评论吧?如果不管,久而久之,会因为每个人的习惯不

Android Studio如何导出可供Unity使用的aar插件详解 转

Android Studio如何导出可供Unity使用的aar插件详解 前言 项目之前使用Eclipse导出的jar文件来做与Android交互,最近因为工作需要需使用Android Studio的aar文件,网上参考了部分文章,也结合自己的理解重新整理一下具体的方法,通过写一个测试Demo来表述Android Studio创建aar的过程与及Unity如何使用aar文件,希望对刚好有这个需求的人能起到部分帮助与引导,同时如果文中有误希望也能不吝赐教. 版本信息 Unity 5.3.1f1, A

require(&#39;./expample.js).default详解

最近总碰到类似于 var a = require('./expample.js).default 这样的代码,感觉很奇葩,总结一波. 为什么会出现这个问题? import 是静态编译的,而 require 可以动态加载,也就是说你可以通过判断条件来决定什么时候去 require ,而 import 则不行,所以有时候我们会面临需要通过require 去导入一个es6模块(比如react-hot-loader官方demo :P) 当然,这只是场景之一. 前置知识 ES6 Module常用语法.譬如

玩转Bootstrap(JS插件篇)

模态弹出框 一次性导入: Bootstrap提供了一个单一的文件,这个文件包含了Bootstrap的所有JavaScript插件,即bootstrap.js(压缩版本:bootstrap.min.js). 具体使用如下(或见右侧代码编辑器28-29行): <!-导入jQuery版本库,因为Bootstrap的JavaScript插件依赖于jQuery --> <script src="http://libs.baidu.com/jquery/1.9.0/jquery.js&qu

Bootstrap的js插件之轮播(carousel)

轮播请查看以下示例,基本已经涵盖最常用的一个轮播 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>js插件_轮播</titl