vue可视化
git地址:https://gitee.com/HuaWang400/jiajuxiaoshou
转载自:https://juejin.cn/post/6931189766109003783
滚动播报
公共组件-路由组件
<template> <div class="scroll"> <div class="scroll-header" :style="{ height : headerConfig.headerHeight + 'px', background: headerConfig.headerBackground, }"> <div class="scroll-header-item" v-for="(item, index) in headerConfig.headerItems" :key = "'scroll-header-item' + index" :style="{ averageWidth + 'px', ... headerConfig.headerStyle[index] }"> {{item}}</div> </div> <div class="scroll-content" ref="scrollContent"> <div v-for="(item, index) in rowsData" :key = "item.index" :style = "{ height: rowHeights[index] + 'px', background: item.index % 2 === 0 ? rowBackground[0] : rowBackground[1] }" class="scroll-content-li"> <div v-for="( k, i ) in Object.keys(item.data)" :key = "'scroll-content-li' + i" class="scroll-content-li-item" :style="{ headerConfig.headerStyle[i].width ? headerConfig.headerStyle[i].width : averageWidth + 'px', }">{{item.data[k]}}</div> </div> </div> </div> </template> <script> export default { name: 'scroll', props: { header: { type: Object, required: true }, rows: { type: Array, required: true }, capacity: { type: Number, required: true }, rowBackground: { type: Array, default: function () { return ['hsl(207deg 84% 51% / 8%)', 'transparent'] } }, duration: { type: Number, default: 3000 } }, data () { return { headerConfig: null, averageWidth: 0, rowHeight: 0, currentIndex: 0, rowsx: null, rowsData: null, step: 1, rowHeights: new Array(this.rows.length).fill(0) } }, watch: { rows: { handler (newValue, oldValue) { this.handleRowData() const index = this.currentIndex > 0 ? this.currentIndex - 1 : this.currentIndex const temp = this.rowsx.slice(index) temp.push(...this.rowsx.slice(0, index)) this.rowsData = temp clearTimeout(this.timer) this.timer = setTimeout(() => { this.animation() }, this.duration) }, deep: true } }, methods: { handleRowData () { let temp = this.rows.slice() if (this.rows.length > this.capacity) { temp = this.rows.slice().concat(this.rows.slice()) } this.rowsx = temp.map((item, index) => { return { data: item, index: index } }) this.rowsData = this.rowsx.slice() }, setConfig () { const headerConfigDefault = { headerItems: [], headerBackground: 'transparent', headerHeight: 60, headerStyle: [] } this.headerConfig = Object.assign(headerConfigDefault, this.header) this.handleRowData() }, setHeaderWidth () { const width = this.$el.clientWidth let fixedWidth = 0 let n = 0 this.headerConfig.headerStyle.forEach(item => { if (item.width) { fixedWidth += parseInt(item.width) n++ } }) this.averageWidth = (width - fixedWidth) / (this.header.headerItems.length - n) }, animation () { clearTimeout(this.timer) const len = this.rowsx.length if (len <= this.capacity) return const temp = this.rowsx.slice(this.currentIndex) temp.push(...this.rowsx.slice(0, this.currentIndex)) this.rowHeights = new Array(len).fill(this.rowHeight) this.rowHeights.splice(0, this.step, ...new Array(this.step).fill(0)) this.rowsData = temp this.currentIndex += this.step const isLast = this.currentIndex - len if (isLast >= 0) this.currentIndex = isLast this.timer = setTimeout(() => { this.animation() }, this.duration) }, setContentHeight () { const height = this.$el.clientHeight const h = height - this.headerConfig.headerHeight this.$refs.scrollContent.style.height = h + 'px' const min = Math.min(this.rows.length, this.capacity) this.rowHeight = h / min this.rowHeights = new Array(min).fill(this.rowHeight) } }, created () { if (!this.header.headerItems || this.header.headerItems.length === 0) return this.setConfig() this.$nextTick(() => { this.setHeaderWidth() this.setContentHeight() this.timer = setTimeout(() => { this.animation() }, this.duration) }) } } </script> <style lang="less" scoped> .scroll{ height: 100%; 100%; text-align: center; &-header{ display: flex; align-items: center; &-item{ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } } &-content{ overflow: hidden; &-li{ display: flex; align-items: center; overflow: hidden; transition: all 0.3s linear; &-item{ display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; overflow:hidden; padding:0 10px; } } } } </style>
<template> <div class="star-product"> <div class="title">明星产品销售概况</div> <div class="list"> <scroll :header="header" :rows="list" :duration="duration" :capacity="6" ></scroll> </div> </div> </template> <script> import Scroll from "@/components/Common/Scroll"; export default { components: { Scroll, }, data() { return { starProduct: [ { name: "A品牌木门", sales: 92090, orders: 51, }, { name: "B品牌沙发", sales: 602090, orders: 107, }, { name: "C品牌衣柜", sales: 802090, orders: 94, }, { name: "D品牌木门", sales: 92090, orders: 51, }, { name: "E品牌沙发", sales: 602090, orders: 107, }, { name: "F品牌木门", sales: 92090, orders: 51, }, { name: "G品牌木门", // sales: 92090, // orders: 51, }, // { // name: "H品牌沙发", // sales: 602090, // orders: 107, // }, ], header: { headerItems: ["产品", "销售额", "订单量",], headerHeight: 140, headerStyle: [ { fontSize: "45px", }, { "260px", fontSize: "45px", }, { "260px", fontSize: "45px", }, ], }, rowBg: ["red", "green"], duration: 3000, }; }, computed: { list() { return this.starProduct; }, }, }; </script> <style lang="less" scoped> .star-product { height: 100%; 100%; display: flex; flex-direction: column; .title { height: 100px; font-size: 40px; font-weight: bold; } .list { flex: 1; 100%; font-size: 36px; } } </style>
全屏/退出
<template> <div class="display-header"> <span class="sub">数据更新于:{{ time }}</span> <span class="title">2020秋季家具交易会实时销售数据可视化平台</span> <span class="sub full-screen" @click="toggleScreen">{{ operationText }}</span> </div> </template> <script> let timer export default { data () { return { isFullScreen: false } }, computed: { operationText () { return this.isFullScreen ? '退出' : '全屏' }, time () { const t = this.$store.state.updateTime return `${t.toLocaleDateString()} ${t.toLocaleTimeString()}` } }, methods: { toggleScreen () { const main = document.body if (this.isFullScreen) { if (document.exitFullscreen) { document.exitFullscreen() } else if (document.mozCancelFullScreen) { document.mozCancelFullScreen() } else if (document.webkitCancelFullScreen) { document.webkitCancelFullScreen() } else if (document.msExitFullscreen) { document.msExitFullscreen() } } else { if (main.requestFullscreen) { main.requestFullscreen() } else if (main.mozRequestFullScreen) { main.mozRequestFullScreen() } else if (main.webkitRequestFullScreen) { main.webkitRequestFullScreen() } else if (main.msRequestFullscreen) { main.msRequestFullscreen() } } }, changeFullScreenStatus () { this.isFullScreen = !this.isFullScreen } }, mounted () { if (document.body.requestFullscreen) { document.addEventListener('fullscreenchange', this.changeFullScreenStatus) } else if (document.body.msRequestFullscreen) { document.addEventListener('MSFullscreenChange', this.changeFullScreenStatus) } }, destroyed () { clearInterval(timer) if (document.body.requestFullscreen) { document.removeEventListener('fullscreenchange', this.changeFullScreenStatus) } else if (document.body.msRequestFullscreen) { document.removeEventListener('MSFullscreenChange', this.changeFullScreenStatus) } } } </script> <style lang="scss" scoped> .display-header{ height: 100%; display: flex; align-items: center; justify-content: space-between; padding: 0 30px; .title{ font-size: 60px; color: #fff; letter-spacing: .1em; } .sub{ 1000px; color: rgba(255,255,255,.3); } .full-screen{ cursor: pointer; position: relative; text-align: right; &:before{ content: ''; position: absolute; top: -20px; bottom: -20px; left: -20px; right: -20px; } } } </style>