模仿CSDN黑暗帝国动态背景的vue项目(附源码)

时间:2022-11-10 07:54:44

开发工具:Webstorm
技术栈:vue、html、canvas
实现效果(其实这里面的是动态变换的,只是没有截成GIF动图):模仿CSDN黑暗帝国动态背景的vue项目(附源码)
实现步骤:
(1)在这里的项目我是用VueCli3脚手架进行搭建的。
(2)关于动态背景的源码则是在github找的源码。
(3)总体是在App.vue中进行背景的添加
(4)因为在这里是在App.vue中添加的,所以在这里给出了不想以这种动态背景为背景的解决方案。
(5)在最后我会附上源码
(6)因为这个是我用来练手的,所以只有前台页面,而且很多不完善,但是大家可以借鉴一下这个代码,然后在这个基础上大家可以*发挥。如果大家想下载源码文件的话。
需要注意,因为我在登陆的时候与后端进行了交互,大家可以改一下Login.vue的登录的代码即可,修改成直接跳转就可以,因为时间关系,在这里我就不一一阐述了。

1、黑客帝国实现源码:

(1)大家可以创建一个vue文件,将其复制进去即可,给大家贴一个结构目录。

模仿CSDN黑暗帝国动态背景的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>

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>

3、但是如果是后台文件不想以这种动态背景为背景,那怎么办呢?

在这里主要借助z-index属性进行解决。在这里我主要以后台的管理页面为例子,来简单说明一下。

模仿CSDN黑暗帝国动态背景的vue项目(附源码)

效果实现(可以自定义背景):

模仿CSDN黑暗帝国动态背景的vue项目(附源码)
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>

在这里我将这个练习源码上传到CSDN(不需要积分),大家可以下载下来有时间实现一下。
https://download.csdn.net/download/weixin_43388691/86932762