Maison interface Web js tutoriel Une brève discussion sur la mise en œuvre améliorée des compétences Sticky composants_javascript

Une brève discussion sur la mise en œuvre améliorée des compétences Sticky composants_javascript

May 16, 2016 pm 03:10 PM

Dans l'article précédentUtilisation de la méthode getBoundingClientRect pour implémenter un composant collant simple a présenté une implémentation simple du composant collant Après y avoir réfléchi au cours des deux derniers jours, j'ai découvert qu'il y avait plus d'implémentations fournies. La dernière fois, les inconvénients sont que les effets obtenus sur d'autres sites Web sont également quelque peu différents lors de la suppression. La méthode de suppression fournie la dernière fois n'était pas bonne. Sur la base de ce qui précède, cet article propose une version améliorée du composant collant. complet, j'espère que vous êtes intéressé à le lire.

1. Problèmes avec les anciennes versions

Il y a plusieurs problèmes dans la mise en œuvre du composant collant précédent :

Premièrement, en termes d'effet de sticky, avant et après la fixation de l'élément sticky, ce qui ne changera pas, c'est la position par rapport au côté gauche du navigateur et la largeur totale de l'élément sticky. Ce qui peut changer, c'est. la position par rapport au haut ou au bas du navigateur et la hauteur de l'élément collant. Dans l'implémentation fournie ci-dessus, ces deux dernières valeurs changeantes sont considérées comme des valeurs constantes. Pourquoi la valeur supérieure ou la valeur inférieure est-elle toujours 0 lorsqu'elle est fixe ? Bien sûr, il peut être différent de 0, comme top : 20px, bottom : 15px. Dans certaines scènes, l'ajout de tels décalages rendra l'effet collant meilleur, comme l'exemple de composant affixe utilisé dans la documentation officielle de bootstrap (ce composant La fonction est similaire au composant collant implémenté dans cet article) :

Il définit la position par rapport au haut du navigateur en haut : 20 px lorsqu'il est corrigé. Il en va de même pour la hauteur des éléments collants Afin d'afficher un meilleur effet une fois fixés, il est également très courant d'ajuster la hauteur de ligne d'origine ou le rembourrage supérieur et d'autres attributs liés à la hauteur. cette page de Tmall Huabei, ce contenu de bloc utilise le composant collant :

Avant fixe, la hauteur de l'élément collant est :

Une fois fixée, la hauteur de l'élément collant est :

Deuxièmement, lors de l'annulation de la fixation, en prenant comme exemple l'élément collant fixé en haut, la mise en œuvre proposée ci-dessus consiste à annuler directement la position de l'élément collant lorsque la distance entre l'élément cible et le haut du navigateur est less than stickyHeight : attribut fixe, l'élément collant est immédiatement restauré au flux de document normal et l'effet est :

Il disparaît immédiatement lorsqu'il atteint le point critique, mais l'effet de Tmall Huabei n'est pas comme ça :

Il ne disparaît pas immédiatement lorsqu'il atteint le point critique, mais réajuste la valeur supérieure de l'élément collant afin qu'il puisse défiler vers le haut avec le contenu principal de la page Web en conjonction avec la barre de défilement :

D'un point de vue expérience, il est évident que l'effet de Tmall Huabei est meilleur. D'un point de vue fonctionnel, l'implémentation proposée ci-dessus présente un défaut fatal : lorsque la hauteur de l'élément collant est très grande, il dépasse les capacités du navigateur. Lors de l'affichage de la hauteur de la zone, il y aura un bug qui, peu importe la façon dont vous faites défiler, vous ne pouvez pas parcourir tout le contenu des éléments collants. Si vous êtes intéressé, vous pouvez essayer le code implémenté la dernière fois sur. la barre latérale de votre blog. J'ai essayé et trouvé ce problème, j'ai donc voulu améliorer le composant collant : (
Troisièmement, la dernière implémentation présente encore plusieurs lacunes :

1) documentElement.clientHeight n'est pas mis en cache, ce qui entraîne sa réacquisition à chaque fois que le point critique est jugé :

2) La valeur par défaut de l'intervalle de rappel de défilement est trop grande et doit être définie plus petite cette fois, elle est de 5 et le bootstrap utilise 1. Ce n'est qu'ainsi que l'effet peut être garanti
;

3) Dans certains scénarios, la largeur de l'élément collant peut ne pas avoir besoin d'être réinitialisée lorsqu'un redimensionnement est requis. Une option doit être ajoutée pour le contrôler
.

4) Lorsque l'élément collant est fixe et non fixé, une fonction de rappel doit être fournie afin que d'autres composants puissent faire des choses à des points clés lorsqu'ils dépendent de ce composant.

2. Comment s'améliorer

Les options des composants ont été redéfinies :

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元素取消固定时的回调
};
Copier après la connexion

Ceux en gras sont nouveaux ou modifiés. La hauteur d'origine a été supprimée et remplacée par unStickyDistance. Lors de la correction, la position par rapport au haut ou au bas du navigateur est spécifiée avec stickyOffset, de sorte qu'il n'est pas nécessaire d'écrire la valeur de l'attribut haut ou bas dans le CSS de .sticky--in-top ou .sticky--in -bas. Si isFixedWidth est faux, un rappel pour actualiser la largeur de l'élément collant lors du redimensionnement sera ajouté :


!opts.isFixedWidth && $win.resize(throttle(function () {
setStickyWidth();
$elem.hasClass(className) && $elem.css('width', stickyWidth);
sticky();
}, opts.wait));
Copier après la connexion

Par rapport à la dernière fois, le problème dans cette implémentation est le traitement logique lors de l'annulation de la fixation. La dernière fois, l'élément collant n'avait que deux états, collant ou non collant. Cette fois, l'état collant est divisé en. staticSticky et DynamicSticky. Le premier représente l'état collant dans lequel la valeur supérieure ou inférieure reste inchangée. Le second représente l'état collant dans lequel la valeur supérieure ou inférieure change. à annuler. Afin de résoudre ce problème plus clairement, le jugement initial est Les points critiques et le code qui effectue différents traitements à différents points critiques sont restructurés comme suit :

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);
}
Copier après la connexion

Il y a un peu l'idée du modèle étatique dedans, mais c'est plus concis. Quand j'ai écrit ce code, je voulais vraiment utiliser la machine à états que j'avais connue auparavant. Je pensais qu'il était tout à fait possible de l'écrire à l'aide d'une machine à états, mais je voulais juste éviter qu'une bibliothèque de classes ne soit référencée. attendez un jour. Réessayez lorsque vous souhaitez pratiquer les machines à états.

La mise en œuvre globale est la suivante :

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);
Copier après la connexion

Ce qui est difficile à comprendre est peut-être la logique de la méthode getState. Certaines des idées de cette partie sont expliquées plus en détail dans le blog précédent.

3. Instructions d'application dans la barre latérale du blog

Tout d'abord, vous devez coller cette implémentation dans le champ de texte HTML du pied de page des paramètres du blog, puis ajouter le code suivant pour initialiser :

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);
Copier après la connexion

Timer est utilisé car le contenu de la barre latérale est chargé par ajax, et il est impossible d'ajouter des rappels lors de ces requêtes ajax. Vous ne pouvez juger si la barre latérale est chargée que par le contenu qu'elles renvoient.

4.Résumé

Ce week-end, j'ai réfléchi à la façon d'améliorer le composant collant. De plus, j'ai passé la majeure partie de la journée à écrire cet article. Au moins maintenant, je me sens un peu satisfait de la fonction et de la mise en œuvre du composant collant que j'ai fini d'écrire en dernier. C'était bizarre, comme s'il manquait quelque chose, mais il s'est avéré que c'était parce qu'il manquait encore tellement de choses. À l'heure actuelle, ce composant ne peut avoir pour effet que de réparer et de défaire. Pour les travaux pratiques, l'effet de ce niveau peut ne pas être suffisant. Les fonctions courantes sur Internet qui prennent en charge le défilement de la navigation ou la navigation par onglets tout en étant corrigées sont également très courantes. Suivant Cet article présentera le composant sticky basé sur cet article, comment implémenter les composants navScrollSticky et tabSticky, alors restez à l'écoute.
Merci d'avoir lu :)

Explication supplémentaire :
Dans IE et Firefox, lors de l'actualisation de la page, si la page défile avant l'actualisation, l'opération d'actualisation définira la position de défilement de la page sur la position d'actualisation, mais l'événement de défilement ne sera pas déclenché, il doit donc être appelé immédiatement après le composant est initialisé. Une fonction collante :

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Que dois-je faire si je rencontre l'impression de code brouillé pour les reçus en papier thermique frontal? Que dois-je faire si je rencontre l'impression de code brouillé pour les reçus en papier thermique frontal? Apr 04, 2025 pm 02:42 PM

Des questions et des solutions fréquemment posées pour l'impression de billets thermiques frontaux pour le développement frontal, l'impression de billets est une exigence commune. Cependant, de nombreux développeurs mettent en œuvre ...

Qui est payé plus de python ou de javascript? Qui est payé plus de python ou de javascript? Apr 04, 2025 am 12:09 AM

Il n'y a pas de salaire absolu pour les développeurs Python et JavaScript, selon les compétences et les besoins de l'industrie. 1. Python peut être davantage payé en science des données et en apprentissage automatique. 2. JavaScript a une grande demande dans le développement frontal et complet, et son salaire est également considérable. 3. Les facteurs d'influence comprennent l'expérience, la localisation géographique, la taille de l'entreprise et les compétences spécifiques.

Démystifier javascript: ce qu'il fait et pourquoi c'est important Démystifier javascript: ce qu'il fait et pourquoi c'est important Apr 09, 2025 am 12:07 AM

JavaScript est la pierre angulaire du développement Web moderne, et ses principales fonctions incluent la programmation axée sur les événements, la génération de contenu dynamique et la programmation asynchrone. 1) La programmation axée sur les événements permet aux pages Web de changer dynamiquement en fonction des opérations utilisateur. 2) La génération de contenu dynamique permet d'ajuster le contenu de la page en fonction des conditions. 3) La programmation asynchrone garantit que l'interface utilisateur n'est pas bloquée. JavaScript est largement utilisé dans l'interaction Web, les applications à une page et le développement côté serveur, améliorant considérablement la flexibilité de l'expérience utilisateur et du développement multiplateforme.

Comment fusionner les éléments du tableau avec le même ID dans un seul objet en utilisant JavaScript? Comment fusionner les éléments du tableau avec le même ID dans un seul objet en utilisant JavaScript? Apr 04, 2025 pm 05:09 PM

Comment fusionner les éléments du tableau avec le même ID dans un seul objet en JavaScript? Lors du traitement des données, nous rencontrons souvent la nécessité d'avoir le même ID ...

La différence dans Console.Log de sortie Résultat: Pourquoi les deux appels sont-ils différents? La différence dans Console.Log de sortie Résultat: Pourquoi les deux appels sont-ils différents? Apr 04, 2025 pm 05:12 PM

Discussion approfondie des causes profondes de la différence de sortie Console.log. Cet article analysera les différences dans les résultats de sortie de la fonction Console.log dans un morceau de code et expliquera les raisons derrière. � ...

Comment réaliser des effets de défilement de parallaxe et d'animation des éléments, comme le site officiel de Shiseido?
ou:
Comment pouvons-nous réaliser l'effet d'animation accompagné d'un défilement de page comme le site officiel de Shiseido? Comment réaliser des effets de défilement de parallaxe et d'animation des éléments, comme le site officiel de Shiseido? ou: Comment pouvons-nous réaliser l'effet d'animation accompagné d'un défilement de page comme le site officiel de Shiseido? Apr 04, 2025 pm 05:36 PM

La discussion sur la réalisation des effets de défilement de parallaxe et d'animation des éléments dans cet article explorera comment réaliser le site officiel de Shiseido (https://www.shiseido.co.jp/sb/wonderland/) ...

JavaScript est-il difficile à apprendre? JavaScript est-il difficile à apprendre? Apr 03, 2025 am 12:20 AM

Apprendre JavaScript n'est pas difficile, mais c'est difficile. 1) Comprendre les concepts de base tels que les variables, les types de données, les fonctions, etc. 2) Master la programmation asynchrone et les implémenter via des boucles d'événements. 3) Utilisez les opérations DOM et promettez de gérer les demandes asynchrones. 4) Évitez les erreurs courantes et utilisez des techniques de débogage. 5) Optimiser les performances et suivre les meilleures pratiques.

Comment implémenter la fonction de glisser-déposer et de régler la fonction de réglage similaire à VScode dans le développement frontal? Comment implémenter la fonction de glisser-déposer et de régler la fonction de réglage similaire à VScode dans le développement frontal? Apr 04, 2025 pm 02:06 PM

Explorez la mise en œuvre de la fonction de glisser et de réglage du panneau de type VScode dans le frontal. Dans le développement frontal, comment implémenter un VScode comme ...

See all articles