5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LIFULLAdvent Calendar 2018

Day 25

jQuery scrollTopの引数について

Last updated at Posted at 2018-12-26

書くのが遅くなってしまいましたが、本記事は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

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

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やクリスマスにふさわしい話でもないですが、最近へーっとなったお話でした。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?