vue2实现在屏幕中有一个小机器人可以随意移动

第一步:创建store目录结构

复制代码
src/
├── store/
│   ├── modules/
│   │   └── robot.js     # 机器人专用状态模块
│   └── index.js         # Vuex 主配置文件

第二步:创建机器人状态模块

创建 src/store/modules/robot.js 文件,内容如下:

复制代码
// 从本地存储读取初始位置(实现持久化)
const getInitialPosition = () => {
    try {
      return JSON.parse(localStorage.getItem('robotPosition')) || { x: 100, y: 100 }
    } catch {
      return { x: 100, y: 100 }
    }
  }
  
  export default {
    namespaced: true,  // 启用命名空间
    
    state: () => ({
      position: getInitialPosition(),
      visibility: true
    }),
    
    mutations: {
      UPDATE_POSITION(state, newPos) {
        state.position = newPos
        // 同步到本地存储
        localStorage.setItem('robotPosition', JSON.stringify(newPos))
      },
      TOGGLE_VISIBILITY(state) {
        state.visibility = !state.visibility
      }
    },
    
    actions: {
      setPosition({ commit }, position) {
        commit('UPDATE_POSITION', position)
      },
      resetPosition({ commit }) {
        commit('UPDATE_POSITION', getInitialPosition())
      }
    },
    
    getters: {
      formattedPosition: state => {
        return `X: ${state.position.x}px, Y: ${state.position.y}px`
      }
    }
  }

第三步:配置主Store文件

修改 src/store/index.js:

复制代码
import Vue from 'vue'
import Vuex from 'vuex'
import robot from './modules/robot'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    robot  // 注册机器人模块
  }
})

第四步:初始化Vuex

在 main.js 中挂载 store:

复制代码
import Vue from 'vue'
import App from './App.vue'
import store from './store'  // 自动识别 index.js

new Vue({
  store,  // 注入全局 store
  render: h => h(App)
}).$mount('#app')

第五步(可选):增强持久化配置

如果要实现更复杂的持久化,可以使用 vuex-persistedstate:

1.安装插件:

复制代码
npm install vuex-persistedstate

2.修改 store 配置:

复制代码
// store/index.js
import createPersistedState from 'vuex-persistedstate'

export default new Vuex.Store({
  modules: { /*...*/ },
  plugins: [
    createPersistedState({
      paths: ['robot.position']  // 只持久化位置信息
    })
  ]
})

第六步:创建全局机器人组件(components/GlobalRobot.vue)

复制代码
<template>
  <div class="global-robot" :style="robotStyle" @mousedown="startDrag" @click="opendialog">
 🤖
  
  </div>
</template>

<script>
import { mapState, mapActions } from 'vuex'

export default {

  name: 'GlobalRobot',
  data() {
    return {

      isDragging: false,
      dragOffset: { x: 0, y: 0 },
      elementWidth: '',
      elementHeight: ''
    }
  },
  computed: {
    ...mapState('robot', ['position']),
    robotStyle() {
      return {
        left: `${this.position.x}px`,
        top: `${this.position.y}px`,
        zIndex: 9999
      }
    }
  },
  methods: {
    ...mapActions('robot', ['setPosition']),

    startDrag(e) {
      this.isDragging = true
      const rect = this.$el.getBoundingClientRect()
      this.elementWidth = rect.width
      this.elementHeight = rect.height
      console.log(this.elementWidth)
      console.log(this.elementHeight)
      this.dragOffset = {
        x: e.clientX - this.position.x,
        y: e.clientY - this.position.y
      }

      document.addEventListener('mousemove', this.onDrag)
      document.addEventListener('mouseup', this.stopDrag)
      e.preventDefault()
    },

    onDrag(e) {
      if (!this.isDragging) return
      const maxX = window.innerWidth - this.elementWidth
      const maxY = window.innerHeight - this.elementHeight
      const newX = e.clientX - this.dragOffset.x
      const newY = e.clientY - this.dragOffset.y
      // 严格边界限制
      this.setPosition({
        x: Math.max(0, Math.min(newX, maxX)),
        y: Math.max(0, Math.min(newY, maxY))
      })
      console.log(
  `边界检测: 
  newX=${newX}, 
  maxX=${maxX}, 
  clampedX=${Math.max(0, Math.min(newX, maxX))}`
)
      
    },

    stopDrag() {
      this.isDragging = false
      document.removeEventListener('mousemove', this.onDrag)
      document.removeEventListener('mouseup', this.stopDrag)
    },
    opendialog() {
      this.dialogVisible = true
    }
  }
}
</script>

<style scoped>
.global-robot {
  position: fixed;
  width: 100px;
  height: 100px;
  /* background-image: linear-gradient(92deg, #407cd6 15%, #3ebcb4 48.8525390625%, #397ace 100%); */
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 50px;
  cursor: move;
  user-select: none;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  transition:
    transform 0.2s,
    box-shadow 0.2s;
  pointer-events: auto;
  /* 确保可交互 */
}

.global-robot:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.25);
}

.global-robot:active {
  cursor: grabbing;
  transform: scale(0.95);
}
</style>
相关推荐
GISer_Jing36 分钟前
WebGL跨端兼容实战:移动端适配全攻略
前端·aigc·webgl
迦南giser38 分钟前
前端性能——传输优化
前端
小白_ysf43 分钟前
Vue 中常见的加密方法(对称、非对称、杂凑算法)
前端·vue.js·算法
2501_944448002 小时前
Flutter for OpenHarmony衣橱管家App实战:支持我们功能实现
android·javascript·flutter
人工智能训练7 小时前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪8 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
xiaoqi9228 小时前
React Native鸿蒙跨平台如何进行狗狗领养中心,实现基于唯一标识的事件透传方式是移动端列表开发的通用规范
javascript·react native·react.js·ecmascript·harmonyos
jin1233229 小时前
React Native鸿蒙跨平台剧本杀组队消息与快捷入口组件,包含消息列表展示、快捷入口管理、快捷操作触发和消息详情预览四大核心功能
javascript·react native·react.js·ecmascript·harmonyos
烬头882110 小时前
React Native鸿蒙跨平台实现二维码联系人APP(QRCodeContactApp)
javascript·react native·react.js·ecmascript·harmonyos
pas13610 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js