ホームページ ウェブフロントエンド jsチュートリアル vue.js の仮想スクロール バー約 2.x

vue.js の仮想スクロール バー約 2.x

Jun 09, 2018 pm 05:25 PM
vue.js スクロール・バー

この記事では主に vue.js 2.x に基づく仮想スクロール バーのサンプル コードを紹介します。

前書き

以前、偶然オープンソースの cms プロジェクトを閲覧していて、プロジェクトの左側のメニューがウィンドウの幅を超えていることに気づきました。なぜスクロール バーがないのか疑問に思いました。そこでよく見てみると、その左側に小さな p があったので、それをドラッグしてみると、ネイティブのスクロール バーと同じであることがわかりました。ソースコードを見ると、このスクロールバーはslimScrollという名前であることがわかり、githubリポジトリにアクセスしてソースコードを調べたところ、同じスクロールバーを作成することができると感じました。 vueで実現!

デザイン

それでは、スクロール バーのデザイン手順を始めましょう:

スクロール バーの dom をデザインします

最初に考えるべきことは次のとおりです: コンテンツを作成したい場合は、スクロールする必要があります。スクロール、最初のことはそれです。親 dom は固定の長さと幅を持つ必要があります。つまり、余分な部分は非表示にする必要があります。つまり、スタイルが追加されます。したがって、コンテンツにラッパーを追加します。長さと幅が親 dom と等しくなるようにスクロールされると、スタイルが 1 つ呼び出されます: overflow: hidden、ラップされた要素はscrollPanel と呼ばれます

2 番目: と同じくらい強力である必要があることがわかっています。ネイティブスクロールバー!スクロール バーと垂直スクロール バーは、兄弟ノード間の関係に属しているため、スクロール バーの存在により元のスタイルのレイアウトが崩れることはなく、その位置を制御するために上と左をサポートするように設計する必要があります。なので、スクロール バーの位置は絶対値でなければなりません。水平スクロール バーを hBar、垂直スクロール バーを vBar と呼びましょう

最後に、scrollPanel、vBar、hBar を設計しました。これらをラップするには親 p が必要です。そして Style:position:relative を追加します

練習

デザインコンポーネント構造

まず第一に、私たちのプラグインには合計 4 つのコンポーネントがあり、そのうち 3 つは子コンポーネント、1 つは親コンポーネントです。すなわち: vueScroll (親コンポーネント)、scrollPanel (スクロールする必要があるコンテンツをラップするサブコンポーネント)、vBar (垂直スクロール バー)、hBar (水平スクロール バー)

次に、各コンポーネントが担当する関数を設計しましょう。ここでのコンポーネントは、コントロール層コンポーネントとディスプレイ コンポーネントに分かれています (反応に慣れている学生はこれを知っているはずです)。ディスプレイ層コンポーネントは、vBar、hBar、scrollPanel などの表示機能を完了するだけです。コントロール層コンポーネントは CPU に似ており、制御できます。幅、高さ、色、透明度、位置などのさまざまな状態のサブコンポーネント。コントロール層コンポーネントは vueScroll です。

具体的な実装

hBar/vBar

hBar/vBar これら 2 つはそれぞれ水平スクロール バーと垂直スクロール バーであり、実装する機能はほぼ同じであるため、ここでは vBar としてまとめて説明します。例。

props は、親コンポーネントによって渡されたプロパティ、具体的には、マウスの移動時に主にスクロール バーを表示する

{
  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' 
 }
ログイン後にコピー

2 イベントを受け取ります。

...
render(_c){
  return _c(
    // ...
    {
      mouseenter: function(e) {
        vm.$emit('showVBar'); // 触发父组件事件,显示滚动条
      }
    }
    // ...
  )
}
ログイン後にコピー

このうち、state は実行時に変更できる状態を表し、ops はユーザーによって渡される構成パラメーターです。

scrollPanel

は、スクロールコンテンツをラップするコンポーネントです: overflow: hidden に設定する必要があります。

1. スタイル

var style = vm.scrollContentStyle;
 style.overflow = 'hidden';
 // ...
 {
   style: style
 }
 // ...
ログイン後にコピー

2. イベント

// ...
  render(_c) {
    // ...
      on: {
        mouseenter: function() {
          vm.$emit('showBar');
        },
        mouseleave: function() {
          vm.$emit('hideBar');
        }
      }
    // ...
  }
 // ...
ログイン後にコピー

vescroll

コントロールコンポーネント。サブコンポーネントによって表示されるステータスを制御したり、さまざまなリスニング イベントを追加したりできます。

1. サブコンポーネントの dom 要素を取得して、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;
  }
  // ...
ログイン後にコピー

2. スクロール バーを表示します。水平スクロール バーの表示と垂直スクロール バーの表示を含みます。

// ...
    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;
      }
    }
  // ...
ログイン後にコピー

3.スクロールバー

dom要素のため高さは固定されていないため、リアルタイムでdomの実際の高さを取得する必要があります。 スクロールバーの高さの計算式は次のとおりです:

var height = Math.max(
      scrollPanelHeight / 
      (scrollPanelScrollHeight / scrollPanelHeight), 
      this.vScrollBar.minBarHeight
      );
ログイン後にコピー

つまり:スクロール バーの高さ: スクロール パネルの高さ == スクロール パネルの高さ: dom 要素の高さ

4. エラーを防ぐために、親からスクロール バーの高さを見つけることができるように、resizeVBarTop を実行します。要素。

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;
}
ログイン後にコピー

5. ホイール スクロール イベントを監視します。

// ...
  on: {
    wheel: vm.wheel
  }
  // ...
   wheel(e) {
    var vm = this;
    vm.showVBar();
    vm.scrollVBar(e.deltaY > 0 ? 1 : -1, 1);
    e.stopPropagation();
  }
  // ...
ログイン後にコピー

6. スクロール バーのドラッグ イベントを監視します

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); // 把事件放到数组里面,等销毁之前移除掉注册的时间。
  }
ログイン後にコピー

7. モバイル端末に適応し、タッチ イベントをリッスンします。原理はドラッグ イベントの原理と似ていますが、現在の方向が x であるか 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"
    });
  }
ログイン後にコピー

8. コンテンツをスクロールする

コンテンツをスクロールする原理は、scrollPanel のscrollTop/scrollLeftを変更して、コンテンツが上下左右に移動するように制御することに他なりません。

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);
  },
ログイン後にコピー

9. 登録されたイベントを破棄します。

今、登録されたイベントをリスナー配列に入れました。そして、それらを beforedestroy フックで破棄できます。

// remove the registryed event.
  this.listeners.forEach(function(item) {
    item.dom.removeEventListener(item.event, item.type);
  });
ログイン後にコピー

実行中のスクリーンショット

PC側の実行中のスクリーンショットは以下の通りです:

リスニングイベントの登録後は以下のようになります:

携帯電話での実行中のスクリーンショット:

パフォーマンス効果がネイティブ スクロール バーと一致していることがわかります。

結論と感想

上記は基本的に私がデザインしたスクロールバーのデザインです。 まず第一に、私にこのような共有プラットフォームを提供してくれたナゲッツに感謝し、それから作者に感謝したいと思います。このようなアイデアを与えてくれたslimScroll。このプラグインを完成させた後、DOM 要素のscrollWidth、scrollHeigh、scrollTop、scrollLeft について詳しく知ることができました。これが将来皆さんに役立つことを願っています。

関連記事:

vue ルートパラメータの受け渡しの 3 つの基本モード (詳細なチュートリアル)

JavaScript の関連トリック

webpack でファイルを動的にインポートする実装

以上がvue.js の仮想スクロール バー約 2.xの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、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)

Microsoft、Windows 11のFluentスクロールバーをGoogle Chromeに導入 Microsoft、Windows 11のFluentスクロールバーをGoogle Chromeに導入 Apr 14, 2023 am 10:52 AM

Windows 10 とは異なり、Windows 11 には、ユーザーが操作すると形状が変化する新しい最新の「流体スクロールバー」が搭載されています。 Fluent スクロールバーは本質的に動的であり、さまざまなフォーム ファクターで、またはウィンドウ サイズを変更すると自動的に拡大縮小され、現在、設定、メディア プレーヤーなどのアプリで使用されています。 Microsoftの新たな提案によると、Google Chromeにはまもなくスムーズなスクロールバー機能が搭載される可能性があるという。 Microsoftは提案の中で、Chromeの古いスクロールバーを最新化したいと述べている

vite が .env ファイルを解析する方法についての詳細な説明 vite が .env ファイルを解析する方法についての詳細な説明 Jan 24, 2023 am 05:30 AM

Vue フレームワークを使用してフロントエンド プロジェクトを開発する場合、デプロイ時に複数の環境をデプロイすることになりますが、開発環境、テスト環境、オンライン環境で呼び出されるインターフェイス ドメイン名が異なることがよくあります。どうすれば区別できるでしょうか?それは環境変数とパターンを使用することです。

Ace コード エディターを Vue プロジェクトに統合する方法の詳細な図による説明 Ace コード エディターを Vue プロジェクトに統合する方法の詳細な図による説明 Apr 24, 2023 am 10:52 AM

Ace は、JavaScript で書かれた埋め込み可能なコード エディターです。 Sublime、Vim、TextMate などのネイティブ エディターの機能とパフォーマンスに匹敵します。あらゆる Web ページや JavaScript アプリケーションに簡単に埋め込むことができます。 Ace は Cloud9 IDE のメイン エディタとして維持されており、Mozilla Skywriter (Bespin) プロジェクトの後継です。

Vue3 で単体テストを作成する方法を調べる Vue3 で単体テストを作成する方法を調べる Apr 25, 2023 pm 07:41 PM

Vue.js は、今日のフロントエンド開発において非常に人気のあるフレームワークとなっています。 Vue.js が進化し続けるにつれて、単体テストの重要性がますます高まっています。今日は、Vue.js 3 で単体テストを作成する方法を検討し、いくつかのベスト プラクティスと一般的な問題と解決策を提供します。

vue3 の reactive() について詳しく話しましょう vue3 の reactive() について詳しく話しましょう Jan 06, 2023 pm 09:21 PM

前書き: vue3 の開発では、reactive は応答性の高いデータを実装するメソッドを提供します。これは日常の開発で頻繁に使用される API です。この記事では、著者はその内部動作メカニズムを探ります。

JSX 構文と Vue のテンプレート構文の簡単な比較 (利点と欠点の分析) JSX 構文と Vue のテンプレート構文の簡単な比較 (利点と欠点の分析) Mar 23, 2023 pm 07:53 PM

Vue.js では、開発者は、JSX 構文とテンプレート構文という 2 つの異なる構文を使用してユーザー インターフェイスを作成できます。どちらの構文にもそれぞれ長所と短所があるので、それらの違い、長所と短所について説明します。

現在の Vue バージョンをクエリする方法 現在の Vue バージョンをクエリする方法 Dec 19, 2022 pm 04:55 PM

現在の Vue バージョンを照会するには 2 つの方法があります: 1. cmd コンソールで、「npm list vue」コマンドを実行してバージョンを照会します。出力結果は Vue のバージョン番号情報です。2. パッケージを見つけて開きます。プロジェクト内のjsonファイルを検索して「依存関係」の項目でvueのバージョン情報が確認できます。

Vue2実装APIの原理を解析する Vue2実装APIの原理を解析する Jan 13, 2023 am 08:30 AM

Vue3 のリリース以来、単語合成 API は Vue を書く学生の視野に入ってきました。合成 API が以前のオプション API よりもどれほど優れているかは誰もが聞いたことがあると思います。そして、@ のリリースにより、 vue/composition-api プラグイン、Vue2 学生もバスに乗れます. 次に、主に Response ref と Reactive を使用して、このプラグインがどのようにこれを実現しているかを詳細に分析します。

See all articles