vue3结合socket实现打字机动画

发布时间 2023-10-09 15:34:45作者: IT丶Hatcher
<template>
  <div>
    <div>ip地址:<input type="text" placeholder="ip地址" v-model="socketIP"></div>
    <br />
    <div>端口号:<input type="text" placeholder="端口号" v-model="port"></div>
    <div>生成条数:<input type="text" placeholder="生成条数" v-model="num"></div>
    <br />
    <!-- <button>确定</button>&nbsp; -->
    <button @click="socketFn()">发送</button>
    <div class="writingbox">
      <div class="textBox" v-for="(item, index) in textContent['writing']" :key="index">{{ item.editContent }}</div>
    </div>
  </div>
</template>
  
<script>
import { reactive, onMounted, toRefs } from 'vue'
import { inject } from "vue";
import { lightHigh, selectSort, del_all, cancelTitleTag, } from '@/libs/utils'



export default {
  name: 'socketTest',
  components: {},
  setup() {
    const state = reactive({
      socketIP: '192.168.xx.xx',
      port: 'xx',
      num: 2,
      socketEndNum: 1,
      socketIndex: 0,
      allObj: {},
      textListLength: 1,
      textContent: {
      },
      isGenerate: false,
      lightword: [],
      switch: true,
      emitNum: 0
    })

    const socket = inject("socket");
    onMounted(() => { })

    const socketFn = () => {
      let text = '发送的内容'
      let socketEmitNum = 0
      // 判断socket是否断开
      socket.connected ? '' : socket.open()
      // 发送socket的请求条数
      for (let i = 0; i < state.num; i++) {
        setTimeout(() => {
          socket.emit('process', text);
          i++
          socketEmitNum++
        }, 1);
      }
      state.switch = true


      let allArr = []

      socket.on('callback', (data) => {
        allArr.push(data)
        allArr.forEach((item, index) => {
          let key = Object.keys(state.allObj)
          let isclude = key.includes(item.uuid)

          if (isclude) {
            if (!state.allObj[item.uuid].includes(item)) {
              state.allObj[item.uuid].push(item)
            }
          } else {
            state.allObj[item.uuid] = []
            state.allObj[item.uuid].push(item)
          }
        })
        // 根据uuid进行分类,
        // console.log("socketEmitNum", socketEmitNum, Object.keys(state.allObj).length);
        if (state.switch && (socketEmitNum === Object.keys(state.allObj).length)) {
          testFn(state.allObj)
        }


        // 当数据返回结束时
        if (data.is_end) {
          if (state.socketEndNum < state.num) {
            state.socketEndNum++
          } else {
            state.socketEndNum = 1
            allArr = []
            // obj  = {}
            socketEmitNum = 0
          }
        }
      });
    }
    const testFn = (obj) => {
      state.switch = false
      let fnobj = JSON.parse(JSON.stringify(obj))
      console.log("obj", obj);
      console.log("fnobj", fnobj);
      let keys = Object.keys(fnobj)
      // console.log("keys",keys);
      let params = {
        num: state.num
      }
      // 初始化数据:
      for (let i = 0; i < params.num; i++) {
        state.textContent['writing'].push({
          count: 0,
          card_new: true,
          editContent: '',
          content: lightHigh(
            '',
            selectSort(state.lightword),
            false
          )
            .replace(/<p>/gi, '')
            .replace(/<\/p>/gi, ''),
          picture: [],
          pictureSize: [],
          video: [],
          videolighWord: [],
          videoImg: '',
          imglighWord: [],
          opacity: '#1A1A1A',
          tapOpacity: '#244EA4',
          titleOpacity: '#000000',
          img2failShow: false,
          img2textShow: false,
          video2failShow: false,
          video2failStatus: [
            '视频生成时间过长',
            '可稍后在历史记录中查看完成视频'
          ],
          video2loadingShow: false,
          editContentStatus: true,
          socketIndex: 0,
          isWriting: false,
          datalength: 0,
          cacheShow: true,
          uuid: keys[i],
          socketCacheData: []
        })
      }
      state.isGenerate = true
      //最后再遍历一遍存入的内容,调整需要展示的参数信息
      state.textContent['writing'].forEach((item, index) => {
        // state.gptCatch[index] = {}
        // state.gptCatch_count[index] = 1
        item.content = lightHigh(
          item.content ? item.content : '',
          selectSort(state.lightword),
          false
        )
          .replace(/<p>/gi, '')
          .replace(/<\/p>/gi, '')
        item.title = ''
        let babel = ''
        if (item?.tags) {
          item?.tags?.forEach((item) => {
            item = ' #' + item + '&nbsp;&nbsp;'
            babel = babel + item
          })
        }
        item.index = index

        item.babel = lightHigh(
          babel,
          selectSort(state.lightword),
          false
        )
        item.word_count = 0
        item.count = del_all(
          cancelTitleTag(item.content + item.babel + item.title)
        ).length

        item.rateValue = ''
        item.copyImg = ''
        // item.copyImg = require('../../assets/images/text2img_copy.svg')
        item.copyStarWrod = '标记灵感'
        item.copyWroddone = false
        item.tagsShow = true
        item.loading = false
        item.dotShow = false
        item.text = ''
        item.socketIndex = 0
        item.isWriting = false
        item.isEnd = false

        if (!item.show_id && !item.content) {
          item.socketCacheData = obj[item.uuid]
        }
      })
      socketHandleFn(state.textContent['writing'])
    }
    // 一段一段处理socket返回的值
    const socketHandleFn = (textContent) => {
      textContent.forEach((item, index) => {
        if (!item.show_id && !item.content) {
          writingTxet(item, index)
        }
      })
    }
    // 将socket中的某一数据中的data进行切割成数组传给writingWord
    const writingTxet = (item, ind) => {
      if (item.socketCacheData[item.socketIndex]?.is_end) {
        item.isEnd = true
      }

      if (item.socketCacheData[item.socketIndex]?.data === 1) {
        item.editContent += item.socketCacheData[item.socketIndex]?.data
        item.socketIndex++
        writingTxet(item, ind)
      } else {
        let textDataArr = item.socketCacheData[item.socketIndex]?.data.split("")
        writingWord(textDataArr, ind, 0, item)
        item.socketIndex++
      }



    }
    
    // 打字机动画效果
    const writingWord = async (textDataArr, ind, i, item) => {
      // 当打字速度过快时,socket数据没来得及返回,导致textDataArr为undefined,进行异常捕获
      try {
        if (i < textDataArr.length) {
          item.editContent += textDataArr[i]
          await new Promise(resolve => { setTimeout(resolve, 0) })
          await writingWord(textDataArr, ind, ++i, item)
        } else if (item.socketCacheData.length - 1 === item.socketIndex && item.isEnd) {
          item.editContent = item.editContent + "----" + item.uuid
          // console.log("打印完成", state.allObj);
          delete state.allObj[item.uuid]
          // console.log("删除后", state.allObj);
        }
        else {
          // console.log("=============");
          await writingTxet(item, ind)
        }
      } catch (error) {
        // console.log("error", ind, textDataArr);
        setTimeout(() => {
          if (!item.isEnd) {
            writingTxet(item, ind)
            // console.log("writingTxet", item, ind);
          }
        }, 2000);
      }
    }


    return {
      ...toRefs(state),
      socketFn
    }
  }
}


</script>
<style lang="less" scoped>
input {
  border: 1px solid;
}

.writingbox {
  width: 500px;
  // height: 800px;
  // border: 1px solid;
  margin: 0 auto;

  .textBox {
    width: 500px;
    min-height: 100px;
    border: 1px solid red;
    margin: 10px 0;
  }
}
</style>