Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
mominger opened this issue Jun 25, 2015 · 0 comments
Open

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

mominger opened this issue Jun 25, 2015 · 0 comments

Comments

@mominger
Copy link
Owner

源码注释

//     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前缀事件前缀
     * -webkitcss-webkit-  event:webkit
     * 这里会在vendors存储webkitmozo三种前缀
     */
  $.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,durationcallback)
      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让接下来设置的动画可以正确播放
      //更改 offsetTopoffsetLeftoffsetWidthoffsetHeightscrollTopscrollLeftscrollWidthscrollHeightclientTopclientLeftclientWidthclientHeightgetComputedStyle() 、currentStyle()。这些都会触发回流回流导致DOM重新渲染平时要尽可能避免但这里为了动画即时生效播放则主动触发回流刷新DOMthis.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 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前缀事件前缀
     * -webkitcss-webkit-  event:webkit
     * 这里会在vendors存储webkitmozo三种前缀
     */
  $.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,durationcallback)
      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让接下来设置的动画可以正确播放
      //更改 offsetTopoffsetLeftoffsetWidthoffsetHeightscrollTopscrollLeftscrollWidthscrollHeightclientTopclientLeftclientWidthclientHeightgetComputedStyle() 、currentStyle()。这些都会触发回流回流导致DOM重新渲染平时要尽可能避免但这里为了动画即时生效播放则主动触发回流刷新DOMthis.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)

API

form 2 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant