首页 > 其他分享 >vue3 登录添加图形验证码

vue3 登录添加图形验证码

时间:2023-07-20 18:12:02浏览次数:33  
标签:const 登录 props ctx Number randomNum 验证码 let vue3

1. 新增组件 IdentifyCode.vue ,使用canvas绘制验证码内容:

<template>
  <div class="s-canvas" @click="refreshCode">
    <canvas
      id="s-canvas"
      :width="contentWidth"
      :height="contentHeight"
    ></canvas>
  </div>
</template>
<script setup>
import { ref, onMounted, watch } from "vue";

let curIdentifyCode = ref("");

const props = defineProps({
  identifyCode: {
    type: String,
    default: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  },
  fontSizeMin: {
    type: Number,
    default: 16,
  },
  fontSizeMax: {
    type: Number,
    default: 40,
  },
  backgroundColorMin: {
    type: Number,
    default: 180,
  },
  backgroundColorMax: {
    type: Number,
    default: 240,
  },
  colorMin: {
    type: Number,
    default: 50,
  },
  colorMax: {
    type: Number,
    default: 160,
  },
  lineColorMin: {
    type: Number,
    default: 40,
  },
  lineColorMax: {
    type: Number,
    default: 180,
  },
  dotColorMin: {
    type: Number,
    default: 0,
  },
  dotColorMax: {
    type: Number,
    default: 255,
  },
  contentWidth: {
    type: Number,
    default: 112,
  },
  contentHeight: {
    type: Number,
    default: 38,
  },
});

watch(curIdentifyCode, () => {
  drawPic();
});

const emit = defineEmits(["updateIdentifyCode"]);

// 生成一个随机数
const randomNum = (min, max) => {
  return Math.floor(Math.random() * (max - min) + min);
};
// 生成一个随机的颜色
const randomColor = (min, max) => {
  let r = randomNum(min, max);
  let g = randomNum(min, max);
  let b = randomNum(min, max);
  return "rgb(" + r + "," + g + "," + b + ")";
};
const drawPic = () => {
  let canvas = document.getElementById("s-canvas");
  let ctx = canvas.getContext("2d");
  ctx.textBaseline = "bottom";
  // 绘制背景
  ctx.fillStyle = randomColor(
    props.backgroundColorMin,
    props.backgroundColorMax
  );
  ctx.fillRect(0, 0, props.contentWidth, props.contentHeight);
  // 绘制文字
  for (let i = 0; i < curIdentifyCode.value.length; i++) {
    drawText(ctx, curIdentifyCode.value[i], i);
  }
  drawLine(ctx);
  drawDot(ctx);
};
const drawText = (ctx, txt, i) => {
  ctx.fillStyle = randomColor(props.colorMin, props.colorMax);
  ctx.font = randomNum(props.fontSizeMin, props.fontSizeMax) + "px SimHei";
  let x = (i + 1) * (props.contentWidth / (curIdentifyCode.value.length + 1));
  let y = randomNum(props.fontSizeMax, props.contentHeight - 5);
  let deg = randomNum(-45, 45);
  // 修改坐标原点和旋转角度
  ctx.translate(x, y);
  ctx.rotate((deg * Math.PI) / 180);
  ctx.fillText(txt, 0, 0);
  // 恢复坐标原点和旋转角度
  ctx.rotate((-deg * Math.PI) / 180);
  ctx.translate(-x, -y);
};
const drawLine = (ctx) => {
  // 绘制干扰线
  for (let i = 0; i < 8; i++) {
    ctx.strokeStyle = randomColor(props.lineColorMin, props.lineColorMax);
    ctx.beginPath();
    ctx.moveTo(
      randomNum(0, props.contentWidth),
      randomNum(0, props.contentHeight)
    );
    ctx.lineTo(
      randomNum(0, props.contentWidth),
      randomNum(0, props.contentHeight)
    );
    ctx.stroke();
  }
};
const drawDot = (ctx) => {
  // 绘制干扰点
  for (let i = 0; i < 100; i++) {
    ctx.fillStyle = randomColor(0, 255);
    ctx.beginPath();
    ctx.arc(
      randomNum(0, props.contentWidth),
      randomNum(0, props.contentHeight),
      1,
      0,
      2 * Math.PI
    );
    ctx.fill();
  }
};

const refreshCode = () => {
  curIdentifyCode.value = "";
  makeCode(props.identifyCode, 4);
};
const makeCode = (o, l) => {
  for (let i = 0; i < l; i++) {
    curIdentifyCode.value += o[randomNum(0, o.length)];
  }
  // console.log(curIdentifyCode.value);
  emit("updateIdentifyCode", curIdentifyCode.value);
};

onMounted(() => {
  drawPic();
  refreshCode();
});

defineExpose({
  refreshCode,
});
</script>

2. 引入组件并使用:

<div class="login-box tx-c pd-t-30">
  <div>用户登录</div>
  <div class="form-box flex-row just-c">
    <el-form
      class="mr-t-40"
      ref="loginForm"
      :model="state.loginForm"
      :rules="state.loginFormRules"
    >
      <el-form-item prop="username">
        <el-input
          placeholder="请输入正确的用户名"
          v-model.trim="state.loginForm.username"
        >
          <template #prefix>
            <img src="@/assets/images/login/yonghu.png" alt="" />
          </template>
        </el-input>
      </el-form-item>
      <el-form-item prop="password">
        <el-input
          type="password"
          placeholder="请输入正确的账号匹配密码"
          v-model.trim="state.loginForm.password"
        >
          <template #prefix>
            <img src="@/assets/images/login/mima.png" alt="" />
          </template>
        </el-input>
      </el-form-item>
      <el-form-item prop="identifyCode">
        <el-input
          placeholder="请输入验证码"
          v-model.trim="state.loginForm.identifyCode"
        >
          <template #prefix>
            <img src="@/assets/images/login/code.png" alt="" />
          </template>
        </el-input>
        <IdentifyCode
          ref="identify"
          class="code-box"
          :contentWidth="120"
          :contentHeight="60"
          @updateIdentifyCode="setIdentifyCode"
        ></IdentifyCode>
      </el-form-item>

      <el-button type="primary" class="mr-t-30" @click="loginValidator"
        >登录
      </el-button>
    </el-form>
  </div>
</div>
import IdentifyCode from "@/components/IdentifyCode.vue";

const identify = ref(null);
const validateIdentifyCode = (rule, value, callback) => {
  if (value !== curIdentifyCode.value) {
    callback(new Error("验证码错误!"));
    state.loginForm.identifyCode = "";
    identify.value.refreshCode();
  } else {
    callback();
  }
};

const state = reactive({
  loginForm: {
    username: "",
    password: "",
    identifyCode: "",
  },
  loginFormRules: {
    username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
    password: [{ required: true, message: "请输入密码", trigger: "blur" }],
    identifyCode: [
      { required: true, message: "请输入验证码", trigger: "blur" },
      { validator: validateIdentifyCode, trigger: "blur" },
    ],
  },
});
let curIdentifyCode = ref("");

const loginForm = ref(null);

// 登录校验
const loginValidator = () => {
  loginForm.value.validate((valid) => {
    if (valid) {
      login();
    }
  });
};

// 登录
const login = async () => {
  const { username, password } = state.loginForm;
  const params = {
    username,
    password,
    type: "1",
  };
  const res = await $api.login(params);
  const { code, data } = res;
  if (code === 0 && data) {
    sessionStorage.setItem("isLogin", true);
    sessionStorage.setItem("token", data);
    router.replace("/home");
  } else {
    identify.value.refreshCode();
  }
};

const setIdentifyCode = (val) => {
  curIdentifyCode.value = val;
};
<style scoped>
.code-box {
  position: absolute;
  right: 0;
  top: 0;
  cursor: pointer;
}
</style>

3. 组件配置项:

属性 类型 描述
identifyCode String 验证码取值内容
fontSizeMin Number 字体最小值
fontSizeMax Number 字体最大值
backgroundColorMin Number 背景颜色rgb的最小值
backgroundColorMax Number 背景颜色rgb的最大值
colorMin Number 字体颜色rgb的最小值
colorMax Number 字体颜色rgb的最大值
lineColorMin Number 干扰线颜色rgb的最小值
lineColorMax Number 干扰线颜色rgb的最大值
dotColorMin Number 干扰点颜色rgb的最小值
dotColorMax Number 干扰点颜色rgb的最大值
contentWidth Number 画布宽度
contentHeight Number 画布高度

标签:const,登录,props,ctx,Number,randomNum,验证码,let,vue3
From: https://www.cnblogs.com/lpkshuai/p/17569225.html

相关文章

  • linux账号登录错误次数过多解锁
    [root@inmnmapp50~]#pam_tally2--userOSS3_JC_BSLoginFailuresLatestfailureFromOSS3_JC_BS32207/20/2317:50:1410.135.7.152[root@inmnmapp50~]#pam_tally2--userOSS3_JC_BS--resetLoginFailuresLatestfai......
  • 19、SSH限制ip登录
    1、window端通过ssh连接ubuntu虚拟接虚拟机ip:192.168.49.128主机用户:liuwc、liuwc1 ①、只允许指定用户登录[email protected] 修改配置文件vim/etc/ssh/sshd_config 执行此操作修改没有写的权限 执行:sudogedit/etc/ssh/sshd_config 命令行ssh登......
  • 关于vue3使用setup语法糖获取不到组件实例内部的变量
    //子组件<template><div>{{count}}</div><template<scriptsetup>import{ref}from'vue'constcount=ref(0)</script>//父组件<template><div><Childref="child"/>......
  • 58.请使用vue3+vite+typescript+element-plus+setup语法糖,使用xlsx和file-saver实现保
    1<template>2<div>3<el-table4:data="mergedTableData"5border6stripe7>8<!--表头-->9<el-table-column10prop="date"11label="......
  • ubuntu云服务器通过mstsc远程登录
    安装一个轻量级桌面环境,并实现通过Windows11的远程桌面服务访问,以及将所需的服务添加到开机自启,可以按照以下步骤进行操作:首先,通过SSH登录到云服务器。可以使用终端或PuTTY(Windows用户)等工具进行SSH登录。安装轻量级桌面环境,推荐使用Xfce桌面环境。运行以下命令......
  • RTMP流媒体服务器LntonMedia(免费)流媒体服务器平台修改登录密码与开启接口鉴权的解决方
    LntonMedia支持一站式的上传、转码、直播、回放、嵌入、分享功能,具有多屏播放、自由组合、接口丰富等特点。平台可以为用户提供专业、稳定的直播推流、转码、分发和播放服务,全面满足超低延迟、超高画质、超大并发访问量的要求。1、如何修改密码为了提升平台数据安全性,LntonMedia等......
  • 第二天,三次登录
    #用户登录3次机会i=0whilei<3:username=input("请输入用户名:")password=int(input("请输入密码:"))ifusername=='cxr'andpassword==123:print('Sucessed')else:print('failed,plztr......
  • 怎么查看sql server数据库登录密码
    如何查看SQLServer数据库登录密码要查看SQLServer数据库登录密码,需要使用系统存储过程和DMV(DynamicManagementViews)来查询相关信息。下面是一个详细的步骤说明,以及相应的代码示例。步骤1:连接到SQLServer实例首先,使用SQLServerManagementStudio(SSMS)或其他SQLServer数据......
  • 02 开发社区登录模块
    发送邮件流程邮箱设置启用客户端SMTP服务SpringEmail导入jar包邮箱参数配置使用JavaMailSender发送邮件模板引擎使用Thymeleaf发送HTML邮件启用客户端SMTP服务QQ邮箱在这里开启:导入邮箱包SpringBootStarterMailmaven坐标: <!--https://mvnrepos......
  • docker mysql root 外网无法登录
    如何实现“dockermysqlroot外网无法登录”整体流程下面是实现“dockermysqlroot外网无法登录”的步骤。我们将使用Docker来创建一个MySQL容器,并配置使得root用户无法从外部访问。安装Docker:首先需要在你的机器上安装Docker,可以参考官方文档或者使用适合你操作系统的安装......