仿写网易云-项目初始化-扫描二维码登录

仿写网易云-项目初始化-扫描二维码登录

  • 1. 项目初始化
  • 2. 安装使用 Element UI
  • 3. 设置一下页面的布局
  • 4. 开始写 Header
  • 5. 点击未登录弹出登录窗口
    • 5.1 原理分析
    • 5.2 扫码登录 LoginByScanCode 组件
      • 5.2.1 组件UI 样式
      • 5.2.2 函数的封装
      • 5.2.3 页面功能逻辑

1. 项目初始化

仿写网易云-项目初始化-扫描二维码登录_第1张图片

2. 安装使用 Element UI

这里使用的是全部引入,比较方便

  • 安装 element ui :npm i element-ui -S

    全部引入 在 main.js 中添加下面的代码

    • //  element ui
      import ElementUI from 'element-ui'
      import 'element-ui/lib/theme-chalk/index.css'
      Vue.use(ElementUI)
      

    按需引入

  • 安装 babel-plugin-componentnpm install babel-plugin-component -D

  • 修改 babel.config.js 文件:

    module.exports = {
      presets: [
        '@vue/cli-plugin-babel/preset',
        ['@babel/preset-env', { modules: false }]
      ],
      plugins: [
        [
          'component',
          {
            libraryName: 'element-ui',
            styleLibraryName: 'theme-chalk'
          }
        ]
      ]
    }
    
    
  • 按需引入使用案例,在 main.js

    //  element ui
    import { Button, Select } from 'element-ui'
    
    Vue.component(Button)
    Vue.component(Select)
    

3. 设置一下页面的布局

  • Header
  • Footer
  • Side
  • Main

4. 开始写 Header

头部导航

  • 左边的 HeaderLogo
  • 中间的搜索框 HeaderSearch
  • 右边的头像昵称(登录状态)或显示未登录 HeaderRight

5. 点击未登录弹出登录窗口

5.1 原理分析

主要用到 Element 组件的 Dialog对话框

参考了这篇博客: vue之登录弹框Dialog对话框实现

但是这里与此篇博客不同在于,这个弹窗有三个页面

(所以需要用到路由Router来进行切换):

  • 扫码登录
  • 电话号码登录
  • 注册
    仿写网易云-项目初始化-扫描二维码登录_第2张图片
  • Dialog 的使用

    • 官方使用文档:
    • el-dialog 设置一个居中和宽度
    • 在弹出框 el-dialog 中加入一个占位符 router-view 根据不同路径渲染不同组件
    • 未登录字眼链接默认跳转 /logincode,也就是扫描二维码登录
     <el-button class="noLogin" type="text" @click="loginVisible = true">
         <router-link class="noLoginA" to="/logincode">未登录 router-link>
         <i class="el-icon-caret-bottom">i>
    el-button>
    <el-dialog :visible.sync="loginVisible" center :append-to-body='true' :lock-scroll="false" width="350px">
        <router-view>router-view>
    el-dialog>
    
    data () {
        return {
            loginVisible: false
        }
    }
    
  • 路由使用步骤

    1. 占位符

    2. router/index.js 引入组件,配置跳转路径对应的组件

      import LoginByScanCode from '@/components/Header/User/LoginByScanCode.vue'
      import LoginByPhoneNumber from '@/components/Header/User/LoginByPhoneNumber.vue'
      import RegisterByPhoneNumber from '@/components/Header/User/RegisterByPhoneNumber.vue'
      
      const routes = [
        {path: '/logincode',component: LoginByScanCode},
        {path: '/loginphone',component: LoginByPhoneNumber},
        {path: '/register',component: RegisterByPhoneNumber}
      ]
      
    3. 页面中根据需要使用

  • /logincode 通过扫描二维码登录 LoginByScanCode

  • /loginphone 通过验证手机和手机密码登录 LoginByPhoneNumber

  • /register 注册新账号 RegisterByPhoneNumber

5.2 扫码登录 LoginByScanCode 组件

5.2.1 组件UI 样式

仿写网易云-项目初始化-扫描二维码登录_第3张图片
仿写网易云-项目初始化-扫描二维码登录_第4张图片

HTML 结构

<template>
  <div id="login-code-container">
    <p class="title">扫码登录p>
    <div class="main-outer">
      <div class="left-img-outer">
        <img id="left-img" src="@/assets/images/left-img.png">
      div>
      <div class="right-code-outer">
        <div id="right-code">
          <img :src="QRBase64">
          <div class="code-invalid" v-if="codeIsValid === false">
            <p>二维码已失效p>
            <h5><el-button type="primary" size="mini" @click="afreshGetQR()">点击刷新el-button>h5>
          div>
          <div class="code-loading" v-if="codeIsLoading === true">
            <p><i class="el-icon-loading">i>p>
            <p>登录中...... p>
          div>
        div>
        <p>使用<a href="https://music.163.com/#/download">PT音乐a>APP版本扫码登录p>
      div>
    div>
    <router-link to="/loginphone" class="other-way">选择其他登录模式 >router-link>
  div>
template>

CSS 样式


5.2.2 函数的封装

因为需要使用 axios ,在 src 目录下 utils/request.js 引入 axios,并且设置请求根路径

import axios from 'axios'

// 调用 axios.create() 函数,创建一个 axios 的实例对象,用 request 来接收
const request = axios.create({
  // 指定请求的根路径
  baseURL: 'http://127.0.0.1:3000'
})

export default request

在在 src 目录下创建 api ,用来封装函数

  • api/LoginAndReguster/loginByCode.js 放扫码登录相关的请求
  • api/user/user.js 放与用户账户相关的请求
// 注册相关的 API 接口
import request from '@/utils/request.js'

// 每次请求都带上时间戳 timestamp 参数  防止缓存
// withCredentials 请求为跨域类型时是否在请求中协带cookie

// 获得 QR 的 key
export const getLoginQRKey = function () {
  return request.get('/login/qr/key', {
    params: {
      timestamp: new Date().getTime(),
      withCredentials: true
    }
  })
}

// 传入 key 生成二维码图片的 base64 和二维码信息
export const getLoginQR = function (key) {
  return request.get('/login/qr/create', {
    params: {
      key: key,
      qrimg: true,
      timestamp: new Date().getTime(),
      withCredentials: true
    }
  })
}

// 获取登录信息
export const getLoginStatus = function () {
  return request.get('/login/status', {
    params: {
      timestamp: new Date().getTime(),
      withCredentials: true
    }
  })
}

// 带上key 检查二维码是否过期
export const checkStatus = function (key) {
  return request.get('/login/qr/check', {
    params: {
      key: key,
      timestamp: new Date().getTime(),
      withCredentials: true
    }
  })
}

import request from '@/utils/request.js'

// 获取用户信息
export const getUserAccount = function (cookier) {
  return request.get('/user/account', {
    params: {
      cookie: cookier,
      timestamp: new Date().getTime(),
      withCredentials: true
    }
  })
}

5.2.3 页面功能逻辑

写在前面:感觉整个页面逻辑确实没有什么问题,但是在扫描成功确认登录后再次去访问登录状态时还是没有登录,根据登录成功返回的 cookie 带着再去访问账号信息时还是得不到账号信息,对比官方文档给出的案例感觉并无差别,但是官方的案例登陆之后给浏览器设置了cookie,而我的登录成功之后浏览器并没有被设置cookie,导致检查状态一直是未登录。不知道该如何解决。如果有哪位大佬知道原因,还麻烦指点我一下。

getLoginQRImg函数

  • getLoginQRKey 获取二维码的 key

  • getLoginQR 获取二维码的信息和 base64 格式的编码,可以直接作为 img 的src渲染到页面上

  • 使用 setInterval创建定时器 timer,间隔 3000ms 便访问一次二维码的状态,根据不同的状态渲染页面样式

    • code === 800 二维码已经失效,渲染失效样式的DOM,并且清理 timer
    • code === 802 正在等待确认中,渲染登录中的样式
    • code === 803登录成功,返回 cookie,,并且清理 timer
  • afreshGetQR 函数 当二维码失效的时候点击点击刷新的时候重新调用 getLoginQRImg函数

  • getLoginQRImg函数放在 created组件周期时

  • 但是这里有一个问题,点击 Dialog 的关闭按钮的时候,timer 没有被清除,所以需要监听 Dialog 的状态,父组件中有一个 loginVisible,当Dialog 关闭时为 false,打开时为 true。需要将此变量传递给子组件:

    • 父组件中的占位符bind绑定变量给子组件:

      <router-view :loginVisible="loginVisible">router-view>
      
    • 子组件使用 props 接收,设置一个默认值 false:

      props: {
          loginVisible: {
              type: Boolean,
              default: false
          }
      }
      
  • 在进入定时器 timer 的时候判断该值,如果位false则清除定时器,达到关闭Dialog 同时清除timer的作用。

// 导入获取 key 和 QR 的 API
import { getLoginQRKey, getLoginQR, getLoginStatus, checkStatus } from '@/api/LoginAndRegister/loginByQR.js'
// 导入 user.js
import { getUserAccount } from '@/api/user/user.js'

export default {
  props: {
    loginVisible: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      codeIsValid: true,
      codeIsLoading: false,
      QRkey: '',
      QRBase64: '',
      cookier: ''
    }
  },
  methods: {
    // 获取登录二维码
    async getLoginQRImg () {
      // 获取 key
      const { data: dataKeyObj } = await getLoginQRKey()
      const keyObj = dataKeyObj.data
      this.QRkey = keyObj.unikey
      console.log('二维码的key:', keyObj.unikey)

      // 获取 二维码
      const { data: dataQRObj } = await getLoginQR(this.QRkey)
      const QRObj = dataQRObj.data
      this.QRBase64 = QRObj.qrimg
      console.log('二维码base64格式:', QRObj.qrimg)

      // 循环判断二维码是否过期  是否已经登录
      const timer = setInterval(async () => {
        // loginVisible 为 true 时定时器才有效
        // 当 dialog 被删除时 定时器被消除
        if (this.loginVisible === false) {
          clearInterval(timer)
        }
        const { data: keyStatus } = await checkStatus(this.QRkey)
        console.log(keyStatus)
        if (keyStatus.code === 800) {
          // 二维码过期
          console.log('二维码已失效')
          this.codeIsLoading = false
          clearInterval(timer)
          this.codeIsValid = false
        } else if (keyStatus.code === 802) {
          // 授权登录中
          console.log('授权登录中...')
          this.codeIsLoading = true
        } else if (keyStatus.code === 803) {
          this.codeIsLoading = false
          // 登录成功 会返回 cookie
          console.log('登录成功')
          clearInterval(timer)
          const { data: loginStatus } = await getLoginStatus()
          console.log(loginStatus)
          this.cookier = keyStatus.cookie
          const { data: userAccount } = await getUserAccount(this.cookier)
          console.log(userAccount)
        }
      }, 3000)
    },
    // 重新获取二维码
    afreshGetQR () {
      console.log('重新获取二维码')
      this.getLoginQRImg()
      this.codeIsValid = true
    }
  },
  created () {
    this.getLoginQRImg()
  }
}

你可能感兴趣的:(项目,前端,vue.js,学习)