成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

讀Zepto源碼之Fx模塊

luzhuqun / 427人閱讀

摘要:綁定過(guò)渡或動(dòng)畫(huà)的結(jié)束事件綁定過(guò)渡或動(dòng)畫(huà)的結(jié)束事件,在動(dòng)畫(huà)結(jié)束時(shí),執(zhí)行處理過(guò)的回調(diào)函數(shù)。的回調(diào)執(zhí)行比動(dòng)畫(huà)時(shí)間長(zhǎng),目的是讓事件響應(yīng)在之前,如果瀏覽器支持過(guò)渡或動(dòng)畫(huà)事件,會(huì)在回調(diào)執(zhí)行時(shí)設(shè)置成,的回調(diào)函數(shù)不會(huì)再重復(fù)執(zhí)行。

fx 模塊為利用 CSS3 的過(guò)渡和動(dòng)畫(huà)的屬性為 Zepto 提供了動(dòng)畫(huà)的功能,在 fx 模塊中,只做了事件和樣式瀏覽器前綴的補(bǔ)全,沒(méi)有做太多的兼容。對(duì)于不支持 CSS3 過(guò)渡和動(dòng)畫(huà)的, Zepto 的處理也相對(duì)簡(jiǎn)單,動(dòng)畫(huà)立即完成,馬上執(zhí)行回調(diào)。

讀 Zepto 源碼系列文章已經(jīng)放到了github上,歡迎star: reading-zepto

源碼版本

本文閱讀的源碼為 zepto1.2.0

GitBook

《reading-zepto》

內(nèi)部方法 dasherize
function dasherize(str) { return str.replace(/([A-Z])/g, "-$1").toLowerCase() }

這個(gè)方法是將駝峰式( camleCase )的寫(xiě)法轉(zhuǎn)換成用 - 連接的連詞符的寫(xiě)法( camle-case )。轉(zhuǎn)換的目的是讓寫(xiě)法符合 css 的樣式規(guī)范。

normalizeEvent
function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() }

為事件名增加瀏覽器前綴。

為事件和樣式增加瀏覽器前綴 變量
var prefix = "", eventPrefix,
    vendors = { Webkit: "webkit", Moz: "", O: "o" },
    testEl = document.createElement("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 = {}

vendors 定義了瀏覽器的樣式前綴( key ) 和事件前綴 ( value ) 。

testEl 是為檢測(cè)瀏覽器前綴所創(chuàng)建的臨時(shí)節(jié)點(diǎn)。

cssReset 用來(lái)保存加完前綴后的樣式規(guī)則,用來(lái)過(guò)渡或動(dòng)畫(huà)完成后重置樣式。

瀏覽器前綴檢測(cè)
if (testEl.style.transform === undefined) $.each(vendors, function(vendor, event){
  if (testEl.style[vendor + "TransitionProperty"] !== undefined) {
    prefix = "-" + vendor.toLowerCase() + "-"
    eventPrefix = event
    return false
  }
})

檢測(cè)到瀏覽器不支持標(biāo)準(zhǔn)的 transform 屬性,則依次檢測(cè)加了不同瀏覽器前綴的 transitionProperty 屬性,直至找到合適的瀏覽器前綴,樣式前綴保存在 prefix 中, 事件前綴保存在 eventPrefix 中。

初始化樣式
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"] = ""

獲取瀏覽器前綴后,為所有的 transitionanimation 屬性加上對(duì)應(yīng)的前綴,都初始化為 "",方便后面使用。

方法 $.fx
$.fx = {
  off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),
  speeds: { _default: 400, fast: 200, slow: 600 },
  cssPrefix: prefix,
  transitionEnd: normalizeEvent("TransitionEnd"),
  animationEnd: normalizeEvent("AnimationEnd")
}

off: 表示瀏覽器是否支持過(guò)渡或動(dòng)畫(huà),如果既沒(méi)有瀏覽器前綴,也不支持標(biāo)準(zhǔn)的屬性,則判定該瀏覽器不支持動(dòng)畫(huà)

speeds: 定義了三種動(dòng)畫(huà)持續(xù)的時(shí)間, 默認(rèn)為 400ms

cssPrefix: 樣式瀏覽器兼容前綴,即 prefix

transitionEnd: 過(guò)渡完成時(shí)觸發(fā)的事件,調(diào)用 normalizeEvent 事件加了瀏覽器前綴補(bǔ)全

animationEnd: 動(dòng)畫(huà)完成時(shí)觸發(fā)的事件,同樣加了瀏覽器前綴補(bǔ)全

animate
$.fn.animate = function(properties, duration, ease, callback, delay){
  if ($.isFunction(duration))
    callback = duration, ease = undefined, duration = undefined
  if ($.isFunction(ease))
    callback = ease, ease = undefined
  if ($.isPlainObject(duration))
    ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration
  if (duration) duration = (typeof duration == "number" ? duration :
                            ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000
  if (delay) delay = parseFloat(delay) / 1000
  return this.anim(properties, duration, ease, callback, delay)
}

我們平時(shí)用得最多的是 animate 這個(gè)方法,但是這個(gè)方法最終調(diào)用的是 anim 這個(gè)方法,animate 這個(gè)方法相當(dāng)靈活,因?yàn)樗饕龅氖菂?shù)修正的工作,做得參數(shù)適應(yīng) anim 的接口。

參數(shù):

properties:需要過(guò)渡的樣式對(duì)象,或者 animation 的名稱,只有這個(gè)參數(shù)是必傳的

duration: 過(guò)渡時(shí)間

ease: 緩動(dòng)函數(shù)

callback: 過(guò)渡或者動(dòng)畫(huà)完成后的回調(diào)函數(shù)

delay: 過(guò)渡或動(dòng)畫(huà)延遲執(zhí)行的時(shí)間

修正參數(shù)
if ($.isFunction(duration))
  callback = duration, ease = undefined, duration = undefined

這是處理傳參為 animate(properties, callback) 的情況。

if ($.isFunction(ease))
    callback = ease, ease = undefined

這是處理 animate(properties, duration, callback) 的情況,此時(shí) callback 在參數(shù) ease 的位置

if ($.isPlainObject(duration))
  ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration

這是處理 animate(properties, { duration: msec, easing: type, complete: fn }) 的情況。除了 properties ,后面的參數(shù)還可以寫(xiě)在一個(gè)對(duì)象中傳入。

如果檢測(cè)到為對(duì)象的傳參方式,則將對(duì)應(yīng)的值從對(duì)象中取出。

if (duration) duration = (typeof duration == "number" ? duration :
                          ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000

如果過(guò)渡時(shí)間為數(shù)字,則直接采用,如果是 speeds 中指定的 key ,即 slowfast 甚至 _default ,則從 speeds 中取值,否則用 speends_default 值。

因?yàn)樵跇邮街惺怯?s 取值,所以要將毫秒數(shù)除 1000。

if (delay) delay = parseFloat(delay) / 1000

也將延遲時(shí)間轉(zhuǎn)換為秒。

anim
$.fn.anim = function(properties, duration, ease, callback, delay){
  var key, cssValues = {}, cssProperties, transforms = "",
      that = this, wrappedCallback, endEvent = $.fx.transitionEnd,
      fired = false

  if (duration === undefined) duration = $.fx.speeds._default / 1000
  if (delay === undefined) delay = 0
  if ($.fx.off) duration = 0

  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 {
    cssProperties = []
    // CSS transitions
    for (key in properties)
      if (supportedTransforms.test(key)) transforms += key + "(" + properties[key] + ") "
    else cssValues[key] = properties[key], cssProperties.push(dasherize(key))

    if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)
    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
    setTimeout(function(){
      if (fired) return
      wrappedCallback.call(that)
    }, ((duration + delay) * 1000) + 25)
  }

  // trigger page reflow so new elements can animate
  this.size() && this.get(0).clientLeft

  this.css(cssValues)

  if (duration <= 0) setTimeout(function() {
    that.each(function(){ wrappedCallback.call(this) })
  }, 0)

  return this
}

animation 最終調(diào)用的是 anim 方法,Zepto 也將這個(gè)方法暴露了出去,其實(shí)我覺(jué)得只提供 animation 方法就可以了,這個(gè)方法完全可以作為私有的方法調(diào)用。

參數(shù)默認(rèn)值
if (duration === undefined) duration = $.fx.speeds._default / 1000
if (delay === undefined) delay = 0
if ($.fx.off) duration = 0

如果沒(méi)有傳遞持續(xù)時(shí)間 duration ,則默認(rèn)為 $.fx.speends._default 的定義值 400ms ,這里需要轉(zhuǎn)換成 s

如果沒(méi)有傳遞 delay ,則默認(rèn)不延遲,即 0 。

如果瀏覽器不支持過(guò)渡和動(dòng)畫(huà),則 duration 設(shè)置為 0 ,即沒(méi)有動(dòng)畫(huà),立即執(zhí)行回調(diào)。

處理animation動(dòng)畫(huà)參數(shù)
if (typeof properties == "string") {
  // keyframe animation
  cssValues[animationName] = properties
  cssValues[animationDuration] = duration + "s"
  cssValues[animationDelay] = delay + "s"
  cssValues[animationTiming] = (ease || "linear")
  endEvent = $.fx.animationEnd
} 

如果 propertiesstring, 即 properties 為動(dòng)畫(huà)名,則設(shè)置動(dòng)畫(huà)對(duì)應(yīng)的 cssdurationdelay 都加上了 s 的單位,默認(rèn)的緩動(dòng)函數(shù)為 linear 。

處理transition參數(shù)
else {
  cssProperties = []
  // CSS transitions
  for (key in properties)
    if (supportedTransforms.test(key)) transforms += key + "(" + properties[key] + ") "
  else cssValues[key] = properties[key], cssProperties.push(dasherize(key))

  if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)
  if (duration > 0 && typeof properties === "object") {
    cssValues[transitionProperty] = cssProperties.join(", ")
    cssValues[transitionDuration] = duration + "s"
    cssValues[transitionDelay] = delay + "s"
    cssValues[transitionTiming] = (ease || "linear")
  }
}

supportedTransforms 是用來(lái)檢測(cè)是否為 transform 的正則,如果是 transform ,則拼接成符合 transform 規(guī)則的字符串。

否則,直接將值存入 cssValues 中,將 css 的樣式名存入 cssProperties 中,并且調(diào)用了 dasherize 方法,使得 propertiescss 樣式名( key )支持駝峰式的寫(xiě)法。

if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)

這段是檢測(cè)是否有 transform ,如果有,也將 transform 存入 cssValuescssProperties 中。

接下來(lái)判斷動(dòng)畫(huà)是否開(kāi)啟,并且是否有過(guò)渡屬性,如果有,則設(shè)置對(duì)應(yīng)的值。

回調(diào)函數(shù)的處理
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)
}

如果瀏覽器支持過(guò)渡或者動(dòng)畫(huà)事件,則在動(dòng)畫(huà)結(jié)束的時(shí)候,取消事件監(jiān)聽(tīng),注意在 unbind 時(shí),有個(gè) event.target !== event.currentTarget 的判定,這是排除冒泡事件。

如果事件不存在時(shí),直接取消對(duì)應(yīng)元素上的事件監(jiān)聽(tīng)。

并且將狀態(tài)控制 fired 設(shè)置為 true ,表示回調(diào)已經(jīng)執(zhí)行。

動(dòng)畫(huà)完成后,再將涉及過(guò)渡或動(dòng)畫(huà)的樣式設(shè)置為空。

最后,調(diào)用傳遞進(jìn)來(lái)的回調(diào)函數(shù),整個(gè)動(dòng)畫(huà)完成。

綁定過(guò)渡或動(dòng)畫(huà)的結(jié)束事件
if (duration > 0){
  this.bind(endEvent, wrappedCallback)
  setTimeout(function(){
    if (fired) return
    wrappedCallback.call(that)
  }, ((duration + delay) * 1000) + 25)
}

綁定過(guò)渡或動(dòng)畫(huà)的結(jié)束事件,在動(dòng)畫(huà)結(jié)束時(shí),執(zhí)行處理過(guò)的回調(diào)函數(shù)。

注意這里有個(gè) setTimeout ,是避免瀏覽器不支持過(guò)渡或動(dòng)畫(huà)事件時(shí),可以通過(guò) setTimeout 執(zhí)行回調(diào)。setTimeout 的回調(diào)執(zhí)行比動(dòng)畫(huà)時(shí)間長(zhǎng) 25ms ,目的是讓事件響應(yīng)在 setTimeout 之前,如果瀏覽器支持過(guò)渡或動(dòng)畫(huà)事件, fired 會(huì)在回調(diào)執(zhí)行時(shí)設(shè)置成 true, setTimeout 的回調(diào)函數(shù)不會(huì)再重復(fù)執(zhí)行。

觸發(fā)頁(yè)面回流
 // trigger page reflow so new elements can animate
this.size() && this.get(0).clientLeft

this.css(cssValues)

這里用了點(diǎn)黑科技,讀取 clientLeft 屬性,觸發(fā)頁(yè)面的回流,使得動(dòng)畫(huà)的樣式設(shè)置上去時(shí)可以立即執(zhí)行。

具體可以這篇文章中的解釋:2014-02-07-hidden-documentation.md

過(guò)渡時(shí)間不大于零的回調(diào)處理
if (duration <= 0) setTimeout(function() {
  that.each(function(){ wrappedCallback.call(this) })
}, 0)

duration 不大于零時(shí),可以是參數(shù)設(shè)置錯(cuò)誤,也可能是瀏覽器不支持過(guò)渡或動(dòng)畫(huà),就立即執(zhí)行回調(diào)函數(shù)。

系列文章

讀Zepto源碼之代碼結(jié)構(gòu)

讀Zepto源碼之內(nèi)部方法

讀Zepto源碼之工具函數(shù)

讀Zepto源碼之神奇的$

讀Zepto源碼之集合操作

讀Zepto源碼之集合元素查找

讀Zepto源碼之操作DOM

讀Zepto源碼之樣式操作

讀Zepto源碼之屬性操作

讀Zepto源碼之Event模塊

讀Zepto源碼之IE模塊

讀Zepto源碼之Callbacks模塊

讀Zepto源碼之Deferred模塊

讀Zepto源碼之Ajax模塊

讀Zepto源碼之Assets模塊

讀Zepto源碼之Selector模塊

讀Zepto源碼之Touch模塊

讀Zepto源碼之Gesture模塊

讀Zepto源碼之IOS3模塊

附文

譯:怎樣處理 Safari 移動(dòng)端對(duì)圖片資源的限制

參考

一步一步DIY zepto庫(kù),研究zepto源碼7--動(dòng)畫(huà)模塊(fx fx_method)/)

How (not) to trigger a layout in WebKit

2014-02-07-hidden-documentation.md

License

署名-非商業(yè)性使用-禁止演繹 4.0 國(guó)際 (CC BY-NC-ND 4.0)

最后,所有文章都會(huì)同步發(fā)送到微信公眾號(hào)上,歡迎關(guān)注,歡迎提意見(jiàn):

作者:對(duì)角另一面

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88915.html

相關(guān)文章

  • Zepto源碼fx_methods模塊

    摘要:所以模塊依賴于模塊,在引入前必須引入模塊。原有的方法分析見(jiàn)讀源碼之樣式操作方法首先調(diào)用原有的方法,將元素顯示出來(lái),這是實(shí)現(xiàn)動(dòng)畫(huà)的基本條件。如果沒(méi)有傳遞,或者為值,則表示不需要?jiǎng)赢?huà),調(diào)用原有的方法即可。 fx 模塊提供了 animate 動(dòng)畫(huà)方法,fx_methods 利用 animate 方法,提供一些常用的動(dòng)畫(huà)方法。所以 fx_methods 模塊依賴于 fx 模塊,在引入 fx_m...

    junbaor 評(píng)論0 收藏0
  • Zepto源碼Stack模塊

    摘要:讀源碼系列文章已經(jīng)放到了上,歡迎源碼版本本文閱讀的源碼為改寫(xiě)原有的方法模塊改寫(xiě)了以上這些方法,這些方法在調(diào)用的時(shí)候,會(huì)為返回的結(jié)果添加的屬性,用來(lái)保存原來(lái)的集合。方法的分析可以看讀源碼之模塊。 Stack 模塊為 Zepto 添加了 addSelf 和 end 方法。 讀 Zepto 源碼系列文章已經(jīng)放到了github上,歡迎star: reading-zepto 源碼版本 本文閱讀的...

    crossea 評(píng)論0 收藏0
  • Zepto源碼Form模塊

    摘要:模塊處理的是表單提交。表單提交包含兩部分,一部分是格式化表單數(shù)據(jù),另一部分是觸發(fā)事件,提交表單。最終返回的結(jié)果是一個(gè)數(shù)組,每個(gè)數(shù)組項(xiàng)為包含和屬性的對(duì)象。否則手動(dòng)綁定事件,如果沒(méi)有阻止瀏覽器的默認(rèn)事件,則在第一個(gè)表單上觸發(fā),提交表單。 Form 模塊處理的是表單提交。表單提交包含兩部分,一部分是格式化表單數(shù)據(jù),另一部分是觸發(fā) submit 事件,提交表單。 讀 Zepto 源碼系列文章已...

    陳江龍 評(píng)論0 收藏0
  • Zepto源碼Data模塊

    摘要:的模塊用來(lái)獲取節(jié)點(diǎn)中的屬性的數(shù)據(jù),和儲(chǔ)存跟相關(guān)的數(shù)據(jù)。獲取節(jié)點(diǎn)指定的緩存值。如果存在,則刪除指定的數(shù)據(jù),否則將緩存的數(shù)據(jù)全部刪除。為所有下級(jí)節(jié)點(diǎn),如果為方法,則節(jié)點(diǎn)自身也是要被移除的,所以需要將自身也加入到節(jié)點(diǎn)中。 Zepto 的 Data 模塊用來(lái)獲取 DOM 節(jié)點(diǎn)中的 data-* 屬性的數(shù)據(jù),和儲(chǔ)存跟 DOM 相關(guān)的數(shù)據(jù)。 讀 Zepto 源碼系列文章已經(jīng)放到了github上,歡...

    wua_wua2012 評(píng)論0 收藏0
  • Zepto源碼Gesture模塊

    摘要:模塊基于上的事件的封裝,利用屬性,封裝出系列事件。這個(gè)判斷需要引入設(shè)備偵測(cè)模塊。然后是監(jiān)測(cè)事件,根據(jù)這三個(gè)事件,可以組合出和事件。其中變量對(duì)象和模塊中的對(duì)象的作用差不多,可以先看看讀源碼之模塊對(duì)模塊的分析。 Gesture 模塊基于 IOS 上的 Gesture 事件的封裝,利用 scale 屬性,封裝出 pinch 系列事件。 讀 Zepto 源碼系列文章已經(jīng)放到了github上,歡...

    coolpail 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<