• day08-注册功能、前端登录注册页面复制、前端登录功能、前端注册功能


    1 注册功能
    补充(开放文件夹内)
    2 前端登录注册页面复制
    4 前端注册功能

    1 注册功能

    # 分析
    	前端:携带数据格式 {mobile:,code:,password}
        后端:
        	-1 视图类---》注册方法
            -2 序列化类---》校验,保存(表中字段多,传的少---》随机,按某种格式生成---》后期修改)
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    视图类

    class UserRegisterView(GenericViewSet, CreateModelMixin):
        serializer_class = UserRegisterSerializer
    
        # @action(methods=['POST'], detail=False)
        # def register(self, request, *args, **kwargs):
        #     ser = self.get_serializer(data=request.data)
        #     ser.is_valid(raise_exception=True)
        #     ser.save()
        #     return APIResponse(msg='恭喜您注册成功')
        
        # 或者改为
        @action(methods=['POST'], detail=False)
        def register(self, request, *args, **kwargs):
            # 如果是这样做的话,内部执行serializer.data---->会走序列化----》
            # 基于create返回的user做序列化-----》按照fields = ['mobile', 'code', 'password']做序列化
            # 但是code不是表中的字段,就会报错,这个时候需要在序列化类中将其反序列化
            # 即:code = serializers.CharField(max_length=4, min_length=4, write_only=True)
            res = super().create(request, *args, **kwargs)
            return APIResponse(msg='恭喜注册成功')
            
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    序列化类

    class UserRegisterSerializer(serializers.ModelSerializer):
        # code 不是表中字段
        code = serializers.CharField(max_length=4, min_length=4, write_only=True)
    
        class Meta:
            model = User
            fields = ['mobile', 'code', 'password']
    
        def validate(self, attrs):
            # 1 校验验证码是否正确
            mobile = attrs.get('mobile')
            code = attrs.get('code')
            old_code = cache.get('cache_mobile_%s' % mobile)
            if code == old_code or code == '8888':  # 测试阶段,万能验证码
                # 2 组装数据 :username必填,但是没有,code不是表的字段
                attrs['username'] = mobile
                attrs.pop('code')
            # 3 返回
            return attrs
    
        def create(self, validated_data):  # 密码是加密的,如果重写,密码是明文的  validated_data=mobile,password,username
            user = User.objects.create_user(**validated_data)
            return user
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    补充(开放文件夹内)

    #1 为什么要写这个media才能访问
    	-django 默认是不允许前端直接访问项目某个文件夹的
        -有个static文件夹例外,需要额外配置
        -如果想让用户访问,必须配置路由,使用serve函数放开
        	path('media/', serve, {'document_root': settings.MEDIA_ROOT})
        	-浏览器中访问 meida/icon/1.png--->能把settings.MEDIA_ROOT对应的文件夹下的icon/1.png返回给前端
            path('lqz/', serve, {'document_root':os.path.join(BASE_DIR, 'lqz')})
            浏览器中访问 lqz/a.txt----->能把项目根路径下lqz对应的文件夹下的a.txt返回给前端
            
            
    # 2 配置文件中 debug作用
    	-开发阶段,都是debug为True,信息显示更丰富
        	-你访问的路由如果不存在,会把所有能访问到的路由都显示出来
            -程序出了异常,错误信息直接显示在浏览器上
            -自动重启,只要改了代码,会自动重启
        -上线阶段,肯定要改成False
        
        
    #3  ALLOWED_HOSTS 的作用
    	-只有debug 为Flase时,这个必须填
        -限制后端项目(django项目 )能够部署在哪个ip的机器上,写个 *  表示所有地址都可以
        
        
    #4 咱们的项目中,为了知道是在调试模式还是在上线模式,所以才用的debug这个字段
    	-判断,如果是开发阶段,可以有个万能验证码
        
        
        
        
    # 5 短信登录或注册接口
    	-app 只需要输入手机号和验证码,如果账号不存在,直接注册成功,并且登录成功,如果账号存在,就是登录
    	-前端传入:{mobiel,code}--->验证验证码是否正确---》拿着mobile去数据库查询,如果能查到,说明它注册过了,直接签发token返回----》如果查不到,没有注册过---》走注册逻辑完成注册---》再签发token,返回给前端
        
        -这个接口,随机生成一个6位密码,以短信形式通知用户
        -这个接口,密码为空,下次他用账号密码登录,不允许登录
        	-后续改密码:user.set_password(new_password)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    2 前端登录注册页面测试

    登录,注册,都写成组件----》在任意页面中,都能点击显示登录模态框
    写好的组件,应该放在那个组件中----》不是页面组件(小组件)
    点击登录按钮,把Login.vue 通过定位,占满全屏,透明度设为 0.5 ,纯黑色悲剧,覆盖在组件上
    在Login.vue点关闭,要把Login.vue隐藏起来,父子通信之子传父,自定义事件
    
    • 1
    • 2
    • 3
    • 4

    2.1 Header.vue

    
    <template>
      <div class="header">
        <div class="slogan">
          <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活</p>
        </div>
        <div class="nav">
          <ul class="left-part">
            <li class="logo">
              <router-link to="/">
                <img src="../assets/img/head-logo.svg" alt="">
              </router-link>
            </li>
            <li class="ele">
              <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课</span>
            </li>
            <li class="ele">
              <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课</span>
            </li>
            <li class="ele">
              <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课</span>
            </li>
          </ul>
    
          <div class="right-part">
            <div>
              <span @click="handleLogin" >登录</span>
              <span class="line">|</span>
              <span>注册</span>
            </div>
          </div>
          <Login v-if="loginShow" @close="handleClose"></Login>
        </div>
      </div>
    
    </template>
    
    <script>
    import Login from "@/components/Login";
    
    export default {
      name: "Header",
      data() {
        return {
          url_path: sessionStorage.url_path || '/',
          loginShow: false,
        }
      },
      methods: {
        goPage(url_path) {
          // 已经是当前路由就没有必要重新跳转
          if (this.url_path !== url_path) {
            this.$router.push(url_path);
          }
          sessionStorage.url_path = url_path;
        },
        handleLogin(){
          this.loginShow = true
        },
        handleClose(){
          this.loginShow = false
        }
      },
      created() {
        sessionStorage.url_path = this.$route.path;
        this.url_path = this.$route.path;
      },
      components: {
        Login
      }
    }
    </script>
    
    
    <style scoped>
    .header {
      background-color: white;
      box-shadow: 0 0 5px 0 #aaa;
    }
    
    .header:after {
      content: "";
      display: block;
      clear: both;
    }
    
    .slogan {
      background-color: #eee;
      height: 40px;
    }
    
    .slogan p {
      width: 1200px;
      margin: 0 auto;
      color: #aaa;
      font-size: 13px;
      line-height: 40px;
    }
    
    .nav {
      background-color: white;
      user-select: none;
      width: 1200px;
      margin: 0 auto;
    
    }
    
    .nav ul {
      padding: 15px 0;
      float: left;
    }
    
    .nav ul:after {
      clear: both;
      content: '';
      display: block;
    }
    
    .nav ul li {
      float: left;
    }
    
    .logo {
      margin-right: 20px;
    }
    
    .ele {
      margin: 0 20px;
    }
    
    .ele span {
      display: block;
      font: 15px/36px '微软雅黑';
      border-bottom: 2px solid transparent;
      cursor: pointer;
    }
    
    .ele span:hover {
      border-bottom-color: orange;
    }
    
    .ele span.active {
      color: orange;
      border-bottom-color: orange;
    }
    
    .right-part {
      float: right;
    }
    
    .right-part .line {
      margin: 0 10px;
    }
    
    .right-part span {
      line-height: 68px;
      cursor: pointer;
    }
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    2.2 Login.vue

    <template>
      <div class="login">
        <span @click="close">X</span>
    
      </div>
    </template>
    
    <script>
    export default {
      name: "Login",
      methods: {
        close() {
          this.$emit('close_login')
        }
      }
    
    }
    </script>
    
    <style scoped>
    .login {
      width: 100vw;
      height: 100vh;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10;
      background-color: rgba(0, 0, 0, 0.5);
    }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    3 前端登录功能

    <template>
      <div class="login">
        <div class="box">
          <i class="el-icon-close" @click="close_login">i>
          <div class="content">
            <div class="nav">
              <span :class="{active: login_method === 'is_pwd'}" @click="change_login_method('is_pwd')">密码登录span>
              <span :class="{active: login_method === 'is_sms'}" @click="change_login_method('is_sms')">短信登录span>
            div>
    
            <el-form v-if="login_method === 'is_pwd'">
              <el-input
                  placeholder="用户名/手机号/邮箱"
                  prefix-icon="el-icon-user"
                  v-model="username"
                  clearable>
              el-input>
              <el-input
                  placeholder="密码"
                  prefix-icon="el-icon-key"
                  v-model="password"
                  clearable
                  show-password>
              el-input>
              <el-button type="primary" @click="login">登录el-button>
            el-form>
    
            <el-form v-if="login_method === 'is_sms'">
              <el-input
                  placeholder="手机号"
                  prefix-icon="el-icon-phone-outline"
                  v-model="mobile"
                  clearable
                  @blur="check_mobile">
              el-input>
              <el-input
                  placeholder="验证码"
                  prefix-icon="el-icon-chat-line-round"
                  v-model="sms"
                  clearable>
                <template slot="append">
                  <span class="sms" @click="send_sms">{{ sms_interval }}span>
                template>
              el-input>
              <el-button @click="mobile_login" type="primary">登录el-button>
            el-form>
    
            <div class="foot">
              <span @click="go_register">立即注册span>
            div>
          div>
        div>
      div>
    template>
    
    <script>
    export default {
      name: "Login",
      data() {
        return {
          username: '',
          password: '',
          mobile: '',
          sms: '',  // 验证码
          login_method: 'is_pwd',
          sms_interval: '获取验证码',
          is_send: false,
        }
      },
      methods: {
        close_login() {
          this.$emit('close')
        },
        go_register() {
          this.$emit('go')
        },
        change_login_method(method) {
          this.login_method = method;
        },
        check_mobile() {
          if (!this.mobile) return;
          // js正则:/正则语法/
          // '字符串'.match(/正则语法/)
          if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
            this.$message({
              message: '手机号有误',
              type: 'warning',
              duration: 1000,
              onClose: () => {
                this.mobile = '';
              }
            });
            return false;
          }
          // 后台校验手机号是否已存在
          this.$axios({
            url: this.$settings.BASE_URL + 'user/mobile/check_mobile/?mobile=' + this.mobile,
            method: 'get',
          }).then(response => {
            if (response.data.code == 100) {
              this.$message({
                message: '账号正常,可以发送短信',
                type: 'success',
                duration: 1000,
              });
              // 发生验证码按钮才可以被点击
              this.is_send = true;
            } else {
              this.$message({
                message: '账号不存在',
                type: 'warning',
                duration: 1000,
                onClose: () => {
                  this.mobile = '';
                }
              })
            }
          }).catch(() => {
          });
        },
        send_sms() {
          // this.is_send必须允许发生验证码,才可以往下执行逻辑
          if (!this.is_send) return;
          // 按钮点一次立即禁用
          this.is_send = false;
    
          let sms_interval_time = 60;
          this.sms_interval = "发送中...";
    
          // 定时器: setInterval(fn, time, args)
          // 往后台发送验证码
          this.$axios({
            url: this.$settings.BASE_URL + 'user/mobile/send_sms/',
            method: 'post',
            data: {
              mobile: this.mobile
            }
          }).then(response => {
            if (response.data.code == 100) { // 发送成功
              let timer = setInterval(() => {
                if (sms_interval_time <= 1) {
                  clearInterval(timer);
                  this.sms_interval = "获取验证码";
                  this.is_send = true; // 重新回复点击发送功能的条件
                } else {
                  sms_interval_time -= 1;
                  this.sms_interval = `${sms_interval_time}秒后再发`;
                }
              }, 1000);
            } else {  // 发送失败
              this.sms_interval = "重新获取";
              this.is_send = true;
              this.$message({
                message: '短信发送失败',
                type: 'warning',
                duration: 3000
              });
            }
          }).catch(() => {
            this.sms_interval = "频率过快";
            this.is_send = true;
          })
    
    
        },
        login() {
          if (!(this.username && this.password)) {
            this.$message({
              message: '请填好账号密码',
              type: 'warning',
              duration: 1500
            });
            return false  // 直接结束逻辑
          }
    
          this.$axios({
            url: this.$settings.BASE_URL + 'user/login/mul_login/',
            method: 'post',
            data: {
              username: this.username,
              password: this.password,
            }
          }).then(response => {
            let username = response.data.username;
            let token = response.data.token;
            this.$cookies.set('username', username, '7d');
            this.$cookies.set('token', token, '7d');
            this.$emit('success', response.data);
          }).catch(error => {
            console.log(error.response.data)
          })
        },
        mobile_login() {
          if (!(this.mobile && this.sms)) {
            this.$message({
              message: '请填好手机与验证码',
              type: 'warning',
              duration: 1500
            });
            return false  // 直接结束逻辑
          }
    
          this.$axios({
            url: this.$settings.BASE_URL + 'user/login/sms_login/',
            method: 'post',
            data: {
              mobile: this.mobile,
              code: this.sms,
            }
          }).then(response => {
            if (response.data.code == 100) {
              let username = response.data.username;
              let token = response.data.token;
              this.$cookies.set('username', username, '7d');
              this.$cookies.set('token', token, '7d');
              this.$emit('success', response.data);
            } else {
              this.$message({
                message: '登录失败',
                type: 'warning',
                duration: 1500
              });
            }
    
          }).catch(error => {
            console.log(error.response.data)
          })
        }
      }
    }
    script>
    
    <style scoped>
    .login {
      width: 100vw;
      height: 100vh;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10;
      background-color: rgba(0, 0, 0, 0.5);
    }
    
    .box {
      width: 400px;
      height: 420px;
      background-color: white;
      border-radius: 10px;
      position: relative;
      top: calc(50vh - 210px);
      left: calc(50vw - 200px);
    }
    
    .el-icon-close {
      position: absolute;
      font-weight: bold;
      font-size: 20px;
      top: 10px;
      right: 10px;
      cursor: pointer;
    }
    
    .el-icon-close:hover {
      color: darkred;
    }
    
    .content {
      position: absolute;
      top: 40px;
      width: 280px;
      left: 60px;
    }
    
    .nav {
      font-size: 20px;
      height: 38px;
      border-bottom: 2px solid darkgrey;
    }
    
    .nav > span {
      margin: 0 20px 0 35px;
      color: darkgrey;
      user-select: none;
      cursor: pointer;
      padding-bottom: 10px;
      border-bottom: 2px solid darkgrey;
    }
    
    .nav > span.active {
      color: black;
      border-bottom: 3px solid black;
      padding-bottom: 9px;
    }
    
    .el-input, .el-button {
      margin-top: 40px;
    }
    
    .el-button {
      width: 100%;
      font-size: 18px;
    }
    
    .foot > span {
      float: right;
      margin-top: 20px;
      color: orange;
      cursor: pointer;
    }
    
    .sms {
      color: orange;
      cursor: pointer;
      display: inline-block;
      width: 70px;
      text-align: center;
      user-select: none;
    }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320

    4 前端注册功能

    <template>
      <div class="register">
        <div class="box">
          <i class="el-icon-close" @click="close_register">i>
          <div class="content">
            <div class="nav">
              <span class="active">新用户注册span>
            div>
            <el-form>
              <el-input
                  placeholder="手机号"
                  prefix-icon="el-icon-phone-outline"
                  v-model="mobile"
                  clearable
                  @blur="check_mobile">
              el-input>
              <el-input
                  placeholder="密码"
                  prefix-icon="el-icon-key"
                  v-model="password"
                  clearable
                  show-password>
              el-input>
              <el-input
                  placeholder="验证码"
                  prefix-icon="el-icon-chat-line-round"
                  v-model="sms"
                  clearable>
                <template slot="append">
                  <span class="sms" @click="send_sms">{{ sms_interval }}span>
                template>
              el-input>
              <el-button @click="register" type="primary">注册el-button>
            el-form>
            <div class="foot">
              <span @click="go_login">立即登录span>
            div>
          div>
        div>
      div>
    template>
    
    <script>
    export default {
      name: "Register",
      data() {
        return {
          mobile: '',
          password: '',
          sms: '',
          sms_interval: '获取验证码',
          is_send: false,
        }
      },
      methods: {
        close_register() {
          this.$emit('close', false)
        },
        go_login() {
          this.$emit('go')
        },
        check_mobile() {
          if (!this.mobile) return;
          // js正则:/正则语法/
          // '字符串'.match(/正则语法/)
          if (!this.mobile.match(/^1[3-9][0-9]{9}$/)) {
            this.$message({
              message: '手机号有误',
              type: 'warning',
              duration: 1000,
              onClose: () => {
                this.mobile = '';
              }
            });
            return false;
          }
          // 后台校验手机号是否已存在
          this.$axios({
            url: this.$settings.BASE_URL + 'user/mobile/check_mobile/?mobile='+this.mobile,
            method: 'get',
          }).then(response => {
            if (response.data.code!=100) {
              this.$message({
                message: '欢迎注册我们的平台',
                type: 'success',
                duration: 1500,
              });
              // 发生验证码按钮才可以被点击
              this.is_send = true;
            } else {
              this.$message({
                message: '账号已存在,请直接登录',
                type: 'warning',
                duration: 1500,
              })
            }
          }).catch(() => {
          });
        },
        send_sms() {
          // this.is_send必须允许发生验证码,才可以往下执行逻辑
          if (!this.is_send) return;
          // 按钮点一次立即禁用
          this.is_send = false;
    
          let sms_interval_time = 60;
          this.sms_interval = "发送中...";
    
          // 定时器: setInterval(fn, time, args)
    
          // 往后台发送验证码
          this.$axios({
            url: this.$settings.BASE_URL + 'user/mobile/send_sms/',
            method: 'post',
            data: {
              mobile: this.mobile
            }
          }).then(response => {
            if (response.data.code==100) { // 发送成功
              let timer = setInterval(() => {
                if (sms_interval_time <= 1) {
                  clearInterval(timer);
                  this.sms_interval = "获取验证码";
                  this.is_send = true; // 重新回复点击发送功能的条件
                } else {
                  sms_interval_time -= 1;
                  this.sms_interval = `${sms_interval_time}秒后再发`;
                }
              }, 1000);
            } else {  // 发送失败
              this.sms_interval = "重新获取";
              this.is_send = true;
              this.$message({
                message: '短信发送失败',
                type: 'warning',
                duration: 3000
              });
            }
          }).catch(() => {
            this.sms_interval = "频率过快";
            this.is_send = true;
          })
    
    
        },
        register() {
          if (!(this.mobile && this.sms && this.password)) {
            this.$message({
              message: '请填好手机、密码与验证码',
              type: 'warning',
              duration: 1500
            });
            return false  // 直接结束逻辑
          }
    
          this.$axios({
            url: this.$settings.BASE_URL + 'user/register/register/',
            method: 'post',
            data: {
              mobile: this.mobile,
              code: this.sms,
              password: this.password
            }
          }).then(response => {
            this.$message({
              message: '注册成功,3秒跳转登录页面',
              type: 'success',
              duration: 3000,
              showClose: true,
              onClose: () => {
                // 去向成功页面
                this.$emit('success')
              }
            });
          }).catch(error => {
            this.$message({
              message: '注册失败,请重新注册',
              type: 'warning',
              duration: 1500,
              showClose: true,
              onClose: () => {
                // 清空所有输入框
                this.mobile = '';
                this.password = '';
                this.sms = '';
              }
            });
          })
        }
      }
    }
    script>
    
    <style scoped>
    .register {
      width: 100vw;
      height: 100vh;
      position: fixed;
      top: 0;
      left: 0;
      z-index: 10;
      background-color: rgba(0, 0, 0, 0.3);
    }
    
    .box {
      width: 400px;
      height: 480px;
      background-color: white;
      border-radius: 10px;
      position: relative;
      top: calc(50vh - 240px);
      left: calc(50vw - 200px);
    }
    
    .el-icon-close {
      position: absolute;
      font-weight: bold;
      font-size: 20px;
      top: 10px;
      right: 10px;
      cursor: pointer;
    }
    
    .el-icon-close:hover {
      color: darkred;
    }
    
    .content {
      position: absolute;
      top: 40px;
      width: 280px;
      left: 60px;
    }
    
    .nav {
      font-size: 20px;
      height: 38px;
      border-bottom: 2px solid darkgrey;
    }
    
    .nav > span {
      margin-left: 90px;
      color: darkgrey;
      user-select: none;
      cursor: pointer;
      padding-bottom: 10px;
      border-bottom: 2px solid darkgrey;
    }
    
    .nav > span.active {
      color: black;
      border-bottom: 3px solid black;
      padding-bottom: 9px;
    }
    
    .el-input, .el-button {
      margin-top: 40px;
    }
    
    .el-button {
      width: 100%;
      font-size: 18px;
    }
    
    .foot > span {
      float: right;
      margin-top: 20px;
      color: orange;
      cursor: pointer;
    }
    
    .sms {
      color: orange;
      cursor: pointer;
      display: inline-block;
      width: 70px;
      text-align: center;
      user-select: none;
    }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281

    Header.vue

    <template>
      <div class="header">
        <div class="slogan">
          <p>老男孩IT教育 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活p>
        div>
        <div class="nav">
          <ul class="left-part">
            <li class="logo">
              <router-link to="/">
                <img src="../assets/img/head-logo.svg" alt="">
              router-link>
            li>
            <li class="ele">
              <span @click="goPage('/free-course')" :class="{active: url_path === '/free-course'}">免费课span>
            li>
            <li class="ele">
              <span @click="goPage('/actual-course')" :class="{active: url_path === '/actual-course'}">实战课span>
            li>
            <li class="ele">
              <span @click="goPage('/light-course')" :class="{active: url_path === '/light-course'}">轻课span>
            li>
          ul>
    
          <div class="right-part">
            <div v-if="!username">
              <span @click="handleLogin">登录span>
              <span class="line">|span>
              <span @click="handleRegister">注册span>
            div>
            <div v-else>
              <span>{{ username }}span>
              <span class="line">|span>
              <span @click="logOut">注销span>
            div>
          div>
          <Login v-if="loginShow" @close="handleClose" @success="success_login" @go="go_register">Login>
          <Register v-if="registerShow" @close="handleRegisterClose" @success="success_register"
                    @go="success_register">Register>
        div>
      div>
    
    template>
    <script>
    import Login from "@/components/Login.vue";
    import Register from "@/components/Register.vue";
    
    export default {
      name: "Header",
      data() {
        return {
          url_path: sessionStorage.url_path || '/',
          loginShow: false,
          registerShow: false,
          username: '',
          token: ''
        }
      },
      methods: {
        handleRegister() {
          this.registerShow = true
        },
        handleRegisterClose() {
          this.registerShow = false
        },
        success_register() {
          this.registerShow = false
          this.loginShow = true
        },
        go_register() {
          this.registerShow = true
          this.loginShow = false
        },
        logOut() {
          this.username = ''
          this.token = ''
          this.$cookies.remove('username')
          this.$cookies.remove('token')
        },
        goPage(url_path) {
          // 已经是当前路由就没有必要重新跳转
          if (this.url_path !== url_path) {
            this.$router.push(url_path);
          }
          sessionStorage.url_path = url_path;
        },
        handleLogin() {
          this.loginShow = true
        },
        handleClose() {
          this.loginShow = false
    
        },
        success_login(data) {
          this.loginShow = false;  // 模态框消耗
          this.username = data.username;
          this.token = data.token;
        }
      },
      created() {
        sessionStorage.url_path = this.$route.path;
        this.url_path = this.$route.path;
        this.username = this.$cookies.get('username')
      },
      components: {
        Register,
        Login
      }
    }
    script>
    
    
    <style scoped>
    .header {
      background-color: white;
      box-shadow: 0 0 5px 0 #aaa;
    }
    
    .header:after {
      content: "";
      display: block;
      clear: both;
    }
    
    .slogan {
      background-color: #eee;
      height: 40px;
    }
    
    .slogan p {
      width: 1200px;
      margin: 0 auto;
      color: #aaa;
      font-size: 13px;
      line-height: 40px;
    }
    
    .nav {
      background-color: white;
      user-select: none;
      width: 1200px;
      margin: 0 auto;
    
    }
    
    .nav ul {
      padding: 15px 0;
      float: left;
    }
    
    .nav ul:after {
      clear: both;
      content: '';
      display: block;
    }
    
    .nav ul li {
      float: left;
    }
    
    .logo {
      margin-right: 20px;
    }
    
    .ele {
      margin: 0 20px;
    }
    
    .ele span {
      display: block;
      font: 15px/36px '微软雅黑';
      border-bottom: 2px solid transparent;
      cursor: pointer;
    }
    
    .ele span:hover {
      border-bottom-color: orange;
    }
    
    .ele span.active {
      color: orange;
      border-bottom-color: orange;
    }
    
    .right-part {
      float: right;
    }
    
    .right-part .line {
      margin: 0 10px;
    }
    
    .right-part span {
      line-height: 68px;
      cursor: pointer;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
  • 相关阅读:
    LLM 大模型学习必知必会系列(三):LLM和多模态模型高效推理实践
    Kubernetes概述架构与工作流程简述
    NPOI导出千分位带.00格式显示
    安全关键软件开发与审定——DO-178C标准实践指南阅读笔记四——DO-178C及支持文件概览
    Python——私有化和动态添加属性和方法、Property、new和slots方法、单例、异常处理(day09)
    Java lambda 动态查询
    【R语言数据科学】:变量选择(二)Lasso回归
    揭秘华为云GaussDB(for Influx)最佳实践:hint查询
    在优化问题里,强化学习相比启发式算法有什么好处?
    [附源码]计算机毕业设计JAVA车辆违章信息管理系统
  • 原文地址:https://blog.csdn.net/weixin_44145338/article/details/133861216