当前位置:首页 > VUE

vue实现无限画布

2026-02-19 19:13:02VUE

Vue实现无限画布的方法

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

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

安装fabric.js库:

npm install fabric

基础实现代码:

<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方法实现平滑缩放:

vue实现无限画布

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 实现在线预览的常见方法 使用 iframe 嵌入 通过 iframe 标签可以嵌入多种类型的文件,如 PDF、图片、网页等。需要确保文件地址可访问。 <template> &…

vue实现handsontable

vue实现handsontable

Vue 中实现 Handsontable 要在 Vue 项目中集成 Handsontable,可以使用官方提供的 @handsontable/vue 封装库。以下是一个完整的实现步骤。 安装依赖 确…

vue 全景实现

vue 全景实现

Vue 全景实现方案 在Vue中实现全景效果,通常需要结合WebGL或第三方库来处理3D场景渲染。以下是几种常见方法: 使用Three.js库 Three.js是一个强大的WebGL库,适合创建3D…

vue实现弹幕

vue实现弹幕

Vue 实现弹幕功能 弹幕功能通常包括动态生成、滚动显示、颜色和速度随机化等特性。以下是基于 Vue 3 的实现方法。 核心思路 使用 CSS 动画控制弹幕从右向左滚动。 动态生成弹幕数据,随机设置…

vue环境实现

vue环境实现

Vue 环境搭建 安装 Node.js 和 npm Node.js 是运行 Vue 的基础环境,npm 是包管理工具。从 Node.js 官网 下载并安装最新稳定版本。安装完成后,在终端运行以下命令验…

vue实现CRUD

vue实现CRUD

Vue 实现 CRUD 操作 Vue 提供了响应式数据绑定和组件化开发能力,结合后端 API 可以轻松实现 CRUD(增删改查)功能。以下是基于 Vue 3 和 Axios 的完整实现方案。 安装依…