在使用html写的UI图的基础上将数据变为动态的,原计划是新建vue项目然后将html兼容进去,但发现有些样式不兼容(ui图使用了框架,里面包含大量样子需要做剥离与兼容)同时涉及到页面跳转的问题所以考虑在html中引入vue.js实现数据的双向绑定,方便做数据展示。已下为遇到的问题和坑:

一、html页面引入vue.js

可直接参考 在原生HTML文件中引入Vue并使用

我是下载后将js文件放入本地引用的

创建 Vue 实例并挂载到 html元素中有些不一样

vue的版本 Vue常用方法汇总 VUE中的方法作用

<template>
  <div id="app"> // vue挂载的元素 id="app" 可以不写 会默认挂载到当前页面
  </div>
</template>

<script>

export default {
  name: "index",//当前页面的名称
  data() {
    //数据定义
    return {}
  },
  created: {//html加载完成之前
  },
  mounted: {//html加载完成后执行
  },
  methods: {//组件方法
  },
  watch: {
    // watch监听方法,擅长处理的场景:一个数据影响多个数据
  },


}
</script>

js引入vue.js的版本

<html>
<head>
</head>
<div id="app"> // vue挂载的元素 id="app" 必须写 可以不用写在顶级div上 写在那个div上vue就挂载在那个div的作用域中
  ...
</div>
<script>
  new Vue({
    el: '#app', // Vue 实例挂载的元素 名字要与 id="app" 对上 可以换其他名字
    data: { //数据定义 与vue版的不一样,需要先挂载html元素
      return {
        *****
      };
    },
    methods: {
          ****
        }
        * * * * * * *
    // 其他的方法就一样了
  })
</script>
</html>

可以参考 在原生HTML文件中引入Vue并使用

二、图形验证码

一般登录、注册使用的验证码是后端返回的,但由于时间比较紧加上不想重复写相关逻辑(系统有原本后台登录相关的验证码)就考虑直接由前端生成,然后验证。

1、效果图展示

点击图片既可以切换

2.代码

代码是参考js创建随机验证码 其中做了一些修改,原代码为原始的js

 /**
             * @param {number} size 随机字符数
             * @return {str[]} 验证码列表
             */
            genRandomStr(size = 4) {
                const range = [
                    "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
                ];
                const strList = [];
                for (let i = 0; i < size; i++) {
                    const randomStr = range[Math.floor(Math.random() * range.length)];
                    strList.push(randomStr);
                }
                return strList;
            },

            /**
             * @param {number} width 验证码高度
             * @param {number} height 验证码宽度
             * @return {imgSrc:string,value:string} 返回图片链接,验证码值
             */
            useCaptcha(width = 100, height = 50) {
                // 生成随机内容
                const canvas = document.createElement("canvas");
                canvas.width = width;
                canvas.height = height;
                const ctx = canvas.getContext("2d");
                const captcha = this.genRandomStr();

                for (let i in captcha) {
                    const str = captcha[i];
                    const transLen = (width * 0.8) / captcha.length;// 偏移量
                    const sizeRatio = 0.3 + 0.5 * Math.random();// 随机文字大小比例
                    const degRatio = (Math.random() - 0.5) * (width / height); // 设置为长宽比不会旋转太过 // 随机旋转比例
                    ctx.font = height * sizeRatio + "px serif";// 设置字体大小
                    // ctx.rotate(degRatio);
                    ctx.fillStyle = this.randomColor();
                    ctx.fillText(str, width * 0.1, height * 0.8, width * 0.8);
                    ctx.translate(transLen, 0); // 偏移
                    // ctx.rotate(-degRatio); // 恢复旋转
                }
                ctx.translate(-width * 0.8, 0);
                for (var i = 0; i <= 50; i++) {
                    ctx.beginPath(); // 新建画图路径
                    ctx.strokeStyle = this.randomColor();
                    ctx.moveTo(Math.random() * width, Math.random() * height);
                    ctx.lineTo(Math.random() * width, Math.random() * height);
                    ctx.stroke();
                }

                const result = {
                    imgSrc: canvas.toDataURL(),
                    value: captcha.join(""),
                };
                return result;
            },

            setImg() {
                const imgDom = document.getElementById("idcode");
                const captchaObj = this.useCaptcha(300, 150);
                imgDom.src = captchaObj.imgSrc;
                console.log("验证码值:", captchaObj.value);
                // document.getElementById("yzm").value = captchaObj.value;
                this.captCode = captchaObj.value;
            },
            randomColor() {
                const randR = Math.floor(Math.random() * 256);
                const randG = Math.floor(Math.random() * 256);
                const randB = Math.floor(Math.random() * 256);
                return `rgb(${randR},${randG},${randB})`;
            }

三、fom表单的操作

1、表单的点击事件

需要使用v-on 用来绑定各种事件,直接使用onclick 会不生效

参考链接 vue常用事件v-on:click详解事件对象,事件冒泡,事件默认行为 vue基本语法

2、form表单中的button按钮如何阻止提交

在from表单标签开始的地方加上onsubmit="return false"

button使用return false可以阻止提交

<button type="submit" class="submit_button" onClick=“submitAction();return false;”>提交</button>

查考 form表单中的button按钮如何阻止提交

但是这样虽然会阻止button按钮提交,但会导致表单内的单选框无法使用,可见下文

3、获取表单的数据同时校验数据

使用vue项目时可用使用element ui框架来做表单,同时加验证之类的。但现在是使用的html页面,虽然单独引入element的css也可以实现功能,但是样式之类的就不能保证和给出的ui图一致,所以在对ui图代码不做样式改动的情况先完成表单数据获取与验证的功能。(也可以使用原生form的数据获取与校验,但是原生js有点麻烦,既然引入了vue就是想简单一点,同时用v-model 也可以实现就是验证麻烦一点,看具体业务验证复杂程度,我这就就判断必填)

(1)html改造

在表单中添加id,同时在字段上也添加id与name,同时在输入框前面的提示字使用label 标签包裹添加for属性

<form class="form clearfix" onClick="return false;" id="gr-form">
	<div class="row">
		<div class="col-lg-12 col-xs-12 col-md-12 col-sm-12">
			<div class="form-item">
				<div class="ipt-tit"><span style="color: red;padding-right: 3px;">*</span>
					<label for="nickName" style="font-weight: normal;">姓名</label></div>
				<div class="ipt-area">
					<input class="form-control" id="nickName" name="nickName" placeholder="" style="width: 40%;">
					<span>必须填写真实姓名,否则不能通过审核</span>
				</div>
			</div>
		</div>
	</div>
	<div class="row">
		<div class="col-lg-12 col-xs-12 col-md-12 col-sm-12">
			<div class="form-item">
				<div class="ipt-tit"><span style="color: red;padding-right: 3px;">*</span>
					<label for="papersType" style="font-weight: normal;">证件类型</label></div>
				<div class="ipt-area">
					<select class="form-select" style="width: 40%;" id="papersType" name="papersType">
						<option value="0">居民身份证</option>
						<option value="1">士官证</option>
						<option value="2">临时身份证</option>
						<option value="3">护照</option>
						<option value="4">通行证</option>
						<option value="5">外国人居留证</option>
						<option value="6">其他证件</option>

					</select>
					<span>请选择证件类型</span>
				</div>
			</div>
		</div>
	</div>
	<div class="pwdOper">
		<span class="remember">
			<label  >
			  <input type="checkbox" id="protocol" name="protocol" value="yes">
			  <span class="checkbox"></span> 我已经阅读并同意<a href="javascript:void(0)" onClick="btn()">《农村产权交易管理信息平台会员注册协议》</a>
			</label>
			
		</span>
	</div>
</form>

(2)js获取数据

使用serializeArray() 方法通过序列化表单值来创建对象数组(名称和值)

数据通过"对象.属性名"添加属性和方法

(已下方法是写在vue的methods中的)

grsubmitAction() {
	let serializeArray = $("#gr-form").serializeArray();//获取数据 并序列化
   if(this.parameterVerification(serializeArray)) {//校验
   //业务代码
   }
},
parameterVerification(serializeArray){
	var data = {}
	const verifyStatus=true; 
	serializeArray.forEach(function (input) {
		if(!verifyStatus){return;}
		let name = input.name;
		let value = input.value;
		if (value.trim() === "") {
			let label = document.querySelector('label[for="' + name + '"]');
			if (label !== null){
				layer.msg(label.textContent + '为必填项', function () {
				});
				verifyStatus=false
				return;
			}
		} else {
			data[name] = value
		}
	})
	if(data.protocol!==null && data.protocol!=='yes'){
		layer.msg('请先阅读并同意《用户协议》', function () {
		});
		verifyStatus=false
	}
	if (data.phoneNumber !==null && data.phoneNumber!=='') {
		if(!/^1[3456789]\d{9}$/.test(data.phoneNumber)){
			layer.msg('请输入正确的手机号', function () {
				
			})
			verifyStatus=false
		}
	  
	}

	this.form = data
	return verifyStatus;
	
},

其中 $("#gr-form").serializeArray() 是获取去id为gr-form 的表单数据,在parameterVerification方法进行判断是否必填

是否必填看的是 label标签 let label = document.querySelector('label[for="' + name + '"]'); 如果有值的话就说明这个对应的输入框是必填的,同时这里的for 属性与输入框的id和name是一致的,这样就可以与输入框一一对应,这行代码通过label.textContent 方法可用获取到 label 标签中的文字作为提示的内容。

layer.msg()这是layui的弹出层,可用单独引用,这里换成自己框架的弹出层提示

js获取表单数据与验证可用查考:JS获取表单数据 原生js实现from表单验证 多种方式给JS对象添加属性和方法 列化表单数据 serialize()、serializeArray()及使用

4、from表单中的单选或多线按钮无法使用

在上文中提到可用使用 在button使用return false可以阻止提交,这样会导致在表单中的单选或多选无法使用,这个无论是加在 表单上或是按钮上都会有影响,最开始以为是单选框的问题 参考 HTML 单选按钮无法正常工作 文章的问题二中第2条,去掉return false 同时将按钮改为div 绑定点击事件后正常。

四、给页面添加遮罩

由于我这个是html应用vue.js,是在页面出现后才去创建vue实例,然后再去渲染页面上的{{XXX}} 与vue的一些指令,这样就会导致 {{XXX}}这类的代码会以文本的情况先出现在页面上,等vue创建后才会再去渲染,页面会有1 秒左右的延迟,之后闪动一下出现我们想要的,类似与这种

所以,我们在页面显示的时候先给加遮罩,等vue创建完成后再把遮罩取消掉,这样就不会显得很突兀。

//在最外层的div后面加上下面这段代码,默认页面打开的时候就加了遮罩
<mask id="maskdiv" style="position: absolute; top: 0px; left: 0px; background-color: rgba(128, 128, 128, 0.5); width: 1536px; height: 2510px; z-index: 10000;">
	<div id="loadingContainer" style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background-color: rgb(255, 255, 255); padding: 20px; border-radius: 10px; box-shadow: rgba(0, 0, 0, 0.5) 0px 0px 10px; text-align: center;">
		<img src="https://i.miji.bid/2023/11/28/d3172e065f40eefc779ec2f90d2dba7c.gif" style="width: 50px; height: 50px;">
		<div style="margin-top: 10px; color: black;">加载中,请稍候...</div>
	</div>
</mask>

<script>
	 function loadingHide() {
		document.body.removeChild(document.getElementById('maskdiv'));
    }
    var vm = new Vue({
        el: '#app',
        data() {
            return {
            };
        },
		created(){
		},
		mounted(){//vue的 html加载完成后执行
			loadingHide() //关闭遮罩
  		},
	})
</script>

参考原文: JS的loading遮罩层,拿来可用 不过原文是使用js来绘制的这个遮罩,我直接将转换成代码的遮罩复制到页面上页面显示。

五、发送短信按钮添加间隔禁用

// 使用 button
<button class="margin-left-20 padding-left-5 padding-right-5" id="hqyzm" v-on:click="fsyzm()">获取验证码</button>
//不使用 button
<div class="login-btn "v-on:click="verificationCode()" id="hqyzm" style="display: flex;justify-content: center;
						align-items: center;width: 100px;    margin-top: 0px;    margin-left: 5px;">发送验证码</div>
fsyzm(){
	comm.getAjaxNoToken(mineCenterApi.verificationCode + this.form.phoneNumber, {}, function(result) {
		if (result.code === 200) {
			layer.msg('验证码已发送')
		}
	});
	var btn=document.getElementById('hqyzm') //获取按钮
	var time=60
	btn.disabled=true //禁用
	var timer=setInterval(function () {
		if (time<0){
			clearInterval(timer)
			btn.disabled=false
			btn.innerHTML='获取验证码'
			time=60
		}else {
			btn.innerHTML = '还剩' + time + '秒'
			time -= 1
		}
	},1000)

},

verificationCode(){
	if(vm.sffsyzm){ // div无法设置禁用 在vue的date中设置一个变量 然后进行判断
		comm.getAjaxNoToken(mineCenterApi.verificationCode + vm.form.phoneNumber, {}, function(result) {
			if (result.code === 200) {
				layer.msg('验证码已发送')
				vm.sffsyzm=false   // 验证码发送了就设置false 不再发送验证码
				var btn=document.getElementById('hqyzm')
				var time=60
				var timer=setInterval(function () {
					if (time<0){
						clearInterval(timer)
						vm.sffsyzm=true
						btn.innerHTML='发送验证码'
						time=60
					}else {
						btn.innerHTML = '还剩' + time + '秒'
						time -= 1
					}
				},1000)
			}
		});
	
	}else {
		layer.msg('请稍后再试')
	}
	
},

参考: 用Javascript实现发送短信验证码间隔