当前位置:首页 > VUE

vue实现无限画布

2026-02-19 19:13:02VUE

Vue实现无限画布的方法

实现无限画布的核心在于动态加载和渲染画布内容,结合用户交互(如拖动、缩放)调整可见区域。以下是几种常见实现方式:

使用第三方库(如fabric.js + Vue)

安装fabric.js库:

vue实现无限画布

npm install fabric

基础实现代码:

vue实现无限画布

<template>
  <div class="canvas-container" ref="container">
    <canvas ref="canvas"></canvas>
  </div>
</template>

<script>
import { fabric } from 'fabric'

export default {
  mounted() {
    this.initCanvas()
    this.setupEvents()
  },
  methods: {
    initCanvas() {
      this.canvas = new fabric.Canvas(this.$refs.canvas, {
        width: this.$refs.container.clientWidth,
        height: this.$refs.container.clientHeight,
        selection: false,
      })

      // 设置虚拟画布尺寸(无限大)
      this.canvas.setWidth(10000)
      this.canvas.setHeight(10000)
    },
    setupEvents() {
      let lastPos = { x: 0, y: 0 }
      this.canvas.on('mouse:down', (opt) => {
        lastPos = { x: opt.e.clientX, y: opt.e.clientY }
      })

      this.canvas.on('mouse:move', (opt) => {
        if (!opt.e.buttons) return
        const delta = {
          x: opt.e.clientX - lastPos.x,
          y: opt.e.clientY - lastPos.y
        }
        this.canvas.relativePan(delta)
        lastPos = { x: opt.e.clientX, y: opt.e.clientY }
      })
    }
  }
}
</script>

<style>
.canvas-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
canvas {
  display: block;
}
</style>

纯Vue实现方案(基于CSS变换)

<template>
  <div 
    class="infinite-canvas" 
    ref="canvas"
    @mousedown="startDrag"
    @mousemove="drag"
    @mouseup="endDrag"
    @mouseleave="endDrag"
  >
    <div 
      class="canvas-content" 
      :style="{
        transform: `translate(${position.x}px, ${position.y}px) scale(${scale})`
      }"
    >
      <!-- 你的画布内容在这里 -->
      <div v-for="item in items" :key="item.id" class="canvas-item">
        {{ item.content }}
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      position: { x: 0, y: 0 },
      scale: 1,
      isDragging: false,
      startPos: { x: 0, y: 0 },
      items: [] // 你的画布元素数据
    }
  },
  methods: {
    startDrag(e) {
      this.isDragging = true
      this.startPos = {
        x: e.clientX - this.position.x,
        y: e.clientY - this.position.y
      }
    },
    drag(e) {
      if (!this.isDragging) return
      this.position = {
        x: e.clientX - this.startPos.x,
        y: e.clientY - this.startPos.y
      }
    },
    endDrag() {
      this.isDragging = false
    },
    handleWheel(e) {
      // 实现缩放功能
      const delta = e.deltaY > 0 ? -0.1 : 0.1
      this.scale = Math.max(0.1, Math.min(3, this.scale + delta))
    }
  },
  mounted() {
    this.$refs.canvas.addEventListener('wheel', this.handleWheel)
    // 初始化一些测试元素
    for (let i = 0; i < 100; i++) {
      this.items.push({
        id: i,
        content: `Item ${i}`,
        x: Math.random() * 2000 - 1000,
        y: Math.random() * 2000 - 1000
      })
    }
  },
  beforeDestroy() {
    this.$refs.canvas.removeEventListener('wheel', this.handleWheel)
  }
}
</script>

<style>
.infinite-canvas {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  position: relative;
}

.canvas-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform-origin: 0 0;
}

.canvas-item {
  position: absolute;
  border: 1px solid #ccc;
  padding: 10px;
  background: white;
}
</style>

性能优化技巧

动态加载可见区域内容,使用虚拟滚动技术:

// 在drag方法中添加可视区域检查
drag(e) {
  // ...原有拖动逻辑

  // 检查是否需要加载新内容
  this.checkVisibleArea()
},

checkVisibleArea() {
  const viewport = {
    left: -this.position.x,
    top: -this.position.y,
    right: window.innerWidth - this.position.x,
    bottom: window.innerHeight - this.position.y
  }

  // 根据viewport加载或卸载内容
  this.items = this.allItems.filter(item => 
    item.x + item.width > viewport.left && 
    item.x < viewport.right &&
    item.y + item.height > viewport.top &&
    item.y < viewport.bottom
  )
}

添加缩放功能

扩展handleWheel方法实现平滑缩放:

handleWheel(e) {
  e.preventDefault()
  const rect = this.$refs.canvas.getBoundingClientRect()
  const mouseX = e.clientX - rect.left
  const mouseY = e.clientY - rect.top

  const scaleDelta = e.deltaY > 0 ? 0.9 : 1.1
  const newScale = Math.max(0.1, Math.min(3, this.scale * scaleDelta))

  // 计算缩放中心偏移
  this.position = {
    x: mouseX - (mouseX - this.position.x) * (newScale / this.scale),
    y: mouseY - (mouseY - this.position.y) * (newScale / this.scale)
  }

  this.scale = newScale
  this.checkVisibleArea()
}

以上方案可根据实际需求进行组合或调整。第三方库方案功能更强大但体积较大,纯Vue方案更轻量但需要自行实现更多功能。

标签: 画布vue
分享给朋友:

相关文章

vue前端实现搜索

vue前端实现搜索

实现搜索功能的基本方法 在Vue中实现搜索功能通常涉及以下几个关键步骤,结合数据绑定、计算属性和方法调用来动态过滤和显示结果。 数据绑定与输入处理 使用v-model双向绑定搜索输入框的值,监听用户…

vue实现popup

vue实现popup

Vue 实现 Popup 弹窗 使用 Vue 原生组件 创建一个基本的 Vue 组件作为弹窗,通过 v-if 或 v-show 控制显示隐藏。 <template> <div&…

vue实现分站

vue实现分站

Vue 实现分站的方案 在 Vue 中实现分站功能通常涉及路由配置、环境变量管理和动态加载资源。以下是几种常见的实现方式: 基于路由的分站实现 通过 Vue Router 配置多路由,区分不同站点的…

vue实现type切换

vue实现type切换

Vue 实现 Type 切换的实现方法 在 Vue 中实现 Type 切换功能可以通过动态组件、条件渲染或路由切换等方式实现。以下是几种常见方法: 使用 v-if 或 v-show 条件渲染 通过绑…

vue实现登录退出

vue实现登录退出

实现登录功能 在Vue中实现登录功能通常需要结合表单验证、API请求和状态管理。以下是一个基础实现示例: 安装必要依赖(如axios和vuex): npm install axios vuex 创…

vue实现转盘抽奖

vue实现转盘抽奖

Vue 实现转盘抽奖 基本思路 转盘抽奖的核心是通过 CSS 动画实现旋转效果,Vue 负责控制旋转逻辑和数据绑定。关键点包括转盘扇形区域的绘制、旋转动画的触发与停止、中奖结果的判定。 实现步骤 H…