From abc8c178e65d12f0b0a364817e93b1328ab3fdba Mon Sep 17 00:00:00 2001 From: toesbieya <1647775459@qq.com> Date: Sun, 6 Dec 2020 20:43:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=97=E8=A1=A8=E9=A1=B5?= =?UTF-8?q?=E8=87=AA=E9=80=82=E5=BA=94=E9=AB=98=E5=BA=A6=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 增加了背景动画:流光 --- vue/full/src/asset/style/index.scss | 63 ++++++++++++------ vue/full/src/asset/style/variables.scss | 8 ++- .../component/Page/component/PageFooter.vue | 3 +- .../component/Page/component/PageHeader.vue | 2 +- vue/full/src/layout/component/Page/index.vue | 6 +- .../canvasAnimation/fluxRay/Particle.js | 39 +++++++++++ .../plugin/canvasAnimation/fluxRay/index.js | 65 +++++++++++++++++++ .../plugin/canvasAnimation/godrays/index.js | 2 +- vue/full/src/view/_app/login/SetAnimation.vue | 1 + .../_common/ListPage/autoAdaptHeightMixin.js | 45 +++++++++---- 10 files changed, 196 insertions(+), 38 deletions(-) create mode 100644 vue/full/src/plugin/canvasAnimation/fluxRay/Particle.js create mode 100644 vue/full/src/plugin/canvasAnimation/fluxRay/index.js diff --git a/vue/full/src/asset/style/index.scss b/vue/full/src/asset/style/index.scss index 647415f..539d99c 100644 --- a/vue/full/src/asset/style/index.scss +++ b/vue/full/src/asset/style/index.scss @@ -7,6 +7,11 @@ @import "./transition"; @import "./nprogress"; +html { + height: 100%; + box-sizing: border-box; +} + body { height: 100%; -moz-osx-font-smoothing: grayscale; @@ -15,11 +20,6 @@ body { -webkit-tap-highlight-color: transparent; } -html { - height: 100%; - box-sizing: border-box; -} - #app { height: 100%; } @@ -82,39 +82,66 @@ a:hover { /*----------路由页面的最大高度开始----------*/ -$page-header-offsetHeight: $page-header-line-height + #{$page-view-margin * 2}; +//可能达到的最大高度 +$max-height: '100vh - #{$page-view-margin * 2}'; -.max-view-height.full { - height: 100vh; +.max-view-height { + max-height: calc(#{$max-height}); } -.max-view-height { - overflow-y: hidden; - max-height: calc(100vh - #{$page-view-margin * 2}); +//即使高度不够也占满 +.max-view-height.full { + height: 100vh; } +//有导航栏 .has-nav .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$nav-height}); + max-height: calc(#{$max-height} - #{$nav-height}); } +//有多页签栏 .has-tags-view .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$tags-view-height}); + max-height: calc(#{$max-height} - #{$tags-view-height}); } +//有页头 .has-page-header .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$page-header-offsetHeight}); + max-height: calc(#{$max-height} - #{$page-header-height}); } +//有页脚 +.has-page-footer .max-view-height { + max-height: calc(#{$max-height} - #{$page-footer-height}); +} + +//同时有导航栏和多页签栏 .has-nav.has-tags-view .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$nav-height} - #{$tags-view-height}); + max-height: calc(#{$max-height} - #{$nav-height} - #{$tags-view-height}); } +//同时有导航栏和页头 .has-nav .has-page-header .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$nav-height} - #{$page-header-offsetHeight}); + max-height: calc(#{$max-height} - #{$nav-height} - #{$page-header-height}); +} + +//同时有导航栏和页脚 +.has-nav .has-page-footer .max-view-height { + max-height: calc(#{$max-height} - #{$nav-height} - #{$page-footer-height}); } +//同时有导航栏、多页签栏、页头 .has-nav.has-tags-view .has-page-header .max-view-height { - max-height: calc(100vh - #{$page-view-margin * 2} - #{$nav-height} - #{$tags-view-height} - #{$page-header-offsetHeight}); + max-height: calc(#{$max-height} - #{$nav-height} - #{$tags-view-height} - #{$page-header-height}); +} + +//同时有导航栏、多页签栏、页脚 +.has-nav.has-tags-view .has-page-footer .max-view-height { + max-height: calc(#{$max-height} - #{$nav-height} - #{$tags-view-height} - #{$page-footer-height}); +} + +//同时有导航栏、多页签栏、页头、页脚 +.has-nav.has-tags-view .has-page-header.has-page-footer .max-view-height { + max-height: calc(#{$max-height} - #{$nav-height} - #{$tags-view-height} - #{$page-header-height} - #{$page-footer-height}); } /*----------路由页面的最大高度结束----------*/ @@ -226,5 +253,3 @@ $page-header-offsetHeight: $page-header-line-height + #{$page-view-margin * 2}; .el-table a { color: $--color-primary; } - - diff --git a/vue/full/src/asset/style/variables.scss b/vue/full/src/asset/style/variables.scss index 3d555c9..5e0d3fe 100644 --- a/vue/full/src/asset/style/variables.scss +++ b/vue/full/src/asset/style/variables.scss @@ -89,13 +89,17 @@ $navbar-item-hover-color-dark: lighten($root-menu-background-dark, 5%); //多页签栏高度 $tags-view-height: 32px; -//页头行高 -$page-header-line-height: 26px; +//页头高度,用于max-view-height +$page-header-height: 44px; //页头的上下padding $page-header-padding: 12px; + //路由页面的margin $page-view-margin: 24px; +//页脚高度,用于max-view-height +$page-footer-height: 64px; + //亮色边框的颜色,使用的element-ui原定义 $border-color-light: #dcdfe6; //暗色边框的颜色 diff --git a/vue/full/src/layout/component/Page/component/PageFooter.vue b/vue/full/src/layout/component/Page/component/PageFooter.vue index caf3a88..c7f596b 100644 --- a/vue/full/src/layout/component/Page/component/PageFooter.vue +++ b/vue/full/src/layout/component/Page/component/PageFooter.vue @@ -16,7 +16,8 @@ export default { @import "~@/asset/style/variables.scss"; .page-footer { - padding: 48px $page-view-margin $page-view-margin $page-view-margin; + height: $page-footer-height; + padding: $page-view-margin; text-align: center; .copyright { diff --git a/vue/full/src/layout/component/Page/component/PageHeader.vue b/vue/full/src/layout/component/Page/component/PageHeader.vue index c3a4bec..4af9c81 100644 --- a/vue/full/src/layout/component/Page/component/PageHeader.vue +++ b/vue/full/src/layout/component/Page/component/PageHeader.vue @@ -40,7 +40,7 @@ export default { align-items: center; flex-wrap: nowrap; font-size: 14px; - line-height: $page-header-line-height; + height: $page-header-height; padding: $page-header-padding $page-view-margin $page-header-padding $page-view-margin; > .el-breadcrumb .no-redirect { diff --git a/vue/full/src/layout/component/Page/index.vue b/vue/full/src/layout/component/Page/index.vue index c6d3f1e..032299f 100644 --- a/vue/full/src/layout/component/Page/index.vue +++ b/vue/full/src/layout/component/Page/index.vue @@ -17,7 +17,11 @@ export default { return pageGetters.showPageHeader && this.$route.meta.pageHeader !== false }, pageClass() { - return {'scroll-container': true, 'has-page-header': this.renderPageHeader} + return { + 'scroll-container': true, + 'has-page-header': this.renderPageHeader, + 'has-page-footer': true + } } }, diff --git a/vue/full/src/plugin/canvasAnimation/fluxRay/Particle.js b/vue/full/src/plugin/canvasAnimation/fluxRay/Particle.js new file mode 100644 index 0000000..496a85f --- /dev/null +++ b/vue/full/src/plugin/canvasAnimation/fluxRay/Particle.js @@ -0,0 +1,39 @@ +export default class Particle { + constructor(canvas, accel) { + this.init(canvas, accel) + } + + init(canvas, accel) { + this.x = Math.random() * canvas.width + this.y = Math.random() * canvas.height + this.vx = accel * (Math.random() - Math.random()) + this.vy = accel * (Math.random() - Math.random()) + } + + step(parent) { + // move towards every attractor + // at a speed inversely proportional to distance squared + // (much slower when further away, very fast when close) + for (const a of parent.attractors) { + // calculate the square of the distance + // from this particle to the current attractor + const dx = a.x - this.x + const dy = a.y - this.y + const d2 = dx * dx + dy * dy + if (d2 > 0.1) { + // make sure we don't divide by zero + // accelerate towards each attractor + this.vx += parent.accel * dx / d2 + this.vy += parent.accel * dy / d2 + } + } + // move by the velocity + this.x += this.vx + this.y += this.vy + // scale the velocity back for the next frame + this.vx *= parent.damp + this.vy *= parent.damp + // draw particle + parent.ctx.fillRect(this.x, this.y, 0.5, 0.5) + } +} diff --git a/vue/full/src/plugin/canvasAnimation/fluxRay/index.js b/vue/full/src/plugin/canvasAnimation/fluxRay/index.js new file mode 100644 index 0000000..b29e3ec --- /dev/null +++ b/vue/full/src/plugin/canvasAnimation/fluxRay/index.js @@ -0,0 +1,65 @@ +import Particle from './Particle' + +export default class FluxRay { + constructor(canvas) { + this.canvas = canvas + this.canvas.style.setProperty('background-color', 'black') + this.ctx = canvas.getContext('2d') + this.frame = 0 + this.damp = 0.00002 // remember a very small amount of the last direction + this.accel = 100 // move very quickly + this.attractors = Array.from({length: 8}, () => new Particle(canvas, this.accel)) + this.particles = Array.from({length: 1000}, () => new Particle(canvas, this.accel)) + this.rAF = null + this.stopSign = false + this.loop = this.loop.bind(this) + this.start() + } + + start() { + this.resizeObserver = new ResizeObserver(() => this.resize()) + this.resizeObserver.observe(this.canvas) + this.resize() + this.loop() + } + + stop() { + if (this.resizeObserver) { + this.resizeObserver.disconnect() + this.resizeObserver = null + } + this.stopSign = true + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + this.canvas.style.removeProperty('background-color') + } + + loop() { + if (this.stopSign) { + this.rAF && window.cancelAnimationFrame(this.rAF) + return + } + this.draw() + this.rAF = window.requestAnimationFrame(this.loop) + } + + draw() { + if (this.frame++ < 1000) { + this.particles.forEach(p => p.step(this)) + } + } + + reset() { + this.ctx.globalCompositeOperation = "source-over" + this.ctx.fillStyle = "#321" + this.ctx.globalCompositeOperation = "lighter" + this.particles.forEach(p => p.init(this.canvas, this.accel)) + this.attractors.forEach(a => a.init(this.canvas, this.accel)) + this.frame = 0 + } + + resize() { + this.canvas.width = window.innerWidth + this.canvas.height = window.innerHeight + this.reset() + } +} diff --git a/vue/full/src/plugin/canvasAnimation/godrays/index.js b/vue/full/src/plugin/canvasAnimation/godrays/index.js index c956f2b..5ad205b 100644 --- a/vue/full/src/plugin/canvasAnimation/godrays/index.js +++ b/vue/full/src/plugin/canvasAnimation/godrays/index.js @@ -1,5 +1,5 @@ function mountainHeight(position, roughness) { - let frequencies = [1721, 947, 547, 233, 73, 31, 7] + const frequencies = [1721, 947, 547, 233, 73, 31, 7] return frequencies.reduce((height, freq) => height * roughness - Math.cos(freq * position), 0) } diff --git a/vue/full/src/view/_app/login/SetAnimation.vue b/vue/full/src/view/_app/login/SetAnimation.vue index e298836..474a70a 100644 --- a/vue/full/src/view/_app/login/SetAnimation.vue +++ b/vue/full/src/view/_app/login/SetAnimation.vue @@ -10,6 +10,7 @@ const animations = [ {name: '雨', value: 'reflectRain'}, {name: '流星雨', value: 'sparkRain'}, {name: '阳光', value: 'sunlight'}, + {name: '流光', value: 'fluxRay'}, ] export default { diff --git a/vue/full/src/view/_common/ListPage/autoAdaptHeightMixin.js b/vue/full/src/view/_common/ListPage/autoAdaptHeightMixin.js index db040c9..3c37711 100644 --- a/vue/full/src/view/_common/ListPage/autoAdaptHeightMixin.js +++ b/vue/full/src/view/_common/ListPage/autoAdaptHeightMixin.js @@ -3,44 +3,64 @@ * 监听el-table,动态设置max-height属性 */ -import cssVariables from "@/asset/style/variables.scss" -import {debounce} from "@/util" +import {findComponentByTag} from "@/util/vue" export default { data() { return { + //el-table的max-height属性 tableMaxHeight: undefined, - desiredDistance: undefined + //上一次的maxHeight,解决resize时表格高度不正确 + lastTableMaxHeight: undefined, + + //表格距离卡片容器底部的理想距离 + expectedDistance: undefined } }, methods: { - //设置表格距离视窗底部的理想距离(分页高度 + el-card的1px边距 + el-card padding + 页面margin) - calcDesiredDistance() { - const pageViewMargin = parseFloat(cssVariables.pageViewMargin) + //设置表格距离卡片容器底部的理想距离(分页高度 + el-card的1px边距 + el-card padding + 页面margin) + calcExpectedDistance() { const paginationHeight = this.$el.querySelector('.table-container > .el-pagination') ? 50 : 0 - this.desiredDistance = paginationHeight + 1 + 20 + pageViewMargin + this.expectedDistance = paginationHeight + 1 + 20 }, resize() { const clientHeight = window.innerHeight + //计算卡片容器底部距离视窗底部的距离 + const containerRect = this.$el.getBoundingClientRect() + const containerDistance = clientHeight - containerRect.top - containerRect.height + //计算表格底部距离视窗底部的距离 const tableRect = this.$refs.table.$el.getBoundingClientRect() - const distance = clientHeight - tableRect.top - tableRect.height + const tableDistance = clientHeight - tableRect.top - tableRect.height - if (this.desiredDistance === undefined) { - this.calcDesiredDistance() + if (this.expectedDistance === undefined) { + this.calcExpectedDistance() } - const overHeight = this.desiredDistance - distance - this.tableMaxHeight = tableRect.height - overHeight + const overHeight = containerDistance + this.expectedDistance - tableDistance + + //overHeight为0说明表格刚好在卡片容器内 + if (overHeight === 0) { + this.tableMaxHeight = this.lastTableMaxHeight + } + else { + this.lastTableMaxHeight = this.tableMaxHeight + this.tableMaxHeight = tableRect.height - overHeight + } }, + createResizeObserver() { if (this.resizeObserver) return this.resizeObserver = new ResizeObserver(this.resize) this.resizeObserver.observe(this.$el) + const searchFormInstance = findComponentByTag(this, 'search-form') + if (searchFormInstance) { + this.resizeObserver.observe(searchFormInstance.$el) + } this.$once('hook:beforeDestroy', () => { this.resizeObserver && this.resizeObserver.disconnect() @@ -49,7 +69,6 @@ export default { }, mounted() { - this.resize = debounce(this.resize, 300) this.createResizeObserver() } }