如何使用 Vue + webSocket 实现超简单的二维码登录和弹幕效果

1,635 阅读2分钟

image.png 这两天心血来潮,上 codepen 看到了一个超炫酷的一个RGB炫彩效果,想来能不能拿来做点什么,刚好在研究webSocket,想来拿来写一个弹幕或者聊天室也是极好的,所以心动不如行动,咱们开始吧

首先感谢 codepen 上的 Gayane 大佬的布局和 css3 动画,有兴趣的可以给大佬捧捧场

codepen.io/gayane-gasp…

首先介绍下会用到的一些东西

使用的框架是 Vue@2.6

生成二维码的是 npm 的 arale-qrcode 第三方包 www.npmjs.com/package/ara…

后端的 webSocket 使用的是 npm 的 ws 第三方包 www.npmjs.com/package/ws

相关 API 我就不在这里赘述了,各位大佬肯定比我这个萌新要厉害的多,那么开始正题吧

首先是登录页面的布局

<template>
  <div class="loginContainer">
    <div class="card" @click="showQrcode">
      <div v-if="!hasLogin">
        <div v-if="isShow">加入属于你的弹幕世界吧</div>
        <div v-else class="qrcode"></div>
      </div>
      <div v-else class="qrcode">登录成功</div>
    </div>
  </div>
</template>

登录页面的样式使用的是 less

<style lang="less">
.loginContainer {
  position: relative;
  padding: 50px;
}

.title {
  display: flex;
  justify-content: center;
  position: absolute;
  color: #fff;
  text-align: center;
  z-index: 999;
}

@property --rotate {
  syntax: '<angle>';
  initial-value: 132deg;
  inherits: false;
}

:root {
  --card-height: 65vh;
  --card-width: calc(var(--card-height) / 1.5);
}

body {
  min-height: 100vh;
  background: #212534;
  display: flex;
  align-items: center;
  flex-direction: column;
  padding-top: 2rem;
  padding-bottom: 2rem;
  box-sizing: border-box;
}

.card {
  background: #191c29;
  width: var(--card-width);
  height: var(--card-height);
  padding: 3px;
  position: relative;
  border-radius: 6px;
  justify-content: center;
  align-items: center;
  text-align: center;
  display: flex;
  font-size: 1.5em;
  color: rgb(88 199 250 / 0%);
  cursor: pointer;
  font-family: cursive;
}

.card:hover {
  color: rgb(88 199 250 / 100%);
  transition: color 1s;
  color: #fff;
}
.card:hover:before,
.card:hover:after {
  animation: none;
  opacity: 0;
}

.card::before {
  content: '';
  width: 104%;
  height: 102%;
  border-radius: 8px;
  background-image: linear-gradient(
    var(--rotate),
    #5ddcff,
    #3c67e3 43%,
    #4e00c2
  );
  position: absolute;
  z-index: -1;
  top: -1%;
  left: -2%;
  animation: spin 2.5s linear infinite;
}

.card::after {
  position: absolute;
  content: '';
  top: calc(var(--card-height) / 6);
  left: 0;
  right: 0;
  z-index: -1;
  height: 100%;
  width: 100%;
  margin: 0 auto;
  transform: scale(0.8);
  filter: blur(calc(var(--card-height) / 6));
  background-image: linear-gradient(
    var(--rotate),
    #5ddcff,
    #3c67e3 43%,
    #4e00c2
  );
  opacity: 1;
  transition: opacity 0.5s;
  animation: spin 2.5s linear infinite;
}

@keyframes spin {
  0% {
    --rotate: 0deg;
  }
  100% {
    --rotate: 360deg;
  }
}

a {
  color: #212534;
  text-decoration: none;
  font-family: sans-serif;
  font-weight: bold;
  margin-top: 2rem;
}
</style>

注意:Gayane 大佬使用的是原生 css ,没有使用任何的预加载器(大佬还得是大佬啊)

非常简单的登录逻辑

<script>
// 导入二维码生成器
import AraleQrcode from 'arale-qrcode'

export default {
  name: 'BulletScreenQrcodeLogin',

  data () {
    return {
      // 显示 title
      isShow: true,
      // 是否准备登录
      hasLogin: false,
      // webSocket 预定义变量
      ws: null
    }
  },
  // 调用钩子在组件销毁时关闭链接
  beforeDestroy () {
    this.ws.close()
    this.ws = null
  },

  methods: {
    // 显示登录二维码
    async showQrcode () {
      this.isShow = !this.isShow
      // 这里使用的本地服务
      this.ws = new WebSocket('ws://localhost:8080')
      this.ws.onopen = (res) => {
        console.log(res.data)
      }
      // 收到来自 webSocket 信息的时候
      this.ws.onmessage = (res) => {
        if (JSON.parse(res.data).code === 1) {
          // 是否已经扫码登录
          this.hasLogin = true
          this.isShow = false
          // 关闭链接
          this.ws.close()
          // 跳转至弹幕页面
          this.$router.push('/')
        }
      }
      if (!this.isShow) {
        const getQrcode = () => {
          return new Promise((resolve, reject) => {
            // 生成二维码
            const qrcode = new AraleQrcode({
              // 这里是二维码的扫描地址,注意如果不加域名扫描后不会发生跳转
              text: 'http:/localhost:3000/api/login',
              size: 150,
              correctLevel: 3
            })
            resolve(qrcode)
          })
        }
        const qrResult = await getQrcode()
        // 讲二维码添加至页面
        document.querySelector('.qrcode').appendChild(qrResult)
      }
    }
  }
}
</script>

当然在实际工作中二维码登录的业务逻辑肯定没有这么简单,这次也只是一个小 Demo,没有做各种逻辑上的优化,仅仅只是展示或者针对初次了解业务的小伙伴入个门儿,如果小伙伴们喜欢的话我可以再出一期二维码登录的详细逻辑及相关加密方式哟

然后是弹幕展示页面

首先是布局

<template>
  <div class="menu">
    <div class="container">
      <div class="bulletList">
        <div
          class="bulletItem"
          v-for="(item, index) in bulletList"
          :key="index"
        >
          {{ item }}
        </div>
      </div>
      <div class="bullet">
        <input type="text" v-model="bullet" placeholder="请输入您的弹幕" />
        <button class="btn" @click="subBullet">发送</button>
      </div>
    </div>
  </div>
</template>

其次是样式

<style lang="less" scoped>
.menu {
  width: 100%;
  height: 100%;
  background-color: #212534;
  .container {
    .bullet {
      position: absolute;
      left: 50%;
      top: 620px;
      transform: translate(-57.3%, 0);
      width: 700px;
      z-index: 999;

      input {
        width: 100%;
        height: 30px;
        background-color: rgba(0, 0, 0, 0.2);
        outline: none;
        border: none;
        border-radius: 5px;
        padding-left: 20px;
        color: #fff;
      }
    }
    &::after {
      content: '';
      position: absolute;
      top: 100px;
      left: 50%;
      transform: translate(-50%, 0);
      width: 800px;
      height: 500px;
      background-color: rgba(255, 255, 255, 0.2);
      opacity: 0.2;
      box-shadow: 0 0 10px 3px;
      z-index: 1;
    }
  }
  .btn {
    position: absolute;
    top: 0;
    right: -85px;
    width: 50px;
    height: 30px;
    border: none;
    color: #fff;
    box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.2);
    background-color: #2a2e3c;
    border-radius: 5px;
    cursor: pointer;
  }
}
.bulletList {
  position: absolute;
  top: 110px;
  left: 1370px;
}

.bulletItem {
  // position: absolute;
  // top: 0;
  // left: 0;
  padding: 0 10px;
  height: 30px;
  line-height: 30px;
  text-align: center;
  border: 1px solid #212534;
  color: #fff;
  box-shadow: 0 0 5px 3px rgba(255, 255, 255, 0.2);
  animation: toLeft 3s linear forwards;
}
@keyframes toLeft {
  to {
    transform: translate(-1900px);
  }
}

最后就是新增弹幕和显示弹幕的简单逻辑

<script>
export default {
  name: 'BulletScreenQrcodeMenu',

  data () {
    return {
      // 双绑的内容
      bullet: '',
      // 弹幕列表
      bulletList: [],
      // 你懂的
      ws: null
    }
  },

  // 调用钩子在加载的时候进行链接
  mounted () {
    this.ws = new WebSocket('ws://localhost:6060')
    this.ws.onmessage = (res) => {
      if (JSON.parse(res.data).code === 3) {
        this.bulletList.push(JSON.parse(res.data).message)
      }
    }
  },
  // 调用钩子在组件销毁的时候断开链接
  beforeDestroy () {
    this.ws.close()
    this.ws = null
  },

  methods: {
    // 添加弹幕的相关逻辑
    async subBullet () {
      // 向后台发起请求
      const res = await this.axios.post('http://localhost:3000/api/addBullet', {
        bull: this.bullet
      })
      console.log(res)
    }
  }
}
</script>

这里的逻辑都相当简单,也只是做一个展示,并且让小伙伴们了解到其实学习并没有那么的难

最后的成品就是这个样子

登录

1646739125829.png

弹幕展示界面

1646739156997.png

后端

后端是使用 express 框架 + ws 的第三方包

//1.导入模块
const express = require('express');
//2.创建服务器
let app = express();
// cors 
const cors = require('cors')

const webSoket = require('ws');
const { request } = require('express');

const wss1 = new webSoket.Server({ port:8080 })
const wss2 = new webSoket.Server({ port:6060 })

app.use(express.json());//允许请求头携带 json 格式的参数
app.use(express.urlencoded({ extended: false }));//允许请求头携带 application/x-www-form-urlencoded 类别的参数
app.use(cors())

let login = '';
let addBullet = '';

wss1.on('connection',(ws)=>{
    login = ws
    ws.on('open', (res)=>{
        console.log('客户端发起链接');
        ws.send(`{"code":2,"message":"success"}`)
    }) 
    ws.on('message',(res)=>{
        ws.send(`{"code":4,"message":"has open"}`)
    })
    
    ws.onclose = ()=>{
    }
})  

app.get('/api/login', (request, response) => {          
    response.send('扫码成功')
    console.log('有人扫码了');
    login.send(`{"code":1,"message":"扫码成功"}`)
    console.log('我发送了');
});

app.post('/api/addBullet',(request,response)=>{
    console.log(request.body);
    addBullet.send(`{"code":3,"message":"${request.body.bull}"}`)
    console.log('我发送了');

})
app.get('/api/addBullet',(request,response)=>{
    addBullet.send(`{"code":3,"message":"${request.body.bull}"}`)
    console.log(request.body);
    console.log('我发送了');

})
wss2.on('connection',(ws)=>{
    addBullet = ws
})


app.listen(3000,()=>{
    console.log('success');
});

作为一个 demo 应该还算还可以吧

写在最后的话

很多小伙伴们在找工作的都会在担心,都会在害怕,担心面试官问的太难自己答不上来,害怕自己找不到一份满意的工作。其实并不是这样,面试倒不如说是一个展示自己的过程,将自己最好的一面展示给面试官看,看看自己的不足,重新审视自己,查漏补缺,努力完善自己。

所以希望大家在面试的时候放松心态,以最好的状态展示自己,也祝各位大佬们能够在金三银四的时间里能够找到满意的工作,如果这篇文章给您带来的帮助,也请您点个赞吧!