vue3个人网站电子宠物

预览

具体代码

Attack.gif

Attacked.gif

Static.gif

Walk.gif

javascript 复制代码
<template>
  <div class="pet-container" ref="petContainer">
    <p class="pet-msg">{{ pet.msg }}</p>
    <img ref="petRef" @click="debounce(attckPet, 150)()" class="pet" :src="pet.src" alt="" srcset="">
  </div>
</template>

<script setup lang="ts">
import { reactive, onMounted, ref } from 'vue'
import { debounce } from 'lodash'
const imgSrc = {
  Static: import('../../../assets/images/pet/Static.gif'),
  Attack: import('../../../assets/images/pet/Attack.gif'),
  Attacked: import('../../../assets/images/pet/Attacked.gif'),
  Walk: import('../../../assets/images/pet/Walk.gif'),
}
const pet = reactive({
  msg: '打我啊',
  src: imgSrc.Static,
})
const petContainer = ref<HTMLElement | null>()
const petRef = ref<HTMLElement | null>()
const mousePosition = reactive({
  x: 0,
  y: 0,
})
const petPosition = reactive({
  x: 0,
  y: 0,
})
const deg = ref<number>(0)
const deg_y = ref<number>(0)
const count = ref<number>(0)
const speed = 50
let timer = null
let isListenMouseMove = false
onMounted(async () => {
  changeSrc('Static', '打我啊')
})

const changeSrc = async (key, msg) => {
  let res = await imgSrc[key];
  pet.src = res.default
  pet.msg = msg
}

const attckPet = () => {
  if (isListenMouseMove) return
  changeSrc('Attacked', '啊!!!')
  window.addEventListener('mousemove', listenMouseMove)
  isListenMouseMove = true
  petPosition.x = petContainer.value?.offsetLeft
  petPosition.y = petContainer.value?.offsetTop
  setTimeout(() => {
    changeSrc('Walk', '我和你拼了')
    timer = setInterval(() => {
      move()
    }, 10);
  }, 300);
}

const listenMouseMove = (e: MouseEvent) => {
  // 需要移动的x轴距离 = 当前鼠标位置-距离浏览器左边的距离-宠物相对于浏览器页面宽度/2(宽的中心位置)
  mousePosition.x = e.x - petContainer.value.offsetLeft - petContainer.value.clientWidth / 2;
  mousePosition.y = e.y - petContainer.value.offsetTop - petContainer.value.clientHeight / 2;
  let speed = Math.ceil((Math.pow(mousePosition.x, 2) + Math.pow(mousePosition.y, 2)) / 1000);
  // 需要的旋转角度计算
  deg.value = 360 * Math.atan(mousePosition.y / mousePosition.x) / (2 * Math.PI);
  // 这里的event.clientX 返回当事件被触发时鼠标指针相对于浏览器页面(或客户区)的水平坐标。
  // 这里有关于图片位置的设置,注意你的gif图的方向,原图方向向左,那么这里就是小于,原图方向向右,这里就是大于。
  // 翻转图片
  if (petContainer.value.offsetLeft > e.clientX) {
    deg_y.value = - 180;
  } else {
    deg_y.value = 0;
  }
  //这里每一次移动鼠标都要重新计算距离,所以这里的count需要清零
  count.value = 0;
}

const move = () => {
  if (count.value < speed) {
    petPosition.x += mousePosition.x / speed
    petPosition.y += mousePosition.y / speed
    petRef.value.style.transform = "rotateZ(" + deg.value + "deg) rotateY(" + deg_y.value + "deg)"
    petContainer.value.style.left = petPosition.x + "px"
    petContainer.value.style.top = petPosition.y + "px"
    count.value++
  } else {
    window.removeEventListener('mousemove', listenMouseMove)
    changeSrc('Attack', '打死你')
    setTimeout(() => {
      changeSrc('Static', '打我啊')
      timer = clearInterval(timer);
      count.value = 0;
      isListenMouseMove = false;
    }, 1000);
  }
}
</script>

<style scoped lang="scss">
.pet-container {
  position: fixed;
  top: calc(100% - 100px);
  left: 0;

  .pet {
    width: 50px;
    height: 65px;
    cursor: pointer;
  }

  .pet-msg {
    padding: 5px;
    background: #8f8888;
    color: #fff;
  }
}
</style>

参考博客

参考博客

相关推荐
愚公搬代码20 分钟前
【愚公系列】《Web应用安全》001-VMware的安装
前端·安全
xiaohaiAIgeo20 分钟前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
立少→万能汉编22 分钟前
用“立少→超文本”写静态网页,标签<倍>
服务器·前端·javascript
weixin_4316004431 分钟前
NestJS 入门(7):生命周期钩子——构造函数和 `OnModuleInit` 差在哪?
前端·后端·学习·node.js·nest.js
你挚爱的强哥1 小时前
【chromeDownload】自定义组件:多用于登录框底部提供下载Chrome谷歌浏览器的链接
前端·vue.js·chrome
cindershade1 小时前
用原生 HTML5 视频与 Canvas 实现浏览器端视频抽帧封面
前端
笨鸟先飞,勤能补拙1 小时前
Web 服务器与计算机网络全景原理
运维·服务器·前端·网络·人工智能·计算机网络·web安全
NutShell Wang2 小时前
Wails v3 Beta 实战:用显式对象模型重写你的第一个 Go 桌面应用
前端·人工智能·go·vibe coding
daols882 小时前
vue 甘特图 vxe-gantt 任务条拖拽自动更新日期
javascript·vue.js·甘特图
cindershade2 小时前
前端国际化工程实践:语言包拆分、动态加载与日期数字格式统一
前端