Zepto源码分析-动画(fx fx_method)模块

源码注释

//     Zepto.js
//     (c) 2010-2015 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($, undefined){
  var prefix = ‘‘, eventPrefix,    // prefix浏览器前缀 -webkit等,eventPrefix事件前缀
    vendors = { Webkit: ‘webkit‘, Moz: ‘‘, O: ‘o‘ }, //前缀数据源 不包含IE
    testEl = document.createElement(‘div‘),  //临时DIV容器
    supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, //变形检测
    transform,     //变形
    transitionProperty, transitionDuration, transitionTiming, transitionDelay,//过渡
    animationName, animationDuration, animationTiming, animationDelay,     //动画
    cssReset = {}

    //将驼峰字符串转成css属性,如aB-->a-b
  function dasherize(str) { return str.replace(/([a-z])([A-Z])/, ‘$1-$2‘).toLowerCase() }
    //修正事件名
  function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() }

    /**
     * 根据浏览器内核,设置CSS前缀,事件前缀
     * 如-webkit, css:-webkit-  event:webkit
     * 这里会在vendors存储webkit,moz,o三种前缀
     */
  $.each(vendors, function(vendor, event){
    if (testEl.style[vendor + ‘TransitionProperty‘] !== undefined) {
      prefix = ‘-‘ + vendor.toLowerCase() + ‘-‘
      eventPrefix = event
      return false
    }
  })

  transform = prefix + ‘transform‘     //变形
    //过渡
  cssReset[transitionProperty = prefix + ‘transition-property‘] =
  cssReset[transitionDuration = prefix + ‘transition-duration‘] =
  cssReset[transitionDelay    = prefix + ‘transition-delay‘] =
  cssReset[transitionTiming   = prefix + ‘transition-timing-function‘] =
  cssReset[animationName      = prefix + ‘animation-name‘] =
  cssReset[animationDuration  = prefix + ‘animation-duration‘] =
  cssReset[animationDelay     = prefix + ‘animation-delay‘] =
  cssReset[animationTiming    = prefix + ‘animation-timing-function‘] = ‘‘

    /**
     * 动画常量数据源
     * @type {{off: boolean, speeds: {_default: number, fast: number, slow: number}, cssPrefix: string, transitionEnd: *, animationEnd: *}}
     */
  $.fx = {
    off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), //能力检测是否支持动画,具体检测是否支持过渡,支持过渡事件
    speeds: { _default: 400, fast: 200, slow: 600 },
    cssPrefix: prefix,                                //css 前缀  如-webkit-
    transitionEnd: normalizeEvent(‘TransitionEnd‘), //过渡结束事件
    animationEnd: normalizeEvent(‘AnimationEnd‘)     //动画播放结束事件
  }

    /**
     * 创建自定义动画
     * @param properties  样式集
     * @param duration 持续事件
     * @param ease    速率
     * @param callback  完成时的回调
     * @param delay     动画延迟
     * @returns {*}
     */
  $.fn.animate = function(properties, duration, ease, callback, delay){
      //参数修正,传参为function(properties,callback)
    if ($.isFunction(duration))
      callback = duration, ease = undefined, duration = undefined
    if ($.isFunction(ease))  //传参为function(properties,duration,callback)
      callback = ease, ease = undefined
    if ($.isPlainObject(duration))  //传参为function(properties,{})
      ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration
      // duration 数字:持续时间  字符串:取speeds: { _default: 400, fast: 200, slow: 600 }对应数字
      if (duration) duration = (typeof duration == ‘number‘ ? duration :
                    ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000     //动画持续时间默认值
    if (delay) delay = parseFloat(delay) / 1000    //延迟时间,除以1000转换成s
    return this.anim(properties, duration, ease, callback, delay)
  }

    /**
     * 动画核心方法
     * @param properties  样式集
     * @param duration 持续事件
     * @param ease    速率
     * @param callback  完成时的回调
     * @param delay     动画延迟
     * @returns {*}
     */
  $.fn.anim = function(properties, duration, ease, callback, delay){
    var key, cssValues = {}, cssProperties, transforms = ‘‘,      // transforms 变形   cssValues设置给DOM的样式
        that = this, wrappedCallback, endEvent = $.fx.transitionEnd,
        fired = false

      //修正持续时间
    if (duration === undefined) duration = $.fx.speeds._default / 1000
    if (delay === undefined) delay = 0

      //如果浏览器不支持动画,持续时间设为0,直接跳动画结束
    if ($.fx.off) duration = 0

      // properties是动画名
    if (typeof properties == ‘string‘) {
      // keyframe animation
      cssValues[animationName] = properties
      cssValues[animationDuration] = duration + ‘s‘
      cssValues[animationDelay] = delay + ‘s‘
      cssValues[animationTiming] = (ease || ‘linear‘)
      endEvent = $.fx.animationEnd  //动画结束事件
    } else {  //properties 是样式集
      cssProperties = []
      // CSS transitions
      for (key in properties)
          //supportedTransforms.test(key) 正则检测是否为变形
      //key + ‘(‘ + properties[key] + ‘) ‘ 拼凑成变形方法
        if (supportedTransforms.test(key)) transforms += key + ‘(‘ + properties[key] + ‘) ‘
        else cssValues[key] = properties[key], cssProperties.push(dasherize(key))

        //变形统一存入  cssValues   cssProperties
      if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)

       // duration > 0可以播放动画,且properties是对象,表明为过渡,上面有字符串,则为animate
      if (duration > 0 && typeof properties === ‘object‘) {
        cssValues[transitionProperty] = cssProperties.join(‘, ‘)
        cssValues[transitionDuration] = duration + ‘s‘
        cssValues[transitionDelay] = delay + ‘s‘
        cssValues[transitionTiming] = (ease || ‘linear‘)  //默认线性速率
      }
    }

    //动画完成后的响应函数
    wrappedCallback = function(event){
      if (typeof event !== ‘undefined‘) {
        if (event.target !== event.currentTarget) return // makes sure the event didn‘t bubble from "below"
        $(event.target).unbind(endEvent, wrappedCallback)
      } else
        $(this).unbind(endEvent, wrappedCallback) // triggered by setTimeout

      fired = true
      $(this).css(cssReset)
      callback && callback.call(this)
    }

     //处理动画结束事件
    if (duration > 0){
        //绑定动画结束事件
      this.bind(endEvent, wrappedCallback)
      // transitionEnd is not always firing on older Android phones
      // so make sure it gets fired

        //延时ms后执行动画,注意这里加了25ms,保持endEvent,动画先执行完。
        //绑定过事件还做延时处理,是transitionEnd在older Android phones不一定触发
      setTimeout(function(){
          //如果触发过,就不处理
        if (fired) return
        wrappedCallback.call(that)
      }, ((duration + delay) * 1000) + 25)
    }

    // trigger page reflow so new elements can animate
      //主动触发页面回流,刷新DOM,让接下来设置的动画可以正确播放
      //更改 offsetTop、offsetLeft、 offsetWidth、offsetHeight;scrollTop、scrollLeft、scrollWidth、scrollHeight;clientTop、clientLeft、clientWidth、clientHeight;getComputedStyle() 、currentStyle()。这些都会触发回流。回流导致DOM重新渲染,平时要尽可能避免,但这里,为了动画即时生效播放,则主动触发回流,刷新DOM。
    this.size() && this.get(0).clientLeft

      //设置样式,启动动画
    this.css(cssValues)

    // duration为0,即浏览器不支持动画的情况,直接执行动画结束,执行回调。
    if (duration <= 0) setTimeout(function() {
      that.each(function(){ wrappedCallback.call(this) })
    }, 0)

    return this
  }

  testEl = null   //去掉不必要的数据存储,便于垃圾回收
})(Zepto)
//     Zepto.js
//     (c) 2010-2015 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($, undefined){
  var document = window.document, docElem = document.documentElement,
    origShow = $.fn.show, origHide = $.fn.hide, origToggle = $.fn.toggle// origShow展示    origHide隐藏  origToggle展示隐藏开关

    /**
     * 便捷动画的核心方法
     * @param el  DOM
     * @param speed 持续时间
     * @param opacity 不透明度
     * @param scale 缩放
     * @param callback 回调
     * @returns {*}
     */
  function anim(el, speed, opacity, scale, callback) {
      //修正参数  anim(el,callback)
    if (typeof speed == ‘function‘ && !callback) callback = speed, speed = undefined
    var props = { opacity: opacity }
    if (scale) {
      props.scale = scale
      el.css($.fx.cssPrefix + ‘transform-origin‘, ‘0 0‘)  //设置变形原点
    }
    return el.animate(props, speed, null, callback)//不支持速率变化,
  }

    /**
     * 底层方法:隐藏显示的元素
     * @param el
     * @param speed
     * @param scale
     * @param callback
     * @returns {*}
     */
  function hide(el, speed, scale, callback) {
    //不透明度设为0,即完全透明,相当于隐藏元素。这里的原理是播放不透明-透明的过渡。
     //具体代码为 $(dom).animate({opacity: 0, ‘-webkit-transform-origin‘: ‘0px 0px 0px‘, ‘-webkit-transform‘: ‘scale(0, 0)‘ },800)
       //设置了变形原点,缩放为0,它就会缩到左上角再透明
    return anim(el, speed, 0, scale, function(){
      origHide.call($(this)) //调用隐藏
      callback && callback.call(this)
    })
  }

    /**
     * 显示
     * @param speed  持续时间
     * @param callback   回调函数
     * @returns {*}
     */
  $.fn.show = function(speed, callback) {
    origShow.call(this)
      //具体代码为 $(dom).animate({opacity: 1, ‘-webkit-transform-origin‘: ‘0px 0px 0px‘, ‘-webkit-transform‘: ‘scale(1, 1)‘ },800)
      //设置了变形原点,缩放为0,它就会缩到左上角再透明
    if (speed === undefined) speed = 0
    else this.css(‘opacity‘, 0)
    return anim(this, speed, 1, ‘1,1‘, callback)
  }

    /**
     * 隐藏
     * @param speed      持续时间
     * @param callback   回调函数
     * @returns {*}
     */
  $.fn.hide = function(speed, callback) {
    if (speed === undefined) return origHide.call(this)
    else return hide(this, speed, ‘0,0‘, callback)
  }

    /**
     * 显示、隐藏开关
     * @param speed     持续时间
     * @param callback   回调函数
     * @returns {*}
     */
  $.fn.toggle = function(speed, callback) {
    if (speed === undefined || typeof speed == ‘boolean‘)
      return origToggle.call(this, speed)
    else return this.each(function(){
      var el = $(this)
      el[el.css(‘display‘) == ‘none‘ ? ‘show‘ : ‘hide‘](speed, callback)
    })
  }

    /**
     * 淡入淡出
     * 原理: $(dom).animate({opacity: 1/0, ‘-webkit-transform-origin‘: ‘0px 0px 0px‘},800)
     * @param speed  持续时间
     * @param opacity 不透明度
     * @param callback  回调函数
     * @returns {*}
     */
  $.fn.fadeTo = function(speed, opacity, callback) {
    return anim(this, speed, opacity, null, callback)
  }

    /**
     *  淡入
     * 原理: $(dom).animate({opacity: 1, ‘-webkit-transform-origin‘: ‘0px 0px 0px‘},800)
      * @param speed   持续时间
     * @param callback  回调函数
     * @returns {*}
     */
  $.fn.fadeIn = function(speed, callback) {
    var target = this.css(‘opacity‘)
    if (target > 0) this.css(‘opacity‘, 0)
    else target = 1
    return origShow.call(this).fadeTo(speed, target, callback)
  }

    /**
     *  淡出
     * 原理: $(dom).animate({opacity: 0, ‘-webkit-transform-origin‘: ‘0px 0px 0px‘},800)
     * @param speed   持续时间
     * @param callback  回调函数
     * @returns {*}
     */
  $.fn.fadeOut = function(speed, callback) {
    return hide(this, speed, null, callback)
  }

    /**
     * 淡入淡出开关
     * @param speed   持续时间
     * @param callback  回调函数
     * @returns {*}
     */
  $.fn.fadeToggle = function(speed, callback) {
    return this.each(function(){
      var el = $(this)
      el[
        (el.css(‘opacity‘) == 0 || el.css(‘display‘) == ‘none‘) ? ‘fadeIn‘ : ‘fadeOut‘
      ](speed, callback)
    })
  }

})(Zepto)

方法图

时间: 2024-11-09 17:30:00

Zepto源码分析-动画(fx fx_method)模块的相关文章

zepto源码分析系列

如果你也开发移动端web,如果你也用zepto,应该值得你看看.有问题请留言. Zepto源码分析-架构 Zepto源码分析-zepto(DOM)模块 Zepto源码分析-callbacks模块 Zepto源码分析-event模块 Zepto源码分析-ajax模块 Zepto源码分析-form模块 Zepto源码分析-deferred模块 Zepto源码分析-动画(fx fx_method)模块 内容一定要200字一定要200字内容一定要200字一定要200字内容一定要200字一定要200字内容

Zepto源码分析之二~三个API

由于时间关系:本次只对这三个API($.camelCase.$.contains.$.each)方法进行分析 第一个方法变量转驼峰:$.camelCase('hello-world-welcome'); 源码: var camelize; /** * 字符串替换 * 使用replace第二个参数带回调 */ camelize = function(str) { return str.replace(/-+(.)?/g, function(match, chr) { return chr ? ch

jQuery1.9.1源码分析--数据缓存Data模块

阅读目录 jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(elem, name, data)源码分析 internalRemoveData方法源码分析 internalData方法的源码分析 jQuery.fn.extend({data: function( key, value ) {}})源码分析 jQuery.extend({removeData: function( elem, name ) {}})源码分

Hadoop2源码分析-HDFS核心模块分析

1.概述 这篇博客接着<Hadoop2源码分析-RPC机制初识>来讲述,前面我们对MapReduce.序列化.RPC进行了分析和探索,对Hadoop V2的这些模块都有了大致的了解,通过对这些模块的研究,我们明白了MapReduce的运行流程以及内部的实现机制,Hadoop的序列化以及它的通信机制(RPC).今天我们来研究另一个核心的模块,那就是Hadoop的分布式文件存储系统——HDFS,下面是今天分享的内容目录: HDFS简述 NameNode DataNode 接下来,我们开始今天的分享

zepto源码分析-代码结构【转载】

本来想学习一下jQuery的源码,但由于jQuery的源码有10000多行,设计相当复杂,所以决定从zepto开始,分析一个成熟的框架的代码结构及执行步骤. 网上也有很多zepto的源码分析,有的给源码添加注释,有的谈与jQuery的不同,但是都没有系统的讲解zepto框架的代码结构及初始化Zepto对象的过程. 准备 默认你已经对面向对象有一定的了解,本文是边实践边写的,虽有些乱,但好处是为大家提供了分析的思路. 英文文档. 中文文档 注意在文中$变量表示一个函数对象,而$()表示执行函数,他

jQuery源码分析(九) 异步队列模块 Deferred 详解

deferred对象就是jQuery的回调函数解决方案,它解决了如何处理耗时操作的问题,比如一些Ajax操作,动画操作等.(P.s:紧跟上一节:https://www.cnblogs.com/greatdesert/p/11433365.html的内容) 异步队列有三种状态:待定(pending).成功(resolved)和失败(rejected),初始时处于pending状态 我们可以使用jQuery.Deferred创建一个异步队列,返回一个对象,该对象含有如下操作: done(fn/arr

jQuery 源码分析(十三) 数据操作模块 DOM属性 详解

jQuery的属性操作模块总共有4个部分,本篇说一下第2个部分:DOM属性部分,用于修改DOM元素的属性的(属性和特性是不一样的,一般将property翻译为属性,attribute翻译为特性) DOM属性的静态方法接口如下: prop(elem, name, value)    ;设置或读取DOM属性,有两种用法,如下 ·$.prop(elem,name,value)      ;传入第三个参数表示设置elem元素的name属性值为value ·$.prop(elem,name,)      

Zepto源码分析-deferred模块

源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT license. // // Some code (c) 2005, 2013 jQuery Foundation, Inc. and other contributors ;(function($){ var slice = Array.prototype.slice function Deferr

Zepto源码分析-form模块

源码注释 // Zepto.js // (c) 2010-2015 Thomas Fuchs // Zepto.js may be freely distributed under the MIT license. ;(function($){ /** * 序列表单内容为JSON数组 * 返回类似[{a1:1},{a2:2}]的数组 * @returns {Array} */ $.fn.serializeArray = function() { var name, type, result =