ホームページ ウェブフロントエンド jsチュートリアル Sticky コンポーネントの改善された実装に関する簡単な説明_JavaScript スキル

Sticky コンポーネントの改善された実装に関する簡単な説明_JavaScript スキル

May 16, 2016 pm 03:10 PM

前の記事getBoundingClientRect メソッドを使用して単純なスティッキー コンポーネントを実装する では、スティッキー コンポーネントの単純な実装を紹介しましたが、ここ 2 日間考えた結果、さらに多くの実装が提供されていることがわかりました。欠点は、前回提供した修正方法が不十分だったことを踏まえて、他の Web サイトで得られる効果が若干異なることです。この記事では、スティッキー コンポーネントの改良版を提供します。完了しました。興味を持って読んでいただければ幸いです。

1. 古いバージョンの問題

前のスティッキーコンポーネントの実装には複数の問題があります:

まず、スティッキーの効果についてですが、スティッキー要素を修正する前と後で変化しないのは、ブラウザの左側からの相対的な位置と、スティッキー要素の全体の幅です。ブラウザの上部または下部を基準とした位置とスティッキー要素の高さ。後者の 2 つの変化する値は定数値とみなされます。上限値または下限値が固定されているのに常に 0 になるのはなぜですか?もちろん、上: 20px、下: 15px など、0 以外の値にすることもできます。ブートストラップの公式ドキュメントで使用されている接辞コンポーネントの例のように、シーンによっては、そのようなオフセットを追加すると、スティッキー効果がより良く見えます。コンポーネント この機能は、この記事で実装されているスティッキー コンポーネントに似ています):

固定時はブラウザ上部からの相対位置をtop:20pxに設定します。スティッキー要素の高さについても同様であり、固定したときに見栄えの良い効果を表示するには、元の Line-height や Padding-top などの高さ関連の属性を調整することが非常に一般的です。 Tmall Huabei のこのページ、このブロック コンテンツはスティッキー コンポーネントを使用しています:

固定される前のスティッキー要素の高さは次のとおりです:

固定後のスティッキー要素の高さは次のとおりです:

2番目に、固定を解除する場合、上部に固定されているスティッキー要素を例にとります。上記の実装では、ターゲット要素とブラウザの上部の間の距離が離れたときに、スティッキー要素の位置を直接キャンセルします。 StickyHeight: 固定属性より小さい場合、sticky 要素は直ちに通常のドキュメント フローに復元され、その効果は次のとおりです:

臨界点に達するとすぐに消えますが、天猫花北の効果は次のようなものではありません:

臨界点に達してもすぐには消えませんが、スクロール バーと連動して Web ページのメイン コンテンツと一緒に上にスクロールできるように、スティッキー要素の上部の値を再調整します。

経験の観点から、Tmall Huabei の効果が優れていることは明らかです。機能の観点からは、上記の実装には致命的な欠点があります。スティッキー要素の高さが非常に大きい場合、ブラウザの能力を超えているため、どのようにスクロールしてもスティッキー要素の内容をすべて閲覧できないというバグが発生します。興味がある場合は、前回実装したコードを試してみてください。ブログのサイドバー。試してみたところこの問題が見つかったので、sticky コンポーネントを改善したいと思いました: (
第三に、最後の実装にはまだいくつかの欠点があります:

1) documentElement.clientHeight はキャッシュされないため、重要なポイントが判断されるたびに再取得されます:

2) スクロール コールバック間隔のデフォルト値は大きすぎるため、今回は 5 に設定し、ブートストラップでは 1 を使用します。この方法でのみ効果が保証されます。

3) 一部のシナリオでは、サイズ変更が必要な場合にスティッキー要素の幅をリセットする必要がない場合があります。それを制御するためのオプションを追加する必要があります。

4) スティッキー要素が固定されている場合と固定されていない場合、他のコンポーネントがこのコンポーネントに依存するときに重要なポイントで処理できるように、コールバック関数を提供する必要があります。

2. 改善方法

コンポーネントのオプションが再定義されました:

var DEFAULTS = {
target: '', //target元素的jq选择器
type: 'top', //固定的位置,top | bottom,默认为top,表示固定在顶部
wait: 5, //scroll事件回调的间隔
stickyOffset: 0, //固定时距离浏览器可视区顶部或底部的偏移,用来设置top跟bottom属性的值,默认为0
isFixedWidth: true, //sticky元素宽度是否固定,默认为true,如果是自适应的宽度,需设置为false
getStickyWidth: undefined, //用来获取sticky元素宽度的回调,在不传该参数的情况下,stickyWidth将设置为sticky元素的offsetWidth
unStickyDistance: undefined, //该参数决定sticky元素何时进入dynamicSticky状态
onSticky: undefined, ///sticky元素固定时的回调
onUnSticky: undefined ///sticky元素取消固定时的回调
};
ログイン後にコピー

太字のものは新規または変更されたもので、元の高さが削除され、unStickyDistance に置き換えられています。固定する場合はstickyOffsetでブラウザの上部または下部からの相対位置を指定するため、.sticky--in-topや.sticky--inのcssにtopやbottomの属性値を記述する必要はありません。 -底。 isFixedWidth が false の場合、サイズ変更中にスティッキー要素の幅を更新するためのコールバックが追加されます:


!opts.isFixedWidth && $win.resize(throttle(function () {
setStickyWidth();
$elem.hasClass(className) && $elem.css('width', stickyWidth);
sticky();
}, opts.wait));
ログイン後にコピー

前回と比べて今回の実装で問題となったのは、固定を解除する際の論理処理です。前回はsticky要素がstickyとunstickyの2つの状態に分かれていました。 staticStickyとdynamicStickyで、前者は上値または下値が変わらないスティッキー状態を表し、後者は上値または下値が変化するスティッキー状態を表します。この問題をより明確に解決するために、本来の判断は、クリティカル ポイントと、異なるクリティカル ポイントで異なる処理を実行するコードを次のように再構成します。

setSticky = function () {
!$elem.hasClass(className) && $elem.addClass(className).css('width', stickyWidth)
&& (typeof opts.onSticky == 'function' && opts.onSticky($elem, $target));
return true;
},
states = {
staticSticky: function () {
setSticky() && $elem.css(opts.type, opts.stickyOffset);
},
dynamicSticky: function (rect) {
setSticky() && $elem.css(opts.type, rules[opts.type].getDynamicOffset(rect));
},
unSticky: function () {
$elem.hasClass(className) && $elem.removeClass(className).css('width', '').css(opts.type, '')
&& (typeof opts.onUnSticky == 'function' && opts.onUnSticky($elem, $target));
}
},
rules = {
top: {
getState: function (rect) {
if (rect.top < 0 && (rect.bottom - unStickyDistance) > 0) return 'staticSticky';
else if ((rect.bottom - unStickyDistance) <= 0 && rect.bottom > 0) return 'dynamicSticky';
else return 'unSticky';
},
getDynamicOffset: function (rect) {
return -(unStickyDistance - rect.bottom);
}
},
bottom: {
getState: function (rect) {
if (rect.bottom > docClientHeight && (rect.top + unStickyDistance) < docClientHeight) return 'staticSticky';
else if ((rect.top + unStickyDistance) >= docClientHeight && rect.top < docClientHeight) return 'dynamicSticky';
else return 'unSticky';
},
getDynamicOffset: function (rect) {
return -(unStickyDistance + rect.top - docClientHeight);
}
}
}
$win.scroll(throttle(sticky, opts.wait));
function sticky() {
var rect = $target[0].getBoundingClientRect(),
curState = rules[opts.type].getState(rect);
states[curState](rect);
}
ログイン後にコピー
そこには状態モデルの考え方が少し含まれていますが、より簡潔です。このコードを書いたとき、私は以前に学んだステート マシンを使用したかったのですが、ステート マシンを使用してそれを書くことは確かに可能だと思いましたが、参照されないようにするためのクラス ライブラリを 1 つだけ作成したかったのです。いつかステートマシンを練習したいときにもう一度試してください。

全体的な実装は次のとおりです:

var Sticky = (function ($) {
function throttle(func, wait) {
var timer = null;
return function () {
var self = this, args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
return typeof func === 'function' && func.apply(self, args);
}, wait);
}
}
var DEFAULTS = {
target: '', //target元素的jq选择器
type: 'top', //固定的位置,top | bottom,默认为top,表示固定在顶部
wait: 5, //scroll事件回调的间隔
stickyOffset: 0, //固定时距离浏览器可视区顶部或底部的偏移,用来设置top跟bottom属性的值,默认为0
isFixedWidth: true, //sticky元素宽度是否固定,默认为true,如果是自适应的宽度,需设置为false
getStickyWidth: undefined, //用来获取sticky元素宽度的回调,在不传该参数的情况下,stickyWidth将设置为sticky元素的offsetWidth
unStickyDistance: undefined, //该参数决定sticky元素何时进入dynamicSticky状态
onSticky: undefined, ///sticky元素固定时的回调
onUnSticky: undefined ///sticky元素取消固定时的回调
};
return function (elem, opts) {
var $elem = $(elem);
opts = $.extend({}, DEFAULTS, opts || {}, $elem.data() || {});
var $target = $(opts.target);
if (!$elem.length || !$target.length) return;
var stickyWidth,
setStickyWidth = function () {
stickyWidth = typeof opts.getStickyWidth === 'function' && opts.getStickyWidth($elem) || $elem[0].offsetWidth;
},
docClientHeight = document.documentElement.clientHeight,
unStickyDistance = opts.unStickyDistance || $elem[0].offsetHeight,
setSticky = function () {
!$elem.hasClass(className) && $elem.addClass(className).css('width', stickyWidth)
&& (typeof opts.onSticky == 'function' && opts.onSticky($elem, $target));
return true;
},
states = {
staticSticky: function () {
setSticky() && $elem.css(opts.type, opts.stickyOffset);
},
dynamicSticky: function (rect) {
setSticky() && $elem.css(opts.type, rules[opts.type].getDynamicOffset(rect));
},
unSticky: function () {
$elem.hasClass(className) && $elem.removeClass(className).css('width', '').css(opts.type, '')
&& (typeof opts.onUnSticky == 'function' && opts.onUnSticky($elem, $target));
}
},
rules = {
top: {
getState: function (rect) {
if (rect.top < 0 && (rect.bottom - unStickyDistance) > 0) return 'staticSticky';
else if ((rect.bottom - unStickyDistance) <= 0 && rect.bottom > 0) return 'dynamicSticky';
else return 'unSticky';
},
getDynamicOffset: function (rect) {
return -(unStickyDistance - rect.bottom);
}
},
bottom: {
getState: function (rect) {
if (rect.bottom > docClientHeight && (rect.top + unStickyDistance) < docClientHeight) return 'staticSticky';
else if ((rect.top + unStickyDistance) >= docClientHeight && rect.top < docClientHeight) return 'dynamicSticky';
else return 'unSticky';
},
getDynamicOffset: function (rect) {
return -(unStickyDistance + rect.top - docClientHeight);
}
}
},
className = 'sticky--in-' + opts.type,
$win = $(window);
setStickyWidth();
$win.scroll(throttle(sticky, opts.wait));
!opts.isFixedWidth && $win.resize(throttle(function () {
setStickyWidth();
$elem.hasClass(className) && $elem.css('width', stickyWidth);
sticky();
}, opts.wait));
$win.resize(throttle(function () {
docClientHeight = document.documentElement.clientHeight;
}, opts.wait));
function sticky() {
var rect = $target[0].getBoundingClientRect(),
curState = rules[opts.type].getState(rect);
states[curState](rect);
}
}
})(jQuery);
ログイン後にコピー
理解するのが難しいのは、getState メソッドのロジックかもしれません。この部分のアイデアの一部は、前のブログで詳しく説明されています。

3. ブログサイドバーの適用手順

まず、この実装をブログ設定のフッター HTML テキスト フィールドに貼り付けてから、次のコードを追加して初期化する必要があります:


var timer = setInterval(function(){
if($('#blogCalendar').length && $('#profile_block').length && $('#sidebar_search').length) {
new Sticky('#sideBar', {
target: '#main',
onSticky: function($elem, $target){
$target.css('min-height',$elem.outerHeight());
$elem.css('left', '65px');
},
onUnSticky: function($elem, $target){
$target.css('min-height','');
$elem.css('left', '');
}
});
}
},100);
ログイン後にコピー
サイドバーのコンテンツは ajax によってロードされ、これらの ajax リクエスト中にコールバックを追加することはできないため、タイマーが使用されます。サイドバーがロードされたかどうかは、返されるコンテンツを通じてのみ判断できます。

4. 概要

この週末は、スティッキー コンポーネントを改善する方法を考えて、一日のほとんどをこの記事の執筆に費やしました。少なくとも、最後に書き終えたスティッキー コンポーネントの機能と実装には少し満足しています。何かが欠けているように奇妙に感じましたが、それはまだ多くのものが欠けているためであることがわかりました。現時点では、このコンポーネントは固定と固定解除の効果しか実現できません。固定された状態でナビゲーションのスクロールやタブのナビゲーションをサポートするインターネット上の一般的な機能も、このレベルの効果では十分ではない可能性があります。次へ この記事では、この記事を元に Sticky コンポーネント、navScrollSticky コンポーネントと tabSticky コンポーネントの実装方法を紹介しますので、ご期待ください。

読んでいただきありがとうございます:)

補足説明: IE および Firefox では、ページを更新するときに、更新前にページがスクロールしている場合、更新操作によってページのスクロール位置が更新位置に設定されますが、スクロール イベントはトリガーされないため、スクロール イベントの直後に呼び出す必要があります。コンポーネントは初期化されます:

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

フロントエンドのサーマルペーパーレシートのために文字化けしたコード印刷に遭遇した場合はどうすればよいですか? フロントエンドのサーマルペーパーレシートのために文字化けしたコード印刷に遭遇した場合はどうすればよいですか? Apr 04, 2025 pm 02:42 PM

フロントエンドのサーマルペーパーチケット印刷のためのよくある質問とソリューションフロントエンド開発におけるチケット印刷は、一般的な要件です。しかし、多くの開発者が実装しています...

誰がより多くのPythonまたはJavaScriptを支払われますか? 誰がより多くのPythonまたはJavaScriptを支払われますか? Apr 04, 2025 am 12:09 AM

スキルや業界のニーズに応じて、PythonおよびJavaScript開発者には絶対的な給与はありません。 1. Pythonは、データサイエンスと機械学習でさらに支払われる場合があります。 2。JavaScriptは、フロントエンドとフルスタックの開発に大きな需要があり、その給与もかなりです。 3。影響要因には、経験、地理的位置、会社の規模、特定のスキルが含まれます。

javascriptの分解:それが何をするのか、なぜそれが重要なのか javascriptの分解:それが何をするのか、なぜそれが重要なのか Apr 09, 2025 am 12:07 AM

JavaScriptは現代のWeb開発の基礎であり、その主な機能には、イベント駆動型のプログラミング、動的コンテンツ生成、非同期プログラミングが含まれます。 1)イベント駆動型プログラミングにより、Webページはユーザー操作に応じて動的に変更できます。 2)動的コンテンツ生成により、条件に応じてページコンテンツを調整できます。 3)非同期プログラミングにより、ユーザーインターフェイスがブロックされないようにします。 JavaScriptは、Webインタラクション、シングルページアプリケーション、サーバー側の開発で広く使用されており、ユーザーエクスペリエンスとクロスプラットフォーム開発の柔軟性を大幅に改善しています。

JavaScriptを使用して、同じIDを持つArray要素を1つのオブジェクトにマージする方法は? JavaScriptを使用して、同じIDを持つArray要素を1つのオブジェクトにマージする方法は? Apr 04, 2025 pm 05:09 PM

同じIDを持つ配列要素をJavaScriptの1つのオブジェクトにマージする方法は?データを処理するとき、私たちはしばしば同じIDを持つ必要性に遭遇します...

Console.log出力の違い結果:なぜ2つの呼び出しが異なるのですか? Console.log出力の違い結果:なぜ2つの呼び出しが異なるのですか? Apr 04, 2025 pm 05:12 PM

Console.log出力の違いの根本原因に関する詳細な議論。この記事では、Console.log関数の出力結果の違いをコードの一部で分析し、その背後にある理由を説明します。 �...

Shiseidoの公式Webサイトのように、視差スクロールと要素のアニメーション効果を実現する方法は?
または:
Shiseidoの公式Webサイトのようにスクロールするページを伴うアニメーション効果をどのように実現できますか? Shiseidoの公式Webサイトのように、視差スクロールと要素のアニメーション効果を実現する方法は? または: Shiseidoの公式Webサイトのようにスクロールするページを伴うアニメーション効果をどのように実現できますか? Apr 04, 2025 pm 05:36 PM

この記事の視差スクロールと要素のアニメーション効果の実現に関する議論では、Shiseidoの公式ウェブサイト(https://www.shisido.co.co.jp/sb/wonderland/)と同様の達成方法について説明します。

JavaScriptは学ぶのが難しいですか? JavaScriptは学ぶのが難しいですか? Apr 03, 2025 am 12:20 AM

JavaScriptを学ぶことは難しくありませんが、挑戦的です。 1)変数、データ型、関数などの基本概念を理解します。2)非同期プログラミングをマスターし、イベントループを通じて実装します。 3)DOM操作を使用し、非同期リクエストを処理することを約束します。 4)一般的な間違いを避け、デバッグテクニックを使用します。 5)パフォーマンスを最適化し、ベストプラクティスに従ってください。

フロントエンド開発でVSCodeと同様に、パネルドラッグアンドドロップ調整機能を実装する方法は? フロントエンド開発でVSCodeと同様に、パネルドラッグアンドドロップ調整機能を実装する方法は? Apr 04, 2025 pm 02:06 PM

フロントエンドのVSCodeと同様に、パネルドラッグアンドドロップ調整機能の実装を調べます。フロントエンド開発では、VSCODEと同様のVSCODEを実装する方法...

See all articles