Edited at
LIFULLDay 25

jQuery scrollTopの引数について

書くのが遅くなってしまいましたが、本記事はLIFULL Advent Calendar 2018の25日目の記事になります。

今年ももう終わりそうですが、全然Qiitaに記事を書けていません。

個人的には、Vue.jsやBigQueryなど初めて触れる技術もあり、なかなか刺激が多い一年だったんですが、こういう場所でアウトプットするほどの内容でもなく。

毎年クリスマスにAdvent Calendarでなにか書く星のもとに生まれたので、先日へーっとなった件を書いておきます。


三行で



  • jQuery.scrollTopにはfunctionを引数で渡すことができる

  • 公式ドキュメントを見てもよくわからん

  • ソース頑張って追ったらわかった


はじめに

デバイス問わず、サイト内でユーザーのアクションに応じて画面をスクロールすることがあると思います。

jQueryを使って下記のような感じです。

// hoge要素をクリックしたら、fuga要素のトップまでスクロール

$('#hoge').on('click', function () {
// fuga要素のwindow内での高さを取得
var height = $('#fuga').offset().top;

$window).scrollTop(height);
});

最近ソースレビューをしていて、あれ?となったのですが、scrollTopの引数にfunctionを渡しても動きます。

$('#hoge').on('click', function () {

$window).scrollTop(getFugaTop);
});

// fuga要素のwindow内での高さを取得する
var getFugaTop = function () {
return $('#fuga').offset().top;
};

これが、下記のように関数実行していたら全然違和感なかったのですが、上記の通りfunction自体が渡せるのです。

// わかる

$window).scrollTop(getFugaTop());

// え??? でも動く
$window).scrollTop(getFugaTop);


公式ドキュメントを見てみる

https://api.jquery.com/scrollTop/


.scrollTop( value )

value

Type: Number

A number indicating the new position to set the scroll bar to.


だよね、数値渡すものだと思ってた。

わからぬ。


ソースを見てみる


offset.js

https://github.com/jquery/jquery/blob/master/src/offset.js#L199

長いけど大事なところなので全部引っ張ってきた。

// Create scrollLeft and scrollTop methods

jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
var top = "pageYOffset" === prop;

jQuery.fn[ method ] = function( val ) {
return access( this, function( elem, method, val ) {

// Coalesce documents and windows
var win;
if ( isWindow( elem ) ) {
win = elem;
} else if ( elem.nodeType === 9 ) {
win = elem.defaultView;
}

if ( val === undefined ) {
return win ? win[ prop ] : elem[ method ];
}

if ( win ) {
win.scrollTo(
!top ? val : win.pageXOffset,
top ? val : win.pageYOffset
);

} else {
elem[ method ] = val;
}
}, method, val, arguments.length );
};
} );

どうやらscrollTop,scrollLeftはなかでaccessという関数を使いながら、window.scrollToに委譲しているらしい。

accessってなにものだ?


access.js

https://github.com/jquery/jquery/blob/master/src/core/access.js

ファイル全部になっちゃうので要所だけ。

var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {

var i = 0,
len = elems.length,
bulk = key == null;

これのfnが上の関数ね。valueが呼び出し元の引数(今回の大元の引数)か。

if ( !isFunction( value ) ) {

raw = true;
}

お?valueがfunctionだとrawはいじられず、今回だとundefinedらしい。

if ( fn ) {

for ( ; i < len; i++ ) {
fn(
elems[ i ], key, raw ?
value :
value.call( elems[ i ], i, fn( elems[ i ], key ) )
);
}
}

scrollTop側のfnに戻って、第三引数のvalvalue.callになるんか!

しかもご親切にelementとかcallbackとしてfn渡してくれてたりでいろいろやれそう。

なんでこれがドキュメントに書いてないんだ??


最後に

これって多分scrollTopとかに限った話じゃなさそうですよね。

access経由で実装されているjQueryのメソッドなら同じことができそう。

https://github.com/jquery/jquery/search?l=JavaScript&q=access

例えば、、


https://github.com/jquery/jquery/blob/master/src/dimensions.js

// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods


なんだかAdvent Calendarやクリスマスにふさわしい話でもないですが、最近へーっとなったお話でした。