<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專(zhuān)題視頻專(zhuān)題問(wèn)答1問(wèn)答10問(wèn)答100問(wèn)答1000問(wèn)答2000關(guān)鍵字專(zhuān)題1關(guān)鍵字專(zhuān)題50關(guān)鍵字專(zhuān)題500關(guān)鍵字專(zhuān)題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專(zhuān)題關(guān)鍵字專(zhuān)題tag2tag3文章專(zhuān)題文章專(zhuān)題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專(zhuān)題3
        問(wèn)答文章1 問(wèn)答文章501 問(wèn)答文章1001 問(wèn)答文章1501 問(wèn)答文章2001 問(wèn)答文章2501 問(wèn)答文章3001 問(wèn)答文章3501 問(wèn)答文章4001 問(wèn)答文章4501 問(wèn)答文章5001 問(wèn)答文章5501 問(wèn)答文章6001 問(wèn)答文章6501 問(wèn)答文章7001 問(wèn)答文章7501 問(wèn)答文章8001 問(wèn)答文章8501 問(wèn)答文章9001 問(wèn)答文章9501
        當(dāng)前位置: 首頁(yè) - 科技 - 知識(shí)百科 - 正文

        基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼

        來(lái)源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-27 22:20:54
        文檔

        基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼

        基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼:前言 記得以前偶然有一次瀏覽過(guò)一個(gè)開(kāi)源的cms項(xiàng)目,發(fā)現(xiàn)這個(gè)項(xiàng)目的左邊的菜單已經(jīng)超出了windows的寬度,我就好奇為什么沒(méi)出滾動(dòng)條呢?然后我仔細(xì)一看,發(fā)現(xiàn)它左側(cè)有一個(gè)小的div,然后我嘗試著拖動(dòng)它,發(fā)現(xiàn)竟能和原生的滾動(dòng)條一樣!可以通過(guò)查看它的源碼,發(fā)現(xiàn)
        推薦度:
        導(dǎo)讀基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼:前言 記得以前偶然有一次瀏覽過(guò)一個(gè)開(kāi)源的cms項(xiàng)目,發(fā)現(xiàn)這個(gè)項(xiàng)目的左邊的菜單已經(jīng)超出了windows的寬度,我就好奇為什么沒(méi)出滾動(dòng)條呢?然后我仔細(xì)一看,發(fā)現(xiàn)它左側(cè)有一個(gè)小的div,然后我嘗試著拖動(dòng)它,發(fā)現(xiàn)竟能和原生的滾動(dòng)條一樣!可以通過(guò)查看它的源碼,發(fā)現(xiàn)

        前言

        記得以前偶然有一次瀏覽過(guò)一個(gè)開(kāi)源的cms項(xiàng)目,發(fā)現(xiàn)這個(gè)項(xiàng)目的左邊的菜單已經(jīng)超出了windows的寬度,我就好奇為什么沒(méi)出滾動(dòng)條呢?然后我仔細(xì)一看,發(fā)現(xiàn)它左側(cè)有一個(gè)小的div,然后我嘗試著拖動(dòng)它,發(fā)現(xiàn)竟能和原生的滾動(dòng)條一樣!可以通過(guò)查看它的源碼,發(fā)現(xiàn)了這款滾動(dòng)條的叫做slimScroll,然后我去它的github倉(cāng)庫(kù) 看了下,研究了一下源碼,給我的感覺(jué)是我也能做出來(lái)一樣的滾動(dòng)條!通過(guò)vue實(shí)現(xiàn)!

        設(shè)計(jì)

        好, 現(xiàn)在開(kāi)始我們的設(shè)計(jì)滾動(dòng)條的步驟:

        設(shè)計(jì)滾動(dòng)條dom

        首先要思考的是: 如果要使你需要滾動(dòng)的內(nèi)容滾動(dòng)的話(huà),首先一點(diǎn)是它的父dom必須為固定長(zhǎng)寬,即超出部分要隱藏掉,即加了個(gè)樣式: overflow: hidden , 所以,我們給所要滾動(dòng)的內(nèi)容加個(gè)包裝,使它的長(zhǎng)寬和父dom相等,然后有一個(gè)樣式叫: overflow: hidden ,這個(gè)包裝的元素就叫 scrollPanel

        其次:我們知道,我們要做到與原生滾動(dòng)條一樣強(qiáng)大!就必須設(shè)計(jì)水平滾動(dòng)條和垂直滾動(dòng)條,滾動(dòng)條和scrollPanel屬于兄弟節(jié)點(diǎn)之間的關(guān)系,因?yàn)闈L動(dòng)條的存在不能使原本的樣式排版錯(cuò)誤,并且支持top、left來(lái)控制其位置,所以滾動(dòng)條的position必須是absolute,好了,我們叫水平滾動(dòng)條為:hBar,垂直滾動(dòng)條為:vBar

        最后:我們?cè)O(shè)計(jì)了scrollPanel、vBar、hBar, 我們需要一個(gè)父div來(lái)把他們包裝起來(lái),然后加個(gè)樣式:position: relative

        實(shí)踐

        設(shè)計(jì)組件結(jié)構(gòu)

        首先,我們的插件一共是4個(gè)組件,其中3個(gè)是子組件,1個(gè)是父組件,分別是: vueScroll (父組件)、 scrollPanel (包裹需要滾動(dòng)內(nèi)容的子組件)、 vBar (垂直滾動(dòng)條)、 hBar (水平滾動(dòng)條)

        其次,讓我們?cè)O(shè)計(jì)一下各組件所分管的功能。這里的組件分為控制層組件和展示組件(熟悉react的同學(xué)應(yīng)該有所了解),展示層組件只完成展示的功能: vBar 、 hBar 、 scrollPanel ,控制層組件有點(diǎn)類(lèi)似于cpu,可以控制子組件的各個(gè)狀態(tài),比如寬、高、顏色、透明度、位置等等。控制層組件就是: vueScroll 。

        具體實(shí)現(xiàn)

        hBar/vBar

        hBar/vBar 這兩個(gè)分別為水平滾動(dòng)條和垂直滾動(dòng)條,所實(shí)現(xiàn)的功能大體是一樣的,所以舊放在一起說(shuō)了,這里以 vBar 為例。

        props 接收父組件傳過(guò)來(lái)的屬性,具體為:

        {
         height: vm.state.height + 'px', //滾動(dòng)條的高度
         width: vm.ops.width, // 滾動(dòng)條的寬度
         position: 'absolute', 
         background: vm.ops.background, // 滾動(dòng)條背景色
         top: vm.state.top + 'px', // 滾動(dòng)條的高度
         transition: 'opacity .5s', // 消失/顯示 所用的時(shí)間
         cursor: 'pointer', //
         opacity: vm.state.opacity, // 透明度
         userSelect: 'none' 
         }

        2 事件,主要是當(dāng)鼠標(biāo)移動(dòng)的時(shí)候,顯示滾動(dòng)條。

        ...
        render(_c){
         return _c(
         // ...
         {
         mouseenter: function(e) {
         vm.$emit('showVBar'); // 觸發(fā)父組件事件,顯示滾動(dòng)條
         }
         }
         // ...
         )
        }

        其中 state 表示狀態(tài),是在運(yùn)行時(shí)可發(fā)生改變的,而 ops 則是配置參數(shù),是用戶(hù)傳過(guò)來(lái)的。

        scrollPanel

        包裹滾動(dòng)內(nèi)容的組件,樣式需設(shè)置為: 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

        控制組件。控制子組件顯示的狀態(tài),添加各種監(jiān)聽(tīng)事件等。

        1、取得子組件的dom元素,用來(lái)取得dom的實(shí)時(shí)信息。

        // ...
         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、顯示滾動(dòng)條

        顯示滾動(dòng)條,包括顯示水平滾動(dòng)條和顯示垂直滾動(dòng)條,這里以顯示垂直滾動(dòng)條為例:

        // ...
         var temp;
         var deltaY = {
         deltaY: this.vScrollBar.ops.deltaY // 獲取用戶(hù)配置的deltaY
         };
         if(!this.isMouseLeavePanel || this.vScrollBar.ops.keepShow){
         if ((this.vScrollBar.state.height = temp = this.getVBarHeight(deltaY))) { // 判斷條件
         // 重新設(shè)置滾動(dòng)條的狀態(tài)
         this.vScrollBar.state.top = this.resizeVBarTop(temp);
         this.vScrollBar.state.height = temp.height;
         this.vScrollBar.state.opacity = this.vScrollBar.ops.opacity;
         }
         }
         // ...
        

        3、獲取滾動(dòng)條的高度

        因?yàn)閐om元素的高度不是固定的,所以你要實(shí)時(shí)地獲取dom真實(shí)的高度,滾動(dòng)條的高度計(jì)算公式如下:

        var height = Math.max(
         scrollPanelHeight / 
         (scrollPanelScrollHeight / scrollPanelHeight), 
         this.vScrollBar.minBarHeight
         );

        即: 滾動(dòng)條的高度:scrollPanel的高度 == scrollPanel的高度:dom元素高度

        4、resizeVBarTop ,為了防止誤差,并且可以求出滾動(dòng)條距離父元素的高度。

        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、監(jiān)聽(tīng)滾輪滾動(dòng)的事件。

        // ...
         on: {
         wheel: vm.wheel
         }
         // ...
         wheel(e) {
         var vm = this;
         vm.showVBar();
         vm.scrollVBar(e.deltaY > 0 ? 1 : -1, 1);
         e.stopPropagation();
         }
         // ...
        

        6、監(jiān)聽(tīng)滾動(dòng)條拖拽事件

        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('mousemove', move);
         document.addEventListener('mouseup', function(e) {
         vm.mousedown = false;
         vm.hideVBar();
         document.removeEventListener('mousemove', move);
         });
         }
         this.listeners.push({
         dom: vm.vScrollBar.el,
         event: t,
         type: "mousedown"
         });
         vm.vScrollBar.el.addEventListener('mousedown', t); // 把事件放到數(shù)組里面,等銷(xiāo)毀之前移除掉注冊(cè)的時(shí)間。
         }

        7、適配移動(dòng)端,監(jiān)聽(tīng) touch 事件。原理跟拖拽事件差不多,無(wú)非就是多了個(gè)判斷,來(lái)判斷當(dāng)前方向是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('touchmove', move);
         pannel.addEventListener('touchend', function(e) {
         vm.mousedown = false;
         vm.hideBar();
         pannel.removeEventListener('touchmove', move);
         });
         }
         }
         pannel.addEventListener('touchstart', t);
         this.listeners.push({
         dom: pannel,
         event: t,
         type: "touchstart"
         });
         }
        

        8、滾動(dòng)內(nèi)容

        滾動(dòng)內(nèi)容的原理無(wú)非就是改變 scrollPanel 的 scrollTop/scrollLeft 來(lái)達(dá)到控制內(nèi)容上下左右移動(dòng)的目的。

        scrollVBar: function(pos, time) {
         // >0 scroll to down <0 scroll to up
         
         var top = this.vScrollBar.state.top; 
         var scrollPanelHeight = getComputed(this.scrollPanel.el, 'height').replace('px', "");
         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);
         }
         }
         // 這些是傳遞給父組件的監(jiān)聽(tīng)滾動(dòng)的函數(shù)的。
         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('vscroll', bar, content, process);
         },
        

        9、銷(xiāo)毀注冊(cè)的事件。

        剛才我們已經(jīng)把注冊(cè)事件放到listeners數(shù)組里面了,我們可以在beforedestroy鉤子里將他們進(jìn)行銷(xiāo)毀。

        // remove the registryed event.
         this.listeners.forEach(function(item) {
         item.dom.removeEventListener(item.event, item.type);
         });

        運(yùn)行截圖

        PC端運(yùn)行截圖如下圖所示:

        注冊(cè)監(jiān)聽(tīng)事件以后如下圖所示:

        在手機(jī)上運(yùn)行截圖:

        可以看出,跟原生滾動(dòng)條表現(xiàn)效果一致。

        結(jié)語(yǔ)&感悟

        以上就基本把我設(shè)計(jì)的滾動(dòng)條設(shè)計(jì)完了,首先很感激掘金給了我這么一個(gè)分享平臺(tái),然后感謝slimScroll的作者給了我這么一個(gè)思路。做完這個(gè)插件, 我對(duì)dom元素的scrollWidth、scrollHeigh、scrollTop、scrollLeft的了解更多了,最后,附上github項(xiàng)目地址

        以上部分就是這個(gè)組件的核心源碼了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

        聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼

        基于vue.js 2.x的虛擬滾動(dòng)條的示例代碼:前言 記得以前偶然有一次瀏覽過(guò)一個(gè)開(kāi)源的cms項(xiàng)目,發(fā)現(xiàn)這個(gè)項(xiàng)目的左邊的菜單已經(jīng)超出了windows的寬度,我就好奇為什么沒(méi)出滾動(dòng)條呢?然后我仔細(xì)一看,發(fā)現(xiàn)它左側(cè)有一個(gè)小的div,然后我嘗試著拖動(dòng)它,發(fā)現(xiàn)竟能和原生的滾動(dòng)條一樣!可以通過(guò)查看它的源碼,發(fā)現(xiàn)
        推薦度:
        標(biāo)簽: VUE js 滾動(dòng)條
        • 熱門(mén)焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門(mén)推薦

        專(zhuān)題
        Top
        主站蜘蛛池模板: 一级免费黄色毛片| 亚洲国产精品乱码一区二区 | 无码亚洲成a人在线观看| 亚洲片国产一区一级在线观看| 最近中文字幕大全免费版在线| 国产成人精品日本亚洲专一区| 亚洲成?Ⅴ人在线观看无码| 一级毛片免费观看不卡的| 亚洲欧美日韩自偷自拍| 国产亚洲成av片在线观看| 成人毛片18女人毛片免费96 | 亚洲人成网站影音先锋播放| 成人黄软件网18免费下载成人黄18免费视频 | 亚洲精品成人a在线观看| 久草视频免费在线| 中文字幕成人免费高清在线| 亚洲一区二区免费视频| 亚洲精品少妇30p| 国产成人青青热久免费精品| 日本免费在线中文字幕| 五月婷婷免费视频| 亚洲欧美日韩自偷自拍| 亚洲第一网站免费视频| 亚洲精品无码专区久久久| 国产成人免费手机在线观看视频| 最近中文字幕大全免费视频 | 色费女人18女人毛片免费视频| 久久亚洲私人国产精品vA| 久久久久亚洲av毛片大| 国外成人免费高清激情视频| 日韩人妻无码精品久久免费一| 人人公开免费超级碰碰碰视频 | 国产免费的野战视频| 人人玩人人添人人澡免费| 一级黄色毛片免费看| 亚洲AV日韩AV永久无码色欲| 亚洲一区在线免费观看| 亚洲白色白色永久观看| 国产v亚洲v天堂无码网站| 国产偷窥女洗浴在线观看亚洲 | 午夜dj免费在线观看|