当前位置:首页 > 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 实现人脸识别比对的方法 使用现成的人脸识别 API 通过调用第三方人脸识别 API(如 Face++、百度 AI、腾讯云等)实现比对功能。注册开发者账号获取 API Key 和 Secret,…

vue实现fadein

vue实现fadein

Vue 实现 FadeIn 效果 在 Vue 中实现淡入(FadeIn)效果可以通过 CSS 过渡、动画或第三方库实现。以下是几种常见方法: 使用 CSS 过渡 通过 Vue 的过渡系统结合 CSS…

vue mvvm 实现

vue mvvm 实现

Vue MVVM 实现原理 Vue.js 的 MVVM(Model-View-ViewModel)架构通过数据绑定和响应式系统实现视图与数据的自动同步。以下是其核心实现机制: 数据劫持与响应式系统…

vue实现系统

vue实现系统

Vue 实现系统的核心方法 使用 Vue.js 构建系统时,需结合其响应式特性与组件化开发模式。以下为关键实现路径: 项目初始化与工程配置 通过 Vue CLI 或 Vite 创建项目骨架,推荐选…

vue实现computed

vue实现computed

Vue 中 computed 的实现原理 computed 属性是 Vue 的一个核心特性,它基于响应式依赖进行缓存,仅在依赖发生变化时重新计算。以下是 computed 的实现方式: 基本用法 在…

vue for实现

vue for实现

Vue 中的 v-for 指令 v-for 是 Vue.js 中用于渲染列表数据的核心指令,通过遍历数组或对象生成动态内容。 基本语法(数组) <ul> <li v-for=…