利用canvas制作背景动画(1)

效果图
在这里插入图片描述
在这里插入图片描述
html代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      .login-canvas {
        top: 0;
        position: absolute;
        width: 100%;
        height: 100%;
        opacity: 0.45;
      }
    </style>
  </head>
  <body>
    <canvas id="canvas" class="login-canvas" />

    <script>
      var canvas = window.document.getElementById("canvas");
      var ctx = canvas.getContext("2d");

      var squids = new Array(30);
      var bubbles = new Array(50);
      var t = 0;
      var colors = new Array(6);
      var step = 0;
      var colorIndices = [0, 1, 2, 3];
      var gradientSpeed = 0.01;
      var codeUrl = "";
      var cookiePassword = "";

      initCanvas();
      moving();

      function moving() {
        setInterval(() => {
          animate();
          updateGradient();
        }, 10);
      }

      function initCanvas() {
        // create squids
        for (let i = 0; i < squids.length; i++) {
          const s = 20;
          const e = 160;
          squids[i] = {
            re: s + Math.random() * e,
            g: s + Math.random() * e,
            b: s + Math.random() * e,
            x: Math.random() * innerWidth,
            y: Math.random() * innerHeight,
            vx: (0.5 - Math.random()) / 4,
            vy: 0.1 - Math.random(),
            r: 10 + Math.random() * 40,
            a: [],
          };
        }
        // create bubbles
        for (var j = 0; j < bubbles.length; j++) {
          bubbles[j] = {
            x: Math.random() * innerWidth,
            y: Math.random() * innerHeight,
            vx: 0.5 - Math.random(),
            vy: -0.2 - Math.random(),
            o: 0.05 + Math.random() * 0.1,
            r: 3 + Math.random() * 20,
          };
        }
        colors[0] = [62, 35, 255];
        colors[1] = [60, 255, 60];
        colors[2] = [255, 35, 98];
        colors[3] = [45, 175, 230];
        colors[4] = [255, 0, 255];
        colors[5] = [255, 128, 0];
      }

      function animate() {
        t++;
        canvas.width = innerWidth;
        canvas.height = innerHeight;
        // const that = this;
        bubbles.forEach((b) => {
          b.x += b.vx;
          b.y += b.vy;
          limitRang(b);
          ctx.fillStyle = "rgba(255,255,255," + b.o + ")";
          ctx.beginPath();
          ctx.arc(b.x, b.y, b.r, Math.PI * 2, 0);
          ctx.fill();
        });
        squids.forEach((d) => {
          var w = Math.sin((t + d.r * 100) / 10);
          d.x += d.vx * 4;
          d.y -= w + 1;
          d.y += d.vy;
          limitRang(d);
          var color1 = "rgba(" + d.re + "," + d.g + "," + d.b + ",0.4)";
          var color2 = "rgba(" + d.re + "," + d.g + "," + d.b + ",0.2)";
          ctx.fillStyle = color1;
          ctx.beginPath();
          ctx.arc(
            d.x,
            d.y,
            d.r,
            Math.PI + (-0.5 + d.vx) - w / 4,
            0.5 + d.vx + w / 4
          );
          ctx.fill();
          d.a.push({ x: d.x, y: d.y - d.r * 0.2 });
          if (d.a.length > d.r * 3) d.a.splice(0, 1);
          d.a.forEach((p, i) => {
            ctx.fillStyle = color2;
            ctx.fillRect(p.x, p.y, 2, 2);
            if (i > d.a.length / 2) {
              ctx.fillRect(p.x - d.r / 4, p.y, 2, 2);
              ctx.fillRect(p.x + d.r / 4, p.y, 2, 2);
            }
            if (i > d.a.length / 3) {
              ctx.fillRect(p.x + d.r / 10, p.y - 10, 2, 2);
              ctx.fillRect(p.x - d.r / 10, p.y - 10, 2, 2);
            }
          });
        });
      }

      function limitRang(d) {
        if (d.x < -d.r) d.x = innerWidth + d.r;
        if (d.x > innerWidth + d.r) d.x = -d.r;
        if (d.y < -d.r) d.y = innerHeight + d.r;
        if (d.y > innerHeight + d.r) d.y = -d.r;
      }

      function updateGradient() {
        var c = colors[colorIndices[0]];
        var d = colors[colorIndices[1]];
        var e = colors[colorIndices[2]];
        var f = colors[colorIndices[3]];
        var k = 1 - step;
        var l = Math.round(k * c[0] + step * d[0]);
        var i = Math.round(k * c[1] + step * d[1]);
        var a = Math.round(k * c[2] + step * d[2]);
        var g = "rgb(" + l + "," + i + "," + a + ")";
        var m = Math.round(k * e[0] + step * f[0]);
        var j = Math.round(k * e[1] + step * f[1]);
        var b = Math.round(k * e[2] + step * f[2]);
        var h = "rgb(" + m + "," + j + "," + b + ")";
        if (canvas) {
          canvas.style.background =
            "-webkit-gradient(linear, left top, right top, from(" +
            g +
            "), to(" +
            h +
            "))";
          canvas.style.background =
            "-moz-linear-gradient(left, " + g + " 0%, " + h + " 100%)";
        }
        step += gradientSpeed;
        if (step >= 1) {
          step %= 1;
          colorIndices[0] = colorIndices[1];
          colorIndices[2] = colorIndices[3];
          colorIndices[1] =
            (colorIndices[1] +
              Math.floor(1 + Math.random() * (colors.length - 1))) %
            colors.length;
          colorIndices[3] =
            (colorIndices[3] +
              Math.floor(1 + Math.random() * (colors.length - 1))) %
            colors.length;
        }
      }
    </script>
  </body>
</html>

vue写法,多余变量和样式可自行去除

<template>
  <div class="login">
    <canvas id="canvas" ref="canvas" class="login-canvas" />
    <el-form
      ref="loginForm"
      :model="loginForm"
      :rules="loginRules"
      class="login-form"
    >
      <h3 class="title">XXXX平台</h3>
      <el-form-item prop="username">
        <el-input
          v-model="loginForm.username"
          type="text"
          auto-complete="off"
          placeholder="账号"
        >
          <svg-icon
            slot="prefix"
            icon-class="user"
            class="el-input__icon input-icon"
          />
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          v-model="loginForm.password"
          type="password"
          auto-complete="off"
          placeholder="密码"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon
            slot="prefix"
            icon-class="password"
            class="el-input__icon input-icon"
          />
        </el-input>
      </el-form-item>
      <el-form-item prop="code">
        <el-input
          v-model="loginForm.code"
          auto-complete="off"
          placeholder="验证码"
          style="width: 63%"
          @keyup.enter.native="handleLogin"
        >
          <svg-icon
            slot="prefix"
            icon-class="validCode"
            class="el-input__icon input-icon"
          />
        </el-input>
        <div class="login-code">
          <img :src="codeUrl" @click="getCode" />
        </div>
      </el-form-item>
      <el-checkbox
        v-model="loginForm.rememberMe"
        style="margin:0px 0px 25px 0px;"
        >记住密码</el-checkbox
      >
      <router-link target="_blank" class="box medium-a" to="/merchantReg"
        >helloworld</router-link
      >
      <el-form-item style="width:100%;">
        <el-button
          :loading="loading"
          size="medium"
          type="primary"
          style="width:100%;"
          @click.native.prevent="handleLogin"
        >
          <span v-if="!loading">登 录</span>
          <span v-else>登 录 中...</span>
        </el-button>
      </el-form-item>
    </el-form>
    <!--  底部  -->
    <div class="el-login-footer">
      <!-- <span>Copyright © 2020-2021 xxx版权所有.</span> -->
    </div>
  </div>
</template>
<style>
.box {
  color: #f30;
  animation: changeshadow 1s ease-in infinite;
  -webkit-animation: changeshadow 1s linear infinite;
  -moz-animation: changeshadow 1s linear infinite;
  -ms-animation: changeshadow 1s linear infinite;
  -o-animation: changeshadow 1s linear infinite;
}

.medium-a {
  float: right;
  border: 0;
  font-size: 15px;
  text-decoration: underline;
}
.medium-a:hover {
  text-decoration: underline;
  color: #1890ff;
}
</style>
<script>
import { getCodeImg } from '@/api/login';
import Cookies from 'js-cookie';

export default {
  name: 'Login',
  data() {
    return {
      ctx: {},
      canvas: undefined,
      squids: new Array(30),
      bubbles: new Array(50),
      t: 0,
      colors: new Array(6),
      step: 0,
      colorIndices: [0, 1, 2, 3],
      gradientSpeed: 0.01,
      codeUrl: '',
      cookiePassword: '',
      loginForm: {
        username: '',
        password: '',
        rememberMe: false,
        code: '',
        uuid: ''
      },
      loginRules: {
        username: [
          { required: true, trigger: 'blur', message: '用户名不能为空' }
        ],
        password: [
          { required: true, trigger: 'blur', message: '密码不能为空' }
        ],
        code: [{ required: true, trigger: 'change', message: '验证码不能为空' }]
      },
      loading: false,
      redirect: undefined
    };
  },
  watch: {
    $route: {
      handler: function(route) {
        this.redirect = route.query && route.query.redirect;
      },
      immediate: true
    }
  },
  created() {
    this.getCode();
    this.getCookie();
  },
  mounted() {
    this.canvas = window.document.getElementById('canvas');
    this.ctx = this.canvas.getContext('2d');
    this.initCanvas();
    this.moving();
  },
  methods: {
    initCanvas() {
      // create squids
      for (let i = 0; i < this.squids.length; i++) {
        const s = 20;
        const e = 160;
        this.squids[i] = {
          re: s + Math.random() * e,
          g: s + Math.random() * e,
          b: s + Math.random() * e,
          x: Math.random() * innerWidth,
          y: Math.random() * innerHeight,
          vx: (0.5 - Math.random()) / 4,
          vy: 0.1 - Math.random(),
          r: 10 + Math.random() * 40,
          a: []
        };
      }
      // create bubbles
      for (var j = 0; j < this.bubbles.length; j++) {
        this.bubbles[j] = {
          x: Math.random() * innerWidth,
          y: Math.random() * innerHeight,
          vx: 0.5 - Math.random(),
          vy: -0.2 - Math.random(),
          o: 0.05 + Math.random() * 0.1,
          r: 3 + Math.random() * 20
        };
      }
      this.colors[0] = [62, 35, 255];
      this.colors[1] = [60, 255, 60];
      this.colors[2] = [255, 35, 98];
      this.colors[3] = [45, 175, 230];
      this.colors[4] = [255, 0, 255];
      this.colors[5] = [255, 128, 0];
    },
    limitRang(d) {
      if (d.x < -d.r) d.x = innerWidth + d.r;
      if (d.x > innerWidth + d.r) d.x = -d.r;
      if (d.y < -d.r) d.y = innerHeight + d.r;
      if (d.y > innerHeight + d.r) d.y = -d.r;
    },
    async moving() {
      setInterval(() => {
        this.animate();
        this.updateGradient();
      }, 10);
    },
    animate() {
      this.t++;
      this.canvas.width = innerWidth;
      this.canvas.height = innerHeight;
      const that = this;
      this.bubbles.forEach(function(b) {
        b.x += b.vx;
        b.y += b.vy;
        that.limitRang(b);
        that.ctx.fillStyle = 'rgba(255,255,255,' + b.o + ')';
        that.ctx.beginPath();
        that.ctx.arc(b.x, b.y, b.r, Math.PI * 2, 0);
        that.ctx.fill();
      });
      this.squids.forEach(function(d) {
        var w = Math.sin((that.t + d.r * 100) / 10);
        d.x += d.vx * 4;
        d.y -= w + 1;
        d.y += d.vy;
        that.limitRang(d);
        var color1 = 'rgba(' + d.re + ',' + d.g + ',' + d.b + ',0.4)';
        var color2 = 'rgba(' + d.re + ',' + d.g + ',' + d.b + ',0.2)';
        that.ctx.fillStyle = color1;
        that.ctx.beginPath();
        that.ctx.arc(
          d.x,
          d.y,
          d.r,
          Math.PI + (-0.5 + d.vx) - w / 4,
          0.5 + d.vx + w / 4
        );
        that.ctx.fill();
        d.a.push({ x: d.x, y: d.y - d.r * 0.2 });
        if (d.a.length > d.r * 3) d.a.splice(0, 1);
        d.a.forEach(function(p, i) {
          that.ctx.fillStyle = color2;
          that.ctx.fillRect(p.x, p.y, 2, 2);
          if (i > d.a.length / 2) {
            that.ctx.fillRect(p.x - d.r / 4, p.y, 2, 2);
            that.ctx.fillRect(p.x + d.r / 4, p.y, 2, 2);
          }
          if (i > d.a.length / 3) {
            that.ctx.fillRect(p.x + d.r / 10, p.y - 10, 2, 2);
            that.ctx.fillRect(p.x - d.r / 10, p.y - 10, 2, 2);
          }
        });
      });
    },
    updateGradient() {
      var c = this.colors[this.colorIndices[0]];
      var d = this.colors[this.colorIndices[1]];
      var e = this.colors[this.colorIndices[2]];
      var f = this.colors[this.colorIndices[3]];
      var k = 1 - this.step;
      var l = Math.round(k * c[0] + this.step * d[0]);
      var i = Math.round(k * c[1] + this.step * d[1]);
      var a = Math.round(k * c[2] + this.step * d[2]);
      var g = 'rgb(' + l + ',' + i + ',' + a + ')';
      var m = Math.round(k * e[0] + this.step * f[0]);
      var j = Math.round(k * e[1] + this.step * f[1]);
      var b = Math.round(k * e[2] + this.step * f[2]);
      var h = 'rgb(' + m + ',' + j + ',' + b + ')';
      if (this.canvas) {
        this.canvas.style.background =
          '-webkit-gradient(linear, left top, right top, from(' +
          g +
          '), to(' +
          h +
          '))';
        this.canvas.style.background =
          '-moz-linear-gradient(left, ' + g + ' 0%, ' + h + ' 100%)';
      }
      this.step += this.gradientSpeed;
      if (this.step >= 1) {
        this.step %= 1;
        this.colorIndices[0] = this.colorIndices[1];
        this.colorIndices[2] = this.colorIndices[3];
        this.colorIndices[1] =
          (this.colorIndices[1] +
            Math.floor(1 + Math.random() * (this.colors.length - 1))) %
          this.colors.length;
        this.colorIndices[3] =
          (this.colorIndices[3] +
            Math.floor(1 + Math.random() * (this.colors.length - 1))) %
          this.colors.length;
      }
    },
    getCode() {
      getCodeImg().then(res => {
        this.codeUrl = 'data:image/gif;base64,' + res.data.data.img;
        this.loginForm.uuid = res.data.data.uuid;
      });
    },
    getCookie() {
      const username = Cookies.get('username');
      const password = Cookies.get('password');
      const rememberMe = Cookies.get('rememberMe');
      this.loginForm = {
        username: username === undefined ? this.loginForm.username : username,
        password: password === undefined ? this.loginForm.password : password,
        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
      };
    },
    handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true;
          if (this.loginForm.rememberMe) {
            Cookies.set('username', this.loginForm.username, { expires: 30 });
            Cookies.set('password', this.loginForm.password, { expires: 30 });
            Cookies.set('rememberMe', this.loginForm.rememberMe, {
              expires: 30
            });
          } else {
            Cookies.remove('username');
            Cookies.remove('password');
            Cookies.remove('rememberMe');
          }
          this.$store
            .dispatch('LoginByUsername', this.loginForm)
            .then(isImproved => {
              this.loading = false;
              if (isImproved === true) {
                this.$router.push({ path: this.redirect || '/' });
              } else {
                // 品牌信息为完善 先完善信息
                this.$router.push({ path: '/brandInfo' || '/' });
              }
            })
            .catch(response => {
              this.$notify.error({
                title: '失败',
                message: response.data.errmsg
              });
              this.loading = false;
              this.getCode();
            });
        }
      });
    }
  }
};
</script>

<style rel="stylesheet/scss" lang="scss">
.login-canvas {
  top: 0;
  position: absolute;
  width: 100%;
  height: 100%;
  opacity: 0.45;
}

.login {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  background-size: cover;
}
.title {
  margin: 0px auto 30px auto;
  text-align: center;
  color: #707070;
}

.login-form {
  z-index: 999;
  border-radius: 6px;
  background: #ffffff;
  opacity: 0.65;
  width: 400px;
  padding: 25px 25px 5px 25px;
  .el-input {
    height: 38px;
    input {
      height: 38px;
    }
  }
  .input-icon {
    height: 39px;
    width: 14px;
    margin-left: 2px;
  }
}
.login-tip {
  font-size: 13px;
  text-align: center;
  color: #bfbfbf;
}
.login-code {
  width: 33%;
  height: 38px;
  float: right;
  img {
    cursor: pointer;
    vertical-align: middle;
  }
}
.el-login-footer {
  height: 40px;
  line-height: 40px;
  position: fixed;
  bottom: 0;
  width: 100%;
  text-align: center;
  color: #fff;
  font-family: Arial;
  font-size: 12px;
  letter-spacing: 1px;
  z-index: 999;
}
</style>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C+ 安口木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值