当我们在需要把子页面的数据传递给父页面时,就需要用到子传父通信。
下面是要把封装好的验证码组件放到父组件里面使用,由于是子组件里面生成的验证码,所以这里要把子组件的值传递到父组件里面去,用于校验判断。
下面是细节步骤:
1. 首先我们是要把子组件data里面的checkCode传递到父组件里
watch:{
checkCode(newvalue,oldvalue){
this.$emit("send",newvalue,oldvalue)
}
},
// 这里用watch监听checkCode值,一旦变化了就通过this.$emit()提交数据,
// 也可以在mounted函数里,通过this.$emit()传递过去,看实际的需求。
// 第一个参数是自定义的事件,注意这里的事件必须要与在父组件给子组件注册的事件保持一致。
// 后面第二个第三个参数就是需要传递过去的值,这里可以传递过去很多值,
// 在父组件里接受就可以了。
2. 在父组件里找到引用子组件的地方。
<Input v-model="formValidate.authCode" placeholder="请输入验证码" clearable>
<Icon custom="iconfont icon-dunpai" slot="prefix" />
<span slot="append">
<securityCode @send="incident" slot="suffix"></securityCode>
</span>
</Input>
注意: 这里 <securityCode @send="incident" slot="suffix"></securityCode>定义的事件必须要与子组件里面提交的事件一直 this.$emit("send",newvalue,oldvalue)。
3. 最后在事件的方法里就可以接受传递的参数了。
incident(newvalue){
this.identifyingCode = newvalue
},
注意:这里的newvalue形参值要与子组件提交的形参值保持一致,无论后面传递的有多少个参数,接受时的参数名必须要一致。 this.$emit("send",newvalue,oldvalue)
最后就可以在父组件里使用子组件的值了。
子组件完整页面:
<style lang="less" scoped>
</style>
<template>
<div>
<!-- 画布用于展示验证码 -->
<canvas class="codeCanvas" ref="checkCode" @click="getCode"></canvas>
</div>
</template>
<script>
export default {
name:"securityCode",
data(){
return {
inputCode: '', // 输入的值
checkCode: '', // 图片验证码的值
// canvas各种设置
cvs: {
w: 74, // 给出默认宽度 宽度会在图片绘制时根据长度更改
h: 30, // 高 与input保持一致
fontSize: 22, // 字体大小
// 字符串生成范围
str: '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM',
len: 4, // 字符串长度
line: 3 // 噪音线个数
}
}
},
mounted(){
this.getCode();
},
watch:{
checkCode(newvalue,oldvalue){
this.$emit("send",newvalue,oldvalue)
}
},
methods:{
onClick(name){
this.status = name
},
getCode(){
// vue的话可直接用$refs取值,不用vue的话可绑定id然后通过document处理
let domCvs = this.$refs.checkCode;
this.drawCode(domCvs);
},
// 随机整数生成器,范围[0, max)
rInt(max) {
return Math.floor(Math.random() * 100000 % max);
},
// 生成随机字符串
rCode() {
let code = '';
let len = this.cvs.len;
let strLen = this.cvs.str.length;
for(let i = 0; i < len; i ++) {
code += this.cvs.str.charAt(this.rInt(strLen));
}
this.checkCode = code;
return code;
},
// 生成随机颜色 rgba格式
rColor() {
let a = ((Math.random()*5 + 5) / 10).toFixed(2);
return `rgba(${this.rInt(256)}, ${this.rInt(256)}, ${this.rInt(256)}, ${a})`
},
// 验证码图片绘制
drawCode(domCvs) {
let _this = this;
// 随机字符串
let checkCode = this.rCode();
// 宽设置
this.cvs.w = 1 + this.cvs.fontSize * this.cvs.len;
// 判断是否支持canvas
if(domCvs !== null && domCvs.getContext && domCvs.getContext('2d')){
// 设置显示区域大小
domCvs.style.width = _this.cvs.w;
// 设置画板宽高
domCvs.setAttribute('width', _this.cvs.w);
domCvs.setAttribute('height', _this.cvs.h);
// 画笔
let pen = domCvs.getContext('2d');
// 背景: 颜色 区域
pen.fillStyle = '#eee';
pen.fillRect(0, 0, _this.cvs.w, _this.cvs.h);
// 水平线位置
pen.textBaseline = 'middle'; // top middle bottom
// 内容
for(let i = 0; i < _this.cvs.len; i ++) {
pen.fillStyle = _this.rColor(); // 随机颜色
pen.font = `bold ${_this.cvs.fontSize}px 微软雅黑`; // 字体设置
// 字符绘制: (字符, X坐标, Y坐标)
pen.fillText(checkCode.charAt(i), 10 + _this.cvs.fontSize * i, 15 + _this.rInt(10));
}
// 噪音线
for(let i = 0; i < _this.cvs.line; i ++) {
// 起点
pen.moveTo(_this.rInt(_this.cvs.w) / 2, _this.rInt(_this.cvs.h));
// 终点
pen.lineTo(_this.rInt(_this.cvs.w), _this.rInt(_this.cvs.h));
// 颜色
pen.strokeStyle = _this.rColor();
// 粗细
pen.lineWidth = '2';
// 绘制
pen.stroke();
}
} else {
this.$message.error('不支持验证码格式,请升级或更换浏览器重试');
}
},
}
}
</script>
父组件完整页面:
<style lang="less" scoped>
// @import "//at.alicdn.com/t/font_2901774_k83z065422.css";
@import "//at.alicdn.com/t/font_2901774_3y46gmvnbhh.css";
*{
margin: 0;
padding: 0;
}
.main{
overflow: auto; // 超出时 产生滚动条
}
.w{
width: 960px;
padding: 0 100px;
margin: 0 auto;
}
.card{
position:relative;
top: 130px;
left: 0px;
}
.steps{
margin-top: 180px;
}
/deep/ .ivu-tabs-nav .ivu-tabs-tab{
padding:8px 70px;
}
/deep/ .ivu-tabs-tabpane {
width: 100% !important;
}
/deep/ .ivu-input-prefix i, .ivu-input-suffix i{
line-height: 30px;
font-size: 18px;
}
/deep/ .ivu-input-group-append, .ivu-input-group-prepend{
padding: 0px 0px;
line-height: 0;
}
.icon_dp{
position: absolute;
top:8px;
left: 8px;
font-weight: 700;
z-index: 3;
}
.span_code{
font-size: 14px;
color: #5ec3fc;
}
.icon_email{
position: absolute;
top:8px;
left: 8px;
font-size: 18px;
z-index: 3;
}
.icon_xiao{
position: relative;
top: -3px;
left: 0px;
color: lime;
}
</style>
<template>
<div class="mian">
<Card class="w card" >
<Tabs v-model="tabSet">
<TabPane label="①账号验证" :disabled="disabled" name="账号验证">
<Form ref="accountNumber" :label-width="180" :model="formValidate" :rules="verify">
<Row style="margin-top:20px;">
<Col span="18">
<FormItem prop="mailbox">
<Input prefix="md-phone-portrait" v-model="formValidate.mailbox" placeholder="请输入邮箱" clearable/>
</FormItem>
</Col>
</Row>
<Row>
<Col span="18">
<FormItem prop="authCode">
<Icon class="icon_dp" custom="iconfont icon-dunpai" />
<Input v-model="formValidate.authCode" placeholder="请输入验证码" clearable>
<Icon custom="iconfont icon-dunpai" slot="prefix" />
<span slot="append">
<securityCode @send="incident" slot="suffix"></securityCode>
</span>
</Input>
</FormItem>
</Col>
</Row>
<Row>
<Col span="18">
<FormItem prop="sendVerificationCode">
<Icon class="icon_email" type="ios-mail" />
<Input placeholder="请输入短信验证码" v-model="formValidate.sendVerificationCode" clearable>
<Icon type="ios-mail" slot="prefix" />
<Button slot="append" class="span_code" :disabled="verificationCodeDisabled" @click="resendVerificationCode">{
{noteCode}}</Button>
</Input>
</FormItem>
</Col>
</Row>
<Row>
<Col span="18">
<FormItem>
<Button type="primary" long @click="nextStep('accountNumber')">下一步</Button>
</FormItem>
</Col>
</Row>
</Form>
</TabPane>
<TabPane label="②重置密码" :disabled="disabled2" name="重置密码">
<Form :label-width="180" :model="replacement" ref="form" :rules="examine">
<Row style="margin-top:20px;">
<Col span="18">
<FormItem prop="password">
<Input v-model="replacement.password" prefix="ios-lock" password type="password" placeholder="请输入密码"></Input>
</FormItem>
</Col>
</Row>
<Row>
<Col span="18">
<FormItem prop="confirmPassword">
<Input v-model="replacement.confirmPassword" prefix="ios-lock" password type="password" placeholder="请确认密码"></Input>
</FormItem>
</Col>
</Row>
<Row>
<Col span="18">
<FormItem>
<Button style="width:47%;" type="primary" @click="nextStepAgain('form')">下一步</Button>
<Button style="width:47%;margin-left:20px;" @click="reset">重置</Button>
</FormItem>
</Col>
</Row>
</Form>
</TabPane>
<TabPane label="③完成设置" :disabled="disabled3" name="完成设置">
<Form :label-width="180">
<Row style="margin-top:20px;">
<Col span="18">
<FormItem>
<p style="margin-left:55px;">
<Icon custom="iconfont icon-iconweixiao" class="icon_xiao"/>
新登录密码重置成功,请重新登录!
</p>
</FormItem>
</Col>
</Row>
<Row style="margin-top:50px;">
<Col span="18">
<FormItem>
<Button type="primary" long @click="logAgain">重新登录</Button>
</FormItem>
</Col>
</Row>
</Form>
</TabPane>
</Tabs>
</Card>
</div>
</template>
<script>
import securityCode from "./code/securityCode.vue"
export default {
components:{
securityCode
},
computed:{
},
data(){
const validateCode = (rule, value, callback) =>{
let errors = []
if(value !== this.identifyingCode ){
callback("验证码不正确请重新输入")
}
callback(errors)
}
const confirmNewPasswordValidate = (rule, value, callback) =>{
let errors = []
if(value !== this.replacement.password){
callback("两次密码输入不一致")
}
callback(errors)
}
return {
// ------重置密码------
replacement:{
password:"", // 密码
confirmPassword:"", // 确认密码
},
examine:{
password:[ {required: true, message: '请输入密码', trigger: 'blur'} ],
confirmPassword:[
{required: true, message: '请确认密码', trigger: 'blur'},
{validator:confirmNewPasswordValidate,message:"两次密码输入不一致",trigger: 'blur'}
]
},
// ------账号验证------
formValidate:{
mailbox:"", //邮箱
authCode:"",// 输入的验证码
sendVerificationCode:"", // 发送验证码
},
verify:{
mailbox:[
{ required: true, message:'请填写邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
],
authCode:[
{ required: true, message: '请填写验证码', trigger: 'blur' },
{ validator:validateCode, message:'验证码不正确请重新输入',trigger: 'blur' }
],
sendVerificationCode:[
{ required: true, message:'请填写短信验证码', trigger: 'blur' },
]
},
sum:60,
timer:"",
noteCode:"发送验证码",
verificationCodeDisabled:false, // 发送验证码是否禁用
identifyingCode:"", // 图形验证码
tabSet:"重置密码",
disabled:false, // 账号验证
disabled2:true, // 重置密码
disabled3:true, // 完成设置
}
},
mounted(){
this.tabSet = "账号验证"
this.incident()
},
methods:{
resendVerificationCode(){
this.verificationCodeDisabled = true
this.timer = setInterval(() => {
this.noteCode = this.sum+" 秒后发送"
this.sum--
if(this.sum < -1){
clearInterval(this.timer)
this.noteCode = "发送验证码"
this.verificationCodeDisabled = false
this.sum = 60
}
}, 1000)
},
incident(newvalue){
this.identifyingCode = newvalue
},
nextStep(name){
this.$refs[name].validate((valid)=>{
if(valid){
this.disabled = true
this.disabled2 = false
this.disabled3 = true
this.tabSet = "重置密码"
clearInterval(this.timer)
}
})
},
nextStepAgain(name){
this.$refs[name].validate((valid)=>{
if(valid){
this.disabled = true
this.disabled2 = true
this.disabled3 = false
this.tabSet = "完成设置"
}
})
},
reset(){
this.replacement.password = ""
this.replacement.confirmPassword = ""
},
logAgain(){
window.open("#/login")
},
}
}
</script>
效果图: