Maison > interface Web > js tutoriel > Barres de défilement virtuelles sur 2.x dans vue.js

Barres de défilement virtuelles sur 2.x dans vue.js

亚连
Libérer: 2018-06-09 17:25:55
original
1550 Les gens l'ont consulté

Cet article présente principalement l'exemple de code de barre de défilement virtuelle basé sur vue.js 2.x. Maintenant, je le partage avec vous et le donne comme référence.

Avant-propos

Je me souviens avoir parcouru par hasard un projet cms open source et avoir découvert que le menu de gauche de ce projet dépassait la largeur des fenêtres. J'étais curieux de savoir pourquoi. il n'y a pas de barre de défilement ? Ensuite, j'ai regardé de plus près et j'ai trouvé un petit p sur le côté gauche. Ensuite, j'ai essayé de le faire glisser et j'ai découvert que c'était la même que la barre de défilement native ! En regardant son code source, j'ai découvert que cette barre de défilement s'appelle slimScroll. Ensuite, je suis allé sur son référentiel github et je l'ai regardé. Après avoir étudié le code source, j'ai senti que je pouvais aussi faire la même barre de défilement ! Réalisé grâce à vue !

Conception

D'accord, nous commençons maintenant les étapes de conception de la barre de défilement :

Concevoir la barre de défilement dom

La première chose à penser est la suivante : si vous souhaitez faire défiler le contenu que vous devez faire défiler, la première chose est que son domaine parent doit avoir une longueur et une largeur fixes, c'est-à-dire que la partie excédentaire doit être masquée, c'est-à-dire, ajoutez un style : overflow : caché, Par conséquent, nous ajoutons un wrapper au contenu à faire défiler afin que sa longueur et sa largeur soient égales au dom parent, puis il y a un style appelé : overflow : caché, et le L'élément enveloppé s'appelle scrollPanel

Deuxièmement : nous le savons, nous voulons le rendre aussi puissant que la barre de défilement native ! Il est nécessaire de concevoir des barres de défilement horizontales et des barres de défilement verticales. La barre de défilement et scrollPanel appartiennent à la relation entre les nœuds frères, car l'existence de la barre de défilement ne peut pas provoquer d'erreur de mise en page de style d'origine et prend en charge le haut et la gauche pour contrôler sa position. , donc la barre de défilement La position doit être absolue. Eh bien, nous appelons la barre de défilement horizontale : hBar, et la barre de défilement verticale : vBar

Enfin : nous avons conçu scrollPanel, vBar, hBar, et nous avons besoin d'un parent. p pour les envelopper, puis ajoutez un style : position : relative

Pratique

Structure des composants de conception

Premier de au total, nos plug-ins sont constitués de 4 composants, dont 3 sont des composants enfants et 1 est un composant parent, à savoir : vueScroll (composant parent), scrollPanel (sous-composant qui encapsule le contenu qui doit défiler), vBar (barre de défilement verticale) , hBar (barre de défilement horizontale)

Deuxièmement, concevons les fonctions dont chaque composant est responsable. Les composants ici sont divisés en composants de couche de contrôle et composants d'affichage (les étudiants familiers avec React devraient le savoir). Les composants de couche d'affichage ne complètent que la fonction d'affichage : vBar, hBar, scrollPanel. Les composants de couche de contrôle sont quelque peu similaires au CPU et peuvent contrôler. sous-composants. Différents états, tels que la largeur, la hauteur, la couleur, la transparence, la position, etc. Le composant de la couche de contrôle est : vueScroll.

Mise en œuvre spécifique

hBar/vBar

hBar/vBar Ces deux barres sont respectivement une barre de défilement horizontale et une barre de défilement verticale, les fonctions implémentées sont à peu près les mêmes, donc les anciennes sont mentionnées ensemble ici, nous prenons vBar comme exemple.

props reçoit les propriétés transmises par le composant parent, à savoir :

{
  height: vm.state.height + 'px', //滚动条的高度
  width: vm.ops.width, // 滚动条的宽度
  position: 'absolute', 
  background: vm.ops.background, // 滚动条背景色
  top: vm.state.top + 'px', // 滚动条的高度
  transition: 'opacity .5s', // 消失/显示 所用的时间
  cursor: 'pointer', //
  opacity: vm.state.opacity, // 透明度
  userSelect: 'none' 
 }
Copier après la connexion

2 événements, principalement pour afficher la barre de défilement lorsque la souris bouge.

...
render(_c){
  return _c(
    // ...
    {
      mouseenter: function(e) {
        vm.$emit('showVBar'); // 触发父组件事件,显示滚动条
      }
    }
    // ...
  )
}
Copier après la connexion

Parmi eux, state représente l'état, qui peut être modifié au moment de l'exécution, et ops est le paramètre de configuration, qui est transmis par l'utilisateur.

scrollPanel

est un composant qui encapsule le contenu défilant. Le style doit être défini sur : overflow : masqué.

1. Style

var style = vm.scrollContentStyle;
 style.overflow = 'hidden';
 // ...
 {
   style: style
 }
 // ...
Copier après la connexion

2. Composant de contrôle d'événement

// ...
  render(_c) {
    // ...
      on: {
        mouseenter: function() {
          vm.$emit('showBar');
        },
        mouseleave: function() {
          vm.$emit('hideBar');
        }
      }
    // ...
  }
 // ...
Copier après la connexion

vuescroll

. Contrôlez l'état affiché par les sous-composants, ajoutez divers événements d'écoute, etc.

1. Obtenez l'élément dom du sous-composant pour obtenir des informations en temps réel sur le dom.

// ...
   initEl() {
    this.scrollPanel.el = this.$refs['vueScrollPanel'] && this.$refs['vueScrollPanel'].$el;
    this.vScrollBar.el = this.$refs['vScrollBar'] && this.$refs['vScrollBar'].$el;
    this.hScrollBar.el = this.$refs['hScrollBar'] && this.$refs['hScrollBar'].$el;
  }
  // ...
Copier après la connexion

2. Afficher les barres de défilement

Afficher les barres de défilement, y compris l'affichage des barres de défilement horizontales et l'affichage des barres de défilement verticales :

<🎜. >
// ...
    var temp;
    var deltaY = {
      deltaY: this.vScrollBar.ops.deltaY // 获取用户配置的deltaY
    };
    if(!this.isMouseLeavePanel || this.vScrollBar.ops.keepShow){
      if ((this.vScrollBar.state.height = temp = this.getVBarHeight(deltaY))) { // 判断条件
        // 重新设置滚动条的状态
        this.vScrollBar.state.top = this.resizeVBarTop(temp);
        this.vScrollBar.state.height = temp.height;
        this.vScrollBar.state.opacity = this.vScrollBar.ops.opacity;
      }
    }
  // ...
Copier après la connexion
3. Obtenez la hauteur de la barre de défilement

La hauteur de l'élément dom n'étant pas fixe, vous devez obtenir la hauteur réelle du dom en temps réel. de la barre de défilement est la suivante :

var height = Math.max(
      scrollPanelHeight / 
      (scrollPanelScrollHeight / scrollPanelHeight), 
      this.vScrollBar.minBarHeight
      );
Copier après la connexion
C'est-à-dire : la hauteur de la barre de défilement : la hauteur du scrollPanel == la hauteur du scrollPanel : la hauteur de l'élément dom

4. resizeVBarTop, afin d'éviter les erreurs, et la hauteur de la barre de défilement à partir de l'élément parent peut être trouvée.

resizeVBarTop({height, scrollPanelHeight, scrollPanelScrollHeight, deltaY}) {
  // cacl the last height first
  var lastHeight = scrollPanelScrollHeight - scrollPanelHeight - this.scrollPanel.el.scrollTop;
  if(lastHeight < this.accuracy) {
    lastHeight = 0;
  }
  var time = Math.abs(Math.ceil(lastHeight / deltaY));
  var top = scrollPanelHeight - (height + (time * this.vScrollBar.innerDeltaY));
  return top;
}
Copier après la connexion
5. Surveiller les événements de défilement de la roue.

// ...
  on: {
    wheel: vm.wheel
  }
  // ...
   wheel(e) {
    var vm = this;
    vm.showVBar();
    vm.scrollVBar(e.deltaY > 0 ? 1 : -1, 1);
    e.stopPropagation();
  }
  // ...
Copier après la connexion
6. Surveillez les événements de glissement de la barre de défilement

listenVBarDrag: function() {
    var vm = this;
    var y;
    var _y;
    function move(e) {
      _y = e.pageY;
      var _delta = _y - y;
      vm.scrollVBar(_delta > 0 ? 1 : -1, Math.abs(_delta / vm.vScrollBar.innerDeltaY));
      y = _y;
    }
    function t(e) {
      var deltaY = {
        deltaY: vm.vScrollBar.ops.deltaY
      };
      if(!vm.getVBarHeight(deltaY)) {
        return;
      }
      vm.mousedown = true;
      y = e.pageY; // 记录初始的Y的位置
      vm.showVBar();
      document.addEventListener(&#39;mousemove&#39;, move);
      document.addEventListener(&#39;mouseup&#39;, function(e) {
        vm.mousedown = false;
        vm.hideVBar();
        document.removeEventListener(&#39;mousemove&#39;, move);
      });
    }
    this.listeners.push({
      dom: vm.vScrollBar.el,
      event: t,
      type: "mousedown"
    });
    vm.vScrollBar.el.addEventListener(&#39;mousedown&#39;, t); // 把事件放到数组里面,等销毁之前移除掉注册的时间。
  }
Copier après la connexion
7. Adaptez-vous aux terminaux mobiles et écoutez les événements tactiles. Le principe est similaire à celui des événements de traînée, sauf qu'il existe un jugement supplémentaire pour déterminer si la direction actuelle est x ou y.

listenPanelTouch: function() {
    var vm = this;
    var pannel = this.scrollPanel.el;
    var x, y;
    var _x, _y;
    function move(e) {
      if(e.touches.length) {
        var touch = e.touches[0];
        _x = touch.pageX;
        _y = touch.pageY;
        var _delta = void 0;
        var _deltaX = _x - x;
        var _deltaY = _y - y;
        if(Math.abs(_deltaX) > Math.abs(_deltaY)) {
          _delta = _deltaX;
          vm.scrollHBar(_delta > 0 ? -1 : 1, Math.abs(_delta / vm.hScrollBar.innerDeltaX));
        } else if(Math.abs(_deltaX) < Math.abs(_deltaY)){
          _delta = _deltaY;
          vm.scrollVBar(_delta > 0 ? -1 : 1, Math.abs(_delta / vm.vScrollBar.innerDeltaY));
        }
        x = _x;
        y = _y;
      }
    }
    function t(e) {
      var deltaY = {
        deltaY: vm.vScrollBar.ops.deltaY
      };
      var deltaX = {
        deltaX: vm.hScrollBar.ops.deltaX
      };
      if(!vm.getHBarWidth(deltaX) && !vm.getVBarHeight(deltaY)) {
        return;
      }
      if(e.touches.length) {
        e.stopPropagation();
        var touch = e.touches[0];
        vm.mousedown = true;
        x = touch.pageX;
        y = touch.pageY;
        vm.showBar();
        pannel.addEventListener(&#39;touchmove&#39;, move);
        pannel.addEventListener(&#39;touchend&#39;, function(e) {
          vm.mousedown = false;
          vm.hideBar();
          pannel.removeEventListener(&#39;touchmove&#39;, move);
        });
      }
    }
    pannel.addEventListener(&#39;touchstart&#39;, t);
    this.listeners.push({
      dom: pannel,
      event: t,
      type: "touchstart"
    });
  }
Copier après la connexion
8. Faire défiler le contenu

Le principe du défilement du contenu n'est rien de plus que de changer le scrollTop/scrollLeft du scrollPanel pour contrôler le contenu pour se déplacer vers le haut, le bas, la gauche et la droite .

scrollVBar: function(pos, time) {
    // >0 scroll to down <0 scroll to up
     
    var top = this.vScrollBar.state.top; 
    var scrollPanelHeight = getComputed(this.scrollPanel.el, &#39;height&#39;).replace(&#39;px&#39;, "");
    var scrollPanelScrollHeight = this.scrollPanel.el.scrollHeight;
    var scrollPanelScrollTop = this.scrollPanel.el.scrollTop;
    var height = this.vScrollBar.state.height;
    var innerdeltaY = this.vScrollBar.innerDeltaY;
    var deltaY = this.vScrollBar.ops.deltaY;
    if (!((pos < 0 && top <= 0) || (scrollPanelHeight <= top + height && pos > 0) || (Math.abs(scrollPanelScrollHeight - scrollPanelHeight) < this.accuracy))) {
      var Top = top + pos * innerdeltaY * time;
      var ScrollTop = scrollPanelScrollTop + pos * deltaY * time;
      if (pos < 0) {
        // scroll ip
        this.vScrollBar.state.top = Math.max(0, Top);
        this.scrollPanel.el.scrollTop = Math.max(0, ScrollTop);
      } else if (pos > 0) {
        // scroll down
        this.vScrollBar.state.top = Math.min(scrollPanelHeight - height, Top);
        this.scrollPanel.el.scrollTop = Math.min(scrollPanelScrollHeight - scrollPanelHeight, ScrollTop);
      }
    }
    // 这些是传递给父组件的监听滚动的函数的。
    var content = {};
    var bar = {};
    var process = "";
    content.residual = (scrollPanelScrollHeight - scrollPanelScrollTop - scrollPanelHeight);
    content.scrolled = scrollPanelScrollTop;
    bar.scrolled = this.vScrollBar.state.top;
    bar.residual = (scrollPanelHeight - this.vScrollBar.state.top - this.vScrollBar.state.height);
    bar.height = this.vScrollBar.state.height;
    process = bar.scrolled/(scrollPanelHeight - bar.height);
    bar.name = "vBar";
    content.name = "content";
    this.$emit(&#39;vscroll&#39;, bar, content, process);
  },
Copier après la connexion
9. Détruisez les événements enregistrés.

Nous venons tout juste de mettre les événements enregistrés dans le tableau des auditeurs, et nous pouvons les détruire dans le hook beforedestroy.

// remove the registryed event.
  this.listeners.forEach(function(item) {
    item.dom.removeEventListener(item.event, item.type);
  });
Copier après la connexion
Capture d'écran de l'opération

La capture d'écran de l'opération côté PC est la suivante :

Après avoir enregistré l'événement d'écoute, il est comme indiqué ci-dessous :

Exécutez la capture d'écran sur votre téléphone :

On peut voir que l'effet de performance est cohérent avec la barre de défilement native.

Conclusion et réflexion

Ce qui précède est essentiellement le design de la barre de défilement que j'ai conçue. Tout d'abord, je suis très reconnaissant aux Nuggets de m'avoir offert un tel. plateforme de partage, et ensuite je voudrais remercier slimScroll L'auteur m'a donné une telle idée. Après avoir terminé ce plug-in, j'en sais plus sur les éléments scrollWidth, scrollHeigh, scrollTop et scrollLeft du DOM

Ce qui précède est ce que j'ai compilé pour tout le monde. J'espère que cela sera utile à tout le monde à l'avenir.

Articles associés :

3 modes de base des paramètres de routage de vue (tutoriel détaillé)

Astuces associées en JavaScript

Implémenter l'importation dynamique de fichiers dans webpack

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal