vue+eleui專案 專案結構(封裝一個全域性元件-滾動條)
阿新 • • 發佈:2019-01-28
固定高度表格,然後裡面滾動,原生滾動條太難看,而且還有相容問題,好吧,那就自己寫一個吧
<template> <div class="v-scroll-bar" @wheel.prevent="wheelEventHandle" :style="{height:height+'px'}" ref="jScroll"> <!--滾動內容--> <div class="scroll-content" :style="scrollContentStyles"> <slot></slot> </div> <!--滾動條--> <div :class="['scroll-bar-wrap',autoHide?'autoHide':'']" :style="scrollWrapStyle" @mousedown.prevent.stop="clickBarWrapHandler"> <div ref="bar" class="scroll-bar" :style="scrollBarStyle" @mousedown.prevent.stop="clickBarHandler"> </div> </div> </div> </template>
<script> export default { name: 'v-scroll-bar', props: { // 外框高度 height: {type: Number, default: 100, required: true}, // 行高 lineHeight: {type: Number, required: true}, // 資料的長度 length: {type: Number, required: true}, // 速度 speed: {type: Number, default: 2}, //自動隱藏 autoHide: {type: Boolean, default: true}, //滾動條寬度 barWidth: {type: Number, default: 6}, //滾動條跑道顏色 barWrapColor: {type: String, default: 'transparent'}, //滾動條顏色 barColor: {type: String, default: 'rgba(0,0,0,.6)'}, //圓角 radius: {type: Number, default: 10}, //滾動條距離內容的距離 gap: {type: Number, default: 0}, }, data() { return { // 滾動距離 scrollTop: 0, }; }, computed: { // 滾動步長 一次滾動多少的距離 scrollStep() { return this.lineHeight / this.speed; // return 5; }, // 內容的高度 scrollHeight() { return this.length * this.lineHeight; }, // 可滾動的高度 useableDistance() { return this.scrollHeight - this.height; }, // 滾動內容的樣式 scrollContentStyles() { if (this.scrollHeight < this.height) this.scrollTop = 0; return { transform: `translateY(${this.scrollTop}px)`, paddingRight: `${this.gap}px`, }; }, // 滾動條外框樣式 scrollWrapStyle() { return { width: `${this.barWidth}px`, backgroundColor: this.barWrapColor, borderRadius: `${this.radius}px`, }; }, // 滾動條樣式 scrollBarStyle() { this.translateY = (-this.scrollTop * this.height) / this.scrollHeight; let translateY = `translateY(${this.translateY}px)`; return { height: `${this.scrollBarHeight}px`, transform: translateY, msTransform: translateY, webkitTransform: translateY, backgroundColor: this.barColor, borderRadius: `${this.radius}px` }; }, // 滾動條高度 scrollBarHeight() { let barHeight = (this.height * this.height) / (this.length * this.lineHeight); if (barHeight >= this.height) return 0; return barHeight; }, }, methods: { // 滾輪事件處理 wheelEventHandle(event) { let {deltaY} = event; if (deltaY > 0) this.prevScorllHandle(); if (deltaY < 0) this.nextScorllHandle(); }, // 向上滾動 prevScorllHandle() { if (-this.useableDistance < this.scrollTop) { this.scrollTop -= this.scrollStep; } }, // 向下滾動 nextScorllHandle() { if (this.scrollTop < 0) { this.scrollTop += this.scrollStep; } }, //滑塊點選事件 clickBarHandler(event) { event.stopImmediatePropagation(); document.addEventListener('mousemove', this.mouseMoveDocumentHandler, false); document.addEventListener('mouseup', this.mouseUpDocumentHandler, false); document.onselectstart = () => false; this.yMove = ( event.currentTarget.offsetHeight - (event.clientY - event.currentTarget.getBoundingClientRect().top) ); }, // 滑鼠移動事件 mouseMoveDocumentHandler(event) { let prevPage = this.yMove; if (!prevPage) return; let thumbClickPosition = this.$refs['bar'].offsetHeight - prevPage; this.barMoveHandle(event, this.$el, thumbClickPosition); }, // 滑鼠擡起來的事件 mouseUpDocumentHandler() { this.yMove = 0; document.removeEventListener('mousemove', this.mouseMoveDocumentHandler); document.onselectstart = null; }, //滑塊外框事件 clickBarWrapHandler(event) { let thumbHalf = this.$refs['bar'].offsetHeight / 2; this.barMoveHandle(event, event.target, thumbHalf); }, // 滑塊移動處理 barMoveHandle(event, dom, position) { let offset = Math.abs(dom.getBoundingClientRect()['top'] - event.clientY); let thumbPositionPercentage = (offset - position) * 100 / this.$el.offsetHeight; let scrollTop = -(thumbPositionPercentage * this.scrollHeight / 100); if (-scrollTop >= this.useableDistance) { return this.scrollTop = -this.useableDistance } else if (scrollTop >= 0) { return this.scrollTop = 0; } this.scrollTop = scrollTop; }, // 如果有iframe 也需要處理 iframeDocumentHandle() { let iframe = document.getElementsByTagName('iframe'); if (iframe) { for (let i = 0; i < iframe.length; i++) { let iframeDocument = iframe[i].contentWindow.document; iframeDocument.addEventListener('mouseup', this.mouseUpDocumentHandler, false); } } } }, destroyed() { document.removeEventListener('mouseup', this.mouseUpDocumentHandler); }, mounted() { this.iframeDocumentHandle(); } }; </script>
<style lang="scss" rel="stylesheet/scss" scoped> .v-scroll-bar { width: 100%; overflow: hidden; position: relative; &:hover .autoHide { opacity: 1; } .autoHide { opacity: 0; transition: all 200ms; } .scroll-bar-wrap { position: absolute; top: 0; right: 0; height: 100%; overflow: hidden; cursor: pointer; .scroll-bar { width: 100%; cursor: ns-resize; } } } </style>