完成注册页面
今天主要就是完成注册页面(Dialog对话框),跟昨天一样也是用elementui做一个表单的框架出来发送请求并且完成注册
主要参考elementui的文档
register.vue(注册组件是登录组件的子组件)
<template>
<div class="register">
<el-dialog center :visible.sync="dialogVisible" width="600px">
<div slot="title" class="title">注册</div>
<el-form :model="registerForm" :rules="rules" label-width="100px" ref="registerRef">
<!-- 头像上传 -->
<el-form-item label="头像" prop="avatar">
<!-- action 上传文件的url地址,name就是上次文件时候的参数 -->
<el-upload
class="avatar-uploader"
:action="uploadAction"
name="image"
:show-file-list="false"
:on-success="handleAvatarSuccess"
:before-upload="beforeAvatarUpload"
>
<img v-if="imageUrl" :src="imageUrl" class="avatar" />
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
</el-form-item>
<!-- -->
<el-form-item label="昵称" prop="username">
<el-input v-model="registerForm.username"></el-input>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="registerForm.email"></el-input>
</el-form-item>
<el-form-item label="手机" prop="phone">
<el-input v-model="registerForm.phone"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="registerForm.password" show-password></el-input>
</el-form-item>
<el-form-item label="图形码" prop="code">
<el-row>
<el-col :span="17">
<el-input v-model="registerForm.code"></el-input>
</el-col>
<el-col style="margin-left:10px" :span="6">
<img class="captcha" :src="codeURL" @click="getCode" alt />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="验证码" prop="rcode">
<el-row>
<el-col :span="17">
<el-input v-model.number="registerForm.rcode"></el-input>
</el-col>
<el-col style="margin-left:10px" :span="6">
<el-button @click="getRcode">获取用户验证码</el-button>
</el-col>
</el-row>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="dialogVisible = false">取 消</el-button>
<el-button type="primary" @click="submit">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "Register",
// props: ["isShow"],
data() {
return {
// 头像的请求地址
uploadAction: process.env.VUE_APP_BASEURL + "/uploads",
// 要上传头像的src
imageUrl: "",
// 图形码的请求地址
codeURL: process.env.VUE_APP_BASEURL + "/captcha?type=sendsms",
dialogVisible: false,
// dialogVisible: this.isShow
registerForm: {
// 这里面的数据,将来是要提交给服务器
username: "",
phone: "",
email: "",
avatar: "", //头像地址
password: "",
code: "", //图形码
rcode: "" //验证码
},
//校验规则
rules: {
avatar:[
{ required: true, message: "头像不能为空", trigger: "blur" }
],
username: [
{ required: true, message: "用户名不能为空", trigger: "blur" }
],
email: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
callback(new Error("邮箱不能为空"));
return;
}
// 邮箱的正则
const reg = /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/; //邮箱正则
if (!reg.test(value)) {
return callback(new Error("邮箱不合法!"));
}
callback();
},
trigger: "blur"
}
],
phone: [
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
return callback(new Error("手机号不能为空"));
}
const reg = /^1[3456789][0-9]{9}$/; //手机号正则
if (!reg.test(value)) {
return callback(new Error("手机号不合法"));
}
callback();
},
trigger: "blur"
}
],
password: [
{ required: true, message: "密码不能为空", trigger: "blur" },
{ min: 6, message: "长度在不能小于6个字符", trigger: "blur" }
],
code: [
{ required: true, message: "图形码不能为空", trigger: "blur" },
{ min: 4, max: 4, message: "图形码必须是4位", trigger: "blur" }
],
rcode: [
// { required: true, message: '验证码不能为空', trigger: 'blur' },
// { min: 4,max:4,message: '验证码必须是4位', trigger: 'blur' }
{
required: true,
validator: (rule, value, callback) => {
if (!value) {
return callback(new Error("验证码不能为空"));
}
if (!Number.isInteger(value)) {
callback(new Error("请输入数字值"));
}
callback();
},
trigger: "blur"
}
]
}
};
// watch: {
// isShow:function(newValue){
// this.dialogVisible=newValue
// }
// },
},
methods: {
getCode() {
this.codeURL =
process.env.VUE_APP_BASEURL +
"/captcha?type=sendsms&r=" +
Math.random() * 999;
},
//用async await方式,就不用then了
async getRcode() {
const res = await this.$axios.post("/sendsms", {
code: this.registerForm.code,
phone: this.registerForm.phone
});
if (res.data.code == 200) {
this.registerForm.rcode = res.data.data.captcha;
} else {
//如果错误就弹出错误弹出框提示你
this.$message.error(res.data.message);
// 并且重新刷新获得新的图形码
this.getCode();
}
// this.$axios.post("/sendsms", {
// code: this.registerForm.code,
// phone: this.registerForm.phone
// })
// .then(res => {
// // console.log(res);
// // 把获取回来的验证码输入在rcode输入框中
// if (res.data.code == 200) {
// this.registerForm.rcode = res.data.data.captcha;
// }else{
// //如果错误就弹出错误弹出框提示你
// this.$message.error(res.data.message);
// // 并且重新刷新获得新的图形码
// this.getCode()
// }
// });
},
//头像上传成功后的回调函数
handleAvatarSuccess(res) {
//把返回的路径给imageUrl赋值,让注册页面显示刚上传的头像
this.imageUrl = process.env.VUE_APP_BASEURL + "/" + res.data.file_path;
//给registerForm中的avatar模型赋值
this.registerForm.avatar = res.data.file_path;
},
// 头像上传之前的回调函数
beforeAvatarUpload(file) {
const isImage =
file.type === "image/jpeg" ||
file.type === "image/gif" ||
file.type === "image/png";
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isImage) {
this.$message.error("上传头像图片只能是 JPG/png/ 格式!");
}
if (!isLt2M) {
this.$message.error("上传头像图片大小不能超过 2MB!");
}
//如果是要进行上传文件的请求,我们必须返回true,才能进行文件上传
return isImage && isLt2M;
},
// 点击确定按钮对整个form表单做最后一次校验
submit() {
this.$refs.registerRef.validate(async valid => {
if (!valid) return;
const res = await this.$axios.post("/register", this.registerForm);
console.log(res);
//请求成功后
if (res.data.code == 200) {
// 弹出登录成功的提示框
this.$message({
message: "注册成功",
type: "success"
});
// 请求成功后要把当前窗口消失
this.dialogVisible = false;
} else {
this.$message.error(res.data.message);
}
});
}
}
};
</script>
<style lang="less">
//这里我就不复制了太多了
</style>
项目说明:
注册
UI界面搭建
-
el-dialog
- 弹出框
- 当我们点击了登录页面的注册按钮时候,我们就需要把那个Dialog显示出来
- el-dialog的显示和隐藏,是由它的一个属性:visible
- 当我们需要自定义title或是footer的时候,我们需要使用到具名插槽
<div slot="title"> 定义标题的内容</div> <div slot="footer">自定义底部的内容</div> //现在我们是使用el-dialog中提供好的名字叫做 title 和 footer的插槽
-
el-form,表单
-
点击登录页面的注册按钮,显示register组件
- 1、先让register组件成为login组件的子组件
- 2、使用子组件的时候,给子组件设置一个 ref 属性
- 3、点击注册按钮的时候,通过 refs 拿到子组件的实例,然后更改子组件中模型的数据 this.$refs.registerRef.dialogVisible = true
获取用户输入的内容
- el-form model
- el-form-item 里面的 el-input 的 v-model 来实现
- 步骤:
- 1、在模型中定义模型对象
并且模型中的属性,要结合后台接口文档来看,要跟后台接口文档中的属性保持一致【因为传递过去的属性,要和后台要求的一致】 - 2、给el-form绑定一个 model 属性
- 3、给el-form-item里面的 el-input 进行双向数据绑定
- 4、如果它自带的规则,无法满足我们的需求,我们就可以来自定义规则
- 1、在模型中定义模型对象
验证
- el-form rules
- el-form-item prop
- 步骤
- 1、定义好一个模型,它是一个对象 rules,里面可以写一个一个的校验规则
- 2、记得给 el-form 绑定 rules 这个属性
- 3、记得给 el-form-item 设置 prop 这个属性才行,这样的校验规则才起作用
完成刷新图形码的功能
- 更改图形验证码的地址,发送的url地址后面加随机参数
头像上传
注意点: elementui中的头像上传不是使用的axios,用的input输入框中的action以及name属性搭配使用
注册
发送请求,把registerForm中的值带过去为参数
如何把之前通过promise.then获取数据的方式,改成通过 async & awiat 来获取数据
- 1、我们要把我们的函数,变成一个异步函数
- 2、在我们异步函数内部,就可以使用 await 的方式来获取请求的数据
- 3、注意,我们在使用 async & await 的时候,一定要成对使用
关掉eslint的检查
- 1、在项目根目录创建一个文件 vue.config.js 【一定要创建在项目根目录,并且名字也必须是 vue.config.js】
- 2、在vue.config.js中,编写代码,关闭eslint的检查,默认是true
module.exports = {
// 选项...
lintOnSave: false
};
- 3、因为更改了配置文件,所以大家一定要记得,重新运行项目,它才会起作用
插槽
- el-dialog
- 注意点
- 例如:elementui的轮播图
- 插槽一般用于父子组件中
一般我们把插槽定义在子组件中
在父组件中,去写我们的内容,替换子组件中插槽
- 作用: 占位和替换
默认插槽
,就像是子组件有一个装东西的solt口子,父组件中导入子组件的时候在子组件标签内填入的东西就会填满那个口子- 没有名字
- 步骤
1、先整一个父组件和子组件
2、在父组件中使用子组件
child.vue子组件:
<template>
<div id="childId">
子组件<br/>
<!-- 占位和将来被替换,有点类似于 router-view -->
<slot />
</div>
</template>
parent.vue父组件:
<template>
<div id="parentId">
父组件
<hr>
<child>
<!-- <span style="color:red;">测试默认操作</span> -->
<!-- <h1>111</h1> -->
<img src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1589894473467&di=2a3113bedacd5e5c08d856f2a00bc758&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201704%2F11%2F20170411194843_HGBrC.thumb.700_0.jpeg" alt="">
</child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
}
}
</script>
具名插槽
,就像是子组件有一个装东西的并且还有名字solt口子,父组件中导入子组件的时候在子组件标签内找到对应的名字的口子并往里面填入东西- el-dialog中的标题
- 插槽有名字,我们就叫具名插槽
child.vue子组件:
<template>
<div id="childId">
子组件<br />
<div style="border: 1px solid red;">
<slot name="title"/>
</div>
<br />
<div style="border: 1px solid green;">
<slot />
</div>
<br />
<div style="border: 1px solid yellow;">
<slot name="footer"/>
</div>
</div>
</template>
parent.vue父组件:
<template>
<div id="parentId">
父组件
<hr>
<child>
<div slot="title">标题</div>
内容
<span slot="footer"> 底部 </span>
</child>
</div>
</template>
<script>
import child from './child'
export default {
components: {
child
}
}
</script>
作用域插槽
比如 el-table中就有使用- 使用:
父组件中:接收來自子组件的值:
父组件中, 把子组件中的值,传递给父组件:<template slot-scope="scope"> scope.row.xxx </template>
<!-- row是属性的名字,传递的时候写的啥名字,就收的时候,也要写成啥名字 --> <td><slot :row="要传递的值" /></td>
- 使用:
mytable.vue子组件:
<template>
<div>
<table border="1">
<tr>
<th>名称</th>
<th>地址</th>
<th>状态</th>
</tr>
<tr v-for="(item, index) in data" :key="index">
<td>{{item.name}}</td>
<td>{{item.address}}</td>
<!-- 把遍历到这一行的数据,传递给父组件 -->
<td><slot :row="item" /></td>
</tr>
</table>
</div>
</template>
<script>
export default {
props: {
data: {
type: Array,
default: function() {
return [];
}
}
}
};
</script>
<style>
</style>
parent.vue父组件:
<template>
<div>
我是父组件
<br />
<!-- 把list传给子组件 -->
<mytable :data="list">
<template slot-scope="scope">
<span :style="{color:scope.row.status===0?'green':'red'}">
{{scope.row.status===0?'好':'坏'}}
</span>
</template>
</mytable>
</div>
</template>
<script>
import mytable from "./components/mytable";
export default {
components: {
mytable
},
data() {
return {
list: [
{ id: 1, name: "腾讯", address: "深南大道110号", status: 1 },
{ id: 2, name: "华为", address: "坂田大道220号", status: 0 },
{ id: 3, name: "大疆", address: "深圳湾120号", status: 0 }
]
};
}
};
</script>
<style>
</style>