开发工具:Webstorm
技术栈:vue、html、canvas
实现效果(定制小程序开发费用其实这里面的是动态变换的,定制小程序开发费用只是没有截成GIF动图):
实现步骤:
(1)定制小程序开发费用在这里的项目我是用VueCli3定制小程序开发费用脚手架进行搭建的。
(2)关于动态背景的源码则是在github找的源码。
(3)总体是在App.vue中进行背景的添加
(4)因为在这里是在App.vue中添加的,所以在这里给出了不想以这种动态背景为背景的解决方案。
(5)在最后我会附上源码
(6)因为这个是我用来练手的,所以只有前台页面,而且很多不完善,但是大家可以借鉴一下这个代码,然后在这个基础上大家可以自由发挥。如果大家想下载源码文件的话。
需要注意,因为我在登陆的时候与后端进行了交互,大家可以改一下Login.vue的登录的代码即可,修改成直接跳转就可以,因为时间关系,在这里我就不一一阐述了。
1、黑客帝国实现源码:
(1)大家可以创建一个vue文件,将其复制进去即可,给大家贴一个结构目录。
<template> <div class="main"> <canvas id="vue-matrix-raindrop"></canvas> </div></template><script> export default { name: 'vue-matrix-raindrop', props:{ canvasWidth:{ type:Number, default:1900 }, canvasHeight:{ type:Number, default:1200 }, fontSize:{ type:Number, default:20 }, fontFamily:{ type:String, default:'arial' }, textContent:{ type:String, default:'abcdefghijklmnopqrstuvwxyz' }, textColor:{ type:String, default:'#0F0', validator:function(value){ var colorReg = /^#([0-9a-fA-F]{6})|([0-9a-fA-F]{3})$/g return colorReg.test(value) } }, backgroundColor:{ type:String, default:'rgba(0,0,0,0.1)', validator:function(value){ var reg = /^[rR][gG][Bb][Aa][\(]((2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?),){2}(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?),?(0\.\d{1,2}|1|0)?[\)]{1}$/; return reg.test(value); } }, speed:{ type:Number, default:2, validator:function(value){ return value%1 === 0; } } }, mounted:function(){ this.initRAF(); this.initCanvas(); this.initRainDrop(); this.animationUpdate(); }, methods:{ initRAF(){ window.requestAnimationFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; })(); window.cancelAnimationFrame = (function () { return window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || function (id) { window.clearTimeout(id); }; })(); }, initCanvas(){ this.canvas = document.getElementById('vue-matrix-raindrop'); //需要判断获取到的canvas是否是真的canvas if(this.canvas.tagName.toLowerCase() !== 'canvas'){ console.error("Error! Invalid canvas! Please check the canvas's id!") } this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight; console.log(this.canvas.height ) this.canvasCtx = this.canvas.getContext('2d'); this.canvasCtx.font = this.fontSize+'px '+this.fontFamily; this.columns = this.canvas.width / this.fontSize; }, initRainDrop(){ for(var i=0;i<this.columns;i++){ this.rainDropPositionArray.push(0); } }, animationUpdate(){ this.speedCnt++; //speed为1最快,越大越慢 if(this.speedCnt===this.speed){ this.speedCnt = 0; //绘制背景 this.canvasCtx.fillStyle=this.backgroundColor; this.canvasCtx.fillRect(0,0,this.canvas.width,this.canvas.height); //绘制文字 this.canvasCtx.fillStyle=this.textColor; for(var i=0,len=this.rainDropPositionArray.length;i<len;i++){ this.rainDropPositionArray[i]++; var randomTextIndex = Math.floor(Math.random()*this.textContent.length); var randomText = this.textContent[randomTextIndex]; var textYPostion = this.rainDropPositionArray[i]*this.fontSize; this.canvasCtx.fillText(randomText,i*this.fontSize,textYPostion); if(textYPostion>this.canvasHeight){ if(Math.random()>0.9){ this.rainDropPositionArray[i]=0; } } } } window.requestAnimationFrame(this.animationUpdate) } }, data () { return { canvasCtx:null, canvas:null, columns:0, rainDropPositionArray:[], speedCnt:0 } } }</script><!-- Add "scoped" attribute to limit CSS to this component only --><style scoped> canvas { position: absolute; } .component{ position: absolute; width: 100%; height: 100%; z-index: 1; } .userName { position: absolute; top: 40%; left: 20%; }</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
2、对于App.vue文件中的修改:
(1)注意上一个特效文件的路径的修改。
<template> <div id="app" style="width: 100%;height:100%"> <VueMatrixRaindrop></VueMatrixRaindrop> <keep-alive> <router-view></router-view> </keep-alive> </div></template><script>//这里根据自己的前面的特效vue项目的具体目录合理选择import VueMatrixRaindrop from './views/vue-matrix-digit-rain'export default { name: 'app', components: { VueMatrixRaindrop, }, methods:{ }}</script>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
3、但是如果是后台文件不想以这种动态背景为背景,那怎么办呢?
在这里主要借助z-index属性进行解决。在这里我主要以后台的管理页面为例子,来简单说明一下。
效果实现(可以自定义背景):
copyMenu.vue 代码实现:
<template> <el-container class="home-container"> <!-- 头部区域 --> <el-header> <div> <div class="home"> <img src="../assets/logo.png" alt="" /> </div> <span>电商后台管理系统</span> </div> <el-button type="info" @click="logout">退出</el-button> </el-header> <!-- 页面主体区域 --> <el-container> <!-- 侧边栏 --> <el-aside :width="isCollapse ? '64px' : '200px'"> <div class="toggle-button" @click="toggleCollapse">|||</div> <!-- 侧边栏菜单区域 --> <el-menu background-color="#333744" text-color="#fff" active-text-color="#409EFF" unique-opened :collapse="isCollapse" :collapse-transition="false" router :default-active="activePath"> <!-- 一级菜单 --> <el-submenu :index="item.id + ''" v-for="item in menulist" :key="item.id"> <!-- 一级菜单的模板区域 --> <template slot="title"> <!-- 图标 --> <i :class="iconsObj[item.id]"></i> <!-- 文本 --> <span>{{ item.authName }}</span> </template> <!-- 二级菜单 --> <el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children" :key="subItem.id" @click="saveNavState('/' + subItem.path)"> <template slot="title"> <!-- 图标 --> <i class="el-icon-menu"></i> <!-- 文本 --> <span>{{ subItem.authName }}</span> </template> </el-menu-item> </el-submenu> </el-menu> </el-aside> <!-- 右侧内容主体 --> <el-main> <!-- 路由占位符 --> <router-view></router-view> </el-main> </el-container> </el-container></template><script> export default { name: "copy-menu", data() { return { // 左侧菜单数据 menulist: [], iconsObj: { '125': 'iconfont icon-user', '103': 'iconfont icon-tijikongjian', '101': 'iconfont icon-shangpin', '102': 'iconfont icon-danju', '145': 'iconfont icon-baobiao' }, // 是否折叠 isCollapse: false, // 被激活的链接地址 activePath: '' } }, created() { this.getMenuList() this.activePath = window.sessionStorage.getItem('activePath') }, methods: { logout() { window.sessionStorage.clear() this.$router.push('/login') }, // 获取所有的菜单 getMenuList() { console.log("测试") //const router = useRouter() var bmenus = [ { "id": 125, "authName": "用户管理", "path": "users", "children": [ { "id": 110, "authName": "用户列表", "path": "user", "children": [], "order": null }, { "id": 210, "authName": "异步状态", "path": "netTick", "children": [], "order": null }, { "id": 211, "authName": "表格测试", "path": "table", "children": [], "order": null } ], "order": 1 }, { "id": 103, "authName": "权限管理", "path": "rights", "children": [ { "id": 111, "authName": "角色列表", "path": "roles", "children": [], "order": null }, { "id": 112, "authName": "权限列表", "path": "rights", "children": [], "order": null } ], "order": 2 }, { "id": 101, "authName": "商品管理", "path": "goods", "children": [ { "id": 104, "authName": "商品列表", "path": "goods", "children": [], "order": 1 }, { "id": 115, "authName": "分类参数", "path": "params", "children": [], "order": 2 }, { "id": 121, "authName": "商品分类", "path": "categories", "children": [], "order": 3 } ], "order": 3 }, { "id": 102, "authName": "订单管理", "path": "orders", "children": [ { "id": 107, "authName": "订单列表", "path": "orders", "children": [], "order": null } ], "order": 4 }, { "id": 145, "authName": "数据统计", "path": "reports", "children": [ { "id": 146, "authName": "数据报表", "path": "reports", "children": [], "order": null } ], "order": 5 } ]; this.menulist = bmenus; //const { data: res } = await this.$http.get('menus') //if (res.meta.status !== 200) return this.$message.error(res.meta.msg) //this.menulist = res.data //console.log(res) }, // 点击按钮,切换菜单的折叠与展开 toggleCollapse() { this.isCollapse = !this.isCollapse }, // 保存链接的激活状态 saveNavState(activePath) { window.sessionStorage.setItem('activePath', activePath) this.activePath = activePath } } }</script><style lang="less" scoped> .outLine{ width: 100%; height: 100%; z-index: 1; } .home-container { height: 100%; width: 100%; z-index: 1; } .el-header { z-index: 1; background-color: #4a5064; display: flex; justify-content: space-between; padding-left: 0; align-items: center; color: #fff; font-size: 20px; > div { display: flex; align-items: center; span { margin-left: 15px; } } } .el-aside { z-index: 1; background-color: #333744; .el-menu { border-right: none; } } .el-main { z-index: 1; background-color: #eaedf1; } .iconfont { margin-right: 10px; } .toggle-button { background-color: #4a5064; font-size: 10px; line-height: 24px; color: #fff; text-align: center; letter-spacing: 0.2em; cursor: pointer; } .home{ width:60px; height: 60px; img{ width:100%; height: 100%; } }</style>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
在这里我将这个练习源码上传到CSDN(不需要积分),大家可以下载下来有时间实现一下。
https://download.csdn.net/download/weixin_43388691/86932762