仿美团pc,koa+ssr(二)
一,注册和登录功能
pages-->新建register.vue 注册组件
注:md5加密,crypto-js加密库
<template> <div class="page-register"> <article class="header"> <header> <a href="/" class="site-logo" /> <span class="login"> <em class="bold">已有美团账号?</em> <a href="/login"> <el-button type="primary" size="small">登录</el-button> </a> </span> </header> </article> <!-- 注册页 --> <section> <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="100px" class="demo-ruleForm"> <el-form-item label="昵称" prop="name"> <el-input v-model="ruleForm.name" /> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="ruleForm.email" /> <el-button size="mini" round @click="sendMsg">发送验证码</el-button> <!-- 提示错误信息 --> <span class="status">{{ statusMsg }}</span> </el-form-item> <el-form-item label="验证码" prop="code"> <el-input v-model="ruleForm.code" maxlength="4" /> </el-form-item> <el-form-item label="密码" prop="pwd"> <el-input v-model="ruleForm.pwd" type="password" /> </el-form-item> <el-form-item label="确认密码" prop="cpwd"> <el-input v-model="ruleForm.cpwd" type="password" /> </el-form-item> <el-form-item> <el-button type="primary" @click="register">同意以下协议并注册</el-button> <!-- 错误提示 --> <div class="error">{{ error }}</div> </el-form-item> <el-form-item> <a class="f1" href="http://www.meituan.com/about/terms" target="_blank">《美团网用户协议》</a> </el-form-item> </el-form> </section> </div> </template> <script> import CryptoJS from 'crypto-js' export default { data() { return { statusMsg: '', error: '', ruleForm: { name: '', code: '', pwd: '', cpwd: '', email: '' }, // 验证规则属性 rules: { name: [{ required: true, type: 'string', message: '请输入昵称', trigger: 'blur' }], email: [{ required: true, type: 'email', message: '请输入邮箱', trigger: 'blur' }], pwd: [{ required: true, message: '创建密码', trigger: 'blur' }], cpwd: [{ required: true, message: '确认密码', trigger: 'blur' }, { // 自定义验证规则 validator: (rule, value, callback) => { if (value === '') { callback(new Error('请再次输入密码')) } else if (value !== this.ruleForm.pwd) { callback(new Error('两次输入密码不一致')) } else { callback() } }, trigger: 'blur' }] } } }, // 公用模板组件 layout: 'blank', methods: { // 点击发送验证码 sendMsg: function () { const self = this; let namePass let emailPass if (self.timerid) { return false } this.$refs['ruleForm'].validateField('name', (valid) => { namePass = valid }) self.statusMsg = '' if (namePass) { return false } this.$refs['ruleForm'].validateField('email', (valid) => { emailPass = valid }) // 验证成功,发送验证码请求 if (!namePass && !emailPass) { self.$axios.post('/users/verify', { // 中文编码 username: encodeURIComponent(self.ruleForm.name), email: self.ruleForm.email }).then(({ status, data }) => { if (status === 200 && data && data.code === 0) { let count = 60; self.statusMsg = `验证码已发送,剩余${count--}秒` self.timerid = setInterval(function () { self.statusMsg = `验证码已发送,剩余${count--}秒` if (count === 0) { clearInterval(self.timerid) } }, 1000) } else { self.statusMsg = data.msg } }) } }, // 点击注册按钮 register: function () { let self = this; // 验证全部通过,发送注册请求 this.$refs['ruleForm'].validate((valid) => { if (valid) { self.$axios.post('/users/signup', { username: window.encodeURIComponent(self.ruleForm.name), // md5加密 password: CryptoJS.MD5(self.ruleForm.pwd).toString(), email: self.ruleForm.email, code: self.ruleForm.code }).then(({ status, data }) => { if (status === 200) { if (data && data.code === 0) { // 强制跳转到登录页 location.href = '/login' } else { self.error = data.msg } } else { self.error = `服务器出错,错误码:${status}` } setTimeout(function () { self.error = '' }, 1500) }) } }) } } } </script> <style lang="scss"> @import "@/assets/css/register/index.scss"; </style>
layout-->新建blank.vue模板
<template> <div class="layout-blank"> <nuxt/> </div> </template> <script> export default { } </script> <style lang="css"> </style>
pages-->新建login.vue 登录组件,服务端已做了本地化持久存储功能,前端不需要做
<template> <div class="page-login"> <div class="login-header"> <a href="/" class="logo"/> </div> <div class="login-panel"> <div class="banner"> <img src="//s0.meituan.net/bs/file/?f=fe-sso-fs:build/page/static/banner/www.jpg" width="480" height="370" alt="美团网"> </div> <div class="form"> <h4 v-if="error" class="tips"><i/>{{ error }}</h4> <p><span>账号登录</span></p> <el-input v-model="username" prefix-icon="profile"/> <el-input v-model="password" prefix-icon="password" type="password"/> <div class="foot"> <el-checkbox v-model="checked">7天内自动登录</el-checkbox> <b>忘记密码?</b> </div> <el-button class="btn-login" type="success" size="mini" @click="login">登录</el-button> </div> </div> </div> </template> <script> import CryptoJS from 'crypto-js' export default { data: () => { return { checked: '', username: '', password: '', error: '' } }, layout: 'blank', methods: { login: function () { let self=this; self.$axios.post('/users/signin',{ username:window.encodeURIComponent(self.username), password:CryptoJS.MD5(self.password).toString() }).then(({status,data})=>{ if(status===200){ if(data&&data.code===0){ location.href='/' }else{ self.error=data.msg } }else{ self.error=`服务器出错` } }) } } } </script> <style lang="scss"> @import "@/assets/css/login/index.scss"; </style>
components->public->header->user.vue,顶部组件用户信息改造
<template> <div class="m-user"> <template v-if="user"> 欢迎您,<span class="username">{{ user }}</span> [<nuxt-link to="/exit">退出</nuxt-link>] </template> <template v-else> <nuxt-link to="/login" class="login">立即登录</nuxt-link> <nuxt-link class="register" to="/register">注册</nuxt-link> </template> </div> </template> <script> export default { data(){ return { user:'' } }, async mounted(){ const {status,data:{user}} = await this.$axios.get('/users/getUser') if(status===200){ this.user=user } } } </script> <style lang="css"> </style>
pages->新建exit.vue组件,退出功能
<template> <div class=""/> </template> <script> export default { layout: 'blank', // 利用中间件,到达页面自动执行以下逻辑 middleware: async (ctx) => { let {status,data}=await ctx.$axios.get('/users/exit') if(status===200&&data&&data.code===0){ window.location.href='/' } } } </script>