首頁 web前端 js教程 在vue.js中有關2.x的虛擬捲軸

在vue.js中有關2.x的虛擬捲軸

Jun 09, 2018 pm 05:25 PM
vue.js 捲軸

本篇文章主要介紹了基於vue.js 2.x的虛擬捲軸的範例程式碼,現在分享給大家,也給大家做個參考。

前言

記得以前偶然有一次瀏覽過一個開源的cms項目,發現這個項目的左邊的選單已經超出了windows的寬度,我就好奇為什麼沒出捲軸呢?然後我仔細一看,發現它左側有一個小的p,然後我嘗試著拖動它,發現竟能和原生的滾動條一樣!可以透過查看它的源碼,發現了這款滾動條的叫做slimScroll,然後我去它的github倉庫 看了下,研究了一下源碼,給我的感覺是我也能做出來一樣的滾動條!透過vue實現!

設計

好,現在開始我們的設計捲軸的步驟:

設計捲軸dom

#首先要思考的是: 如果要讓你需要滾動的內容滾動的話,首先一點是它的父dom必須為固定長寬,即超出部分要隱藏掉,即加了個樣式: overflow: hidden ,所以,我們為所要滾動的內容加個包裝,使它的長寬和父dom相等,然後有一個樣式叫: overflow: hidden ,這個包裝的元素就叫scrollPanel

其次:我們知道,我們要做到與原生捲軸一樣強大!就必須設計水平滾動條和垂直滾動條,滾動條和scrollPanel屬於兄弟節點之間的關係,因為滾動條的存在不能使原本的樣式排版錯誤,並且支持top、left來控制其位置,所以滾動條的position必須是absolute,好了,我們叫水平滾動條為:hBar,垂直滾動條為:vBar

最後:我們設計了scrollPanel、vBar、hBar, 我們需要一個父p來把他們包裝起來,然後加個樣式:position: relative

實踐

#設計元件結構

##首先,我們的外掛一共是4個組件,其中3個是子組件,1個是父組件,分別是: vueScroll (父組件)、 scrollPanel (包裹需要滾動內容的子組件)、 vBar (垂直滾動條)、 hBar (水平滾動條)

其次,讓我們設計一下各元件所分管的功能。這裡的組件分為控制層組件和展示組件(熟悉react的同學應該有所了解),展示層組件只完成展示的功能: vBar 、 hBar 、 scrollPanel ,控制層組件有點類似於cpu,可以控制子組件的各個狀態,如寬、高、顏色、透明度、位置等等。控制層元件就是: vueScroll 。

具體實作

hBar/vBar

#hBar/vBar 這兩個分別為水平捲軸和垂直捲軸,所實現的功能大致是一樣的,所以舊放在一起說了,這裡以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');
        }
      }
    // ...
  }
 // ...
登入後複製

#vuescroll

控制元件。控制子組件顯示的狀態,新增各種監聽事件等。

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
      );
登入後複製

即: 捲動條的高度:scrollPanel的高度== scrollPanel的高度: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、適配行動端,監聽 touch 事件。原理跟拖曳事件差不多,無非就是多了個判斷,來判斷當前方向是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、銷毀註冊的事件。

剛才我們已經把註冊事件放到listeners陣列裡面了,我們可以在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中有關的trick

在webpack中實作動態引入檔案

#

以上是在vue.js中有關2.x的虛擬捲軸的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

微軟將 Windows 11 的 Fluent 捲軸引入 Google Chrome 微軟將 Windows 11 的 Fluent 捲軸引入 Google Chrome Apr 14, 2023 am 10:52 AM

與 Windows 10 不同,Windows 11 具有新的現代“流暢捲軸”,當使用者與之互動時會改變形狀。 Fluent 捲軸本質上是動態的,它們會在不同的外形尺寸或當您更改視窗大小時自動縮放,並且它目前在設定、媒體播放器等應用程式中使用。根據微軟的一項新提議,Google瀏覽器可能很快就會擁有流暢的捲軸功能。微軟在一份提案中表示,他們希望對 Chrome 中的舊捲軸進行現代化

深入探討vite是怎麼解析.env檔的 深入探討vite是怎麼解析.env檔的 Jan 24, 2023 am 05:30 AM

使用vue框架開發前端專案時,我們部署的時候都會部署多套環境,往往開發、測試以及線上環境呼叫的介面網域都是不一樣的。如何能做到區分呢?那就是使用環境變數和模式。

圖文詳解如何在Vue專案中整合Ace程式碼編輯器 圖文詳解如何在Vue專案中整合Ace程式碼編輯器 Apr 24, 2023 am 10:52 AM

Ace 是一個用 JavaScript 寫的可嵌入程式碼編輯器。它與 Sublime、Vim 和 TextMate 等原生編輯器的功能和效能相符。它可以很容易地嵌入到任何網頁和 JavaScript 應用程式中。 Ace 被維護為Cloud9 IDE的主要編輯器 ,並且是 Mozilla Skywriter (Bespin) 專案的繼承者。

探討如何在Vue3中撰寫單元測試 探討如何在Vue3中撰寫單元測試 Apr 25, 2023 pm 07:41 PM

在當今前端開發中,Vue.js 已經成為了一個非常流行的框架。隨著 Vue.js 的不斷發展,單元測試變得越來越重要。今天,我們將探討如何在 Vue.js 3 中編寫單元測試,並提供一些最佳實踐和常見的問題及解決方案。

Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Vue中JSX語法和模板語法的簡單比較(優劣勢分析) Mar 23, 2023 pm 07:53 PM

在Vue.js中,開發人員可以使用兩種不同的語法來建立使用者介面:JSX語法和範本語法。這兩種文法各有優劣,以下就來探討它們的差異和優劣勢。

深入聊聊vue3中的reactive() 深入聊聊vue3中的reactive() Jan 06, 2023 pm 09:21 PM

前言:在vue3的開發中,reactive是提供實現響應式資料的方法。日常開發這個是使用頻率很高的api。這篇文章筆者就來探索其內部運作機制。

淺析vue怎麼實現檔案切片上傳 淺析vue怎麼實現檔案切片上傳 Mar 24, 2023 pm 07:40 PM

在實際開發專案過程中有時候需要上傳比較大的文件,然後呢,上傳的時候相對來說就會慢一些,so,後台可能會要求前端進行文件切片上傳,很簡單哈,就是把比如說1個G的檔案流切割成若干個小的檔案流,然後分別請求介面傳遞這個小的檔案流。

聊聊vue3怎麼使用高德地圖api 聊聊vue3怎麼使用高德地圖api Mar 09, 2023 pm 07:22 PM

在我們使用高德地圖的時候,官方給我們推薦了很多案例,demo,但是這些案例都是使用原生方法接入,並沒有提供vue或者react 的demo,vue2的接入網上也很多人都有寫過,以下這篇文章就來看看vue3怎麼使用常用的高德地圖api,希望對大家有幫助!

See all articles