返回

在Vue3中构建像素风LOGO编辑器:Pixeled Pic Pro

前端

使用 Vue3 和 Canvas API 构建像素风 LOGO 编辑器

简介

像素风艺术正以其复古魅力和独特的视觉效果而风靡一时。如果你是一位像素艺术爱好者,或者正在寻找一种创造性的方式来设计自己的徽标,那么本文将为你提供一个完美的解决方案。我们将介绍如何使用 Vue3 和 Canvas API 构建一个像素风 LOGO 编辑器,名为 Pixeled Pic Pro。

使用 Vue3 设置项目

首先,使用 Vue CLI 或你偏好的 Vue3 构建工具创建一个新的 Vue3 项目。

vue create pixeled-pic-pro

设置 Canvas 画布

接下来,创建一个网格画布来绘制像素艺术。在 <App.vue> 文件中,添加以下代码:

<template>
  <div id="app">
    <canvas id="canvas" width="512" height="512"></canvas>
  </div>
</template>

<script>
export default {
  mounted() {
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');

    // 设置画布的初始颜色
    context.fillStyle = 'white';
    context.fillRect(0, 0, canvas.width, canvas.height);
  }
};
</script>

实现画笔工具

现在,让我们添加一个画笔工具来绘制像素。在 <App.vue> 文件中,添加以下代码:

<template>
  ...

  <input type="color" v-model="selectedColor">
</template>

<script>
export default {
  ...

  data() {
    return {
      selectedColor: '#000000',
    };
  },

  methods: {
    drawPixel(e) {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 获取鼠标的坐标
      const x = e.clientX - canvas.offsetLeft;
      const y = e.clientY - canvas.offsetTop;

      // 设置画笔的颜色
      context.fillStyle = this.selectedColor;

      // 绘制一个1x1的像素
      context.fillRect(x, y, 1, 1);
    }
  }
};
</script>

撤销和重做

为了方便用户修改错误,我们需要实现撤销和重做功能。在 <App.vue> 文件中,添加以下代码:

<template>
  ...

  <button @click="undo">撤销</button>
  <button @click="redo">重做</button>
</template>

<script>
export default {
  ...

  data() {
    return {
      undoStack: [],
      redoStack: [],
    };
  },

  methods: {
    ...

    undo() {
      if (this.undoStack.length > 0) {
        // 获取上一步操作的状态
        const state = this.undoStack.pop();

        // 将当前状态压入重做栈
        this.redoStack.push(this.getState());

        // 恢复上一步操作的状态
        this.setState(state);
      }
    },

    redo() {
      if (this.redoStack.length > 0) {
        // 获取下一步操作的状态
        const state = this.redoStack.pop();

        // 将当前状态压入撤销栈
        this.undoStack.push(this.getState());

        // 恢复下一步操作的状态
        this.setState(state);
      }
    },

    getState() {
      // 获取画布的像素数据
      const pixels = this.getPixels();

      // 返回画布的状态
      return {
        pixels: pixels,
      };
    },

    setState(state) {
      // 设置画布的像素数据
      this.setPixels(state.pixels);
    },

    getPixels() {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 获取画布的像素数据
      const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;

      // 返回像素数据
      return pixels;
    },

    setPixels(pixels) {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 创建一个新的图像数据对象
      const imageData = new ImageData(new Uint8ClampedArray(pixels), canvas.width, canvas.height);

      // 将图像数据对象绘制到画布上
      context.putImageData(imageData, 0, 0);
    }
  }
};
</script>

保存和加载设计

最后,我们需要实现保存和加载设计的功能。在 <App.vue> 文件中,添加以下代码:

<template>
  ...

  <button @click="saveDesign">保存</button>
  <button @click="loadDesign">加载</button>
</template>

<script>
export default {
  ...

  methods: {
    ...

    saveDesign() {
      // 获取画布的像素数据
      const pixels = this.getPixels();

      // 将像素数据转换为JSON字符串
      const json = JSON.stringify(pixels);

      // 将JSON字符串存储到本地存储中
      localStorage.setItem('design', json);

      // 显示保存成功的消息
      alert('设计已保存!');
    },

    loadDesign() {
      // 从本地存储中获取JSON字符串
      const json = localStorage.getItem('design');

      // 将JSON字符串解析为像素数据
      const pixels = JSON.parse(json);

      // 设置画布的像素数据
      this.setPixels(pixels);

      // 显示加载成功的消息
      alert('设计已加载!');
    }
  }
};
</script>

示例代码

将以下代码粘贴到 <script> 部分中,以获得完整的 Vue3 组件代码:

<script>
export default {
  data() {
    return {
      selectedColor: '#000000',
      undoStack: [],
      redoStack: [],
    };
  },
  mounted() {
    const canvas = document.getElementById('canvas');
    const context = canvas.getContext('2d');

    // 设置画布的初始颜色
    context.fillStyle = 'white';
    context.fillRect(0, 0, canvas.width, canvas.height);
  },
  methods: {
    drawPixel(e) {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 获取鼠标的坐标
      const x = e.clientX - canvas.offsetLeft;
      const y = e.clientY - canvas.offsetTop;

      // 设置画笔的颜色
      context.fillStyle = this.selectedColor;

      // 绘制一个1x1的像素
      context.fillRect(x, y, 1, 1);
    },
    undo() {
      if (this.undoStack.length > 0) {
        // 获取上一步操作的状态
        const state = this.undoStack.pop();

        // 将当前状态压入重做栈
        this.redoStack.push(this.getState());

        // 恢复上一步操作的状态
        this.setState(state);
      }
    },
    redo() {
      if (this.redoStack.length > 0) {
        // 获取下一步操作的状态
        const state = this.redoStack.pop();

        // 将当前状态压入撤销栈
        this.undoStack.push(this.getState());

        // 恢复下一步操作的状态
        this.setState(state);
      }
    },
    getState() {
      // 获取画布的像素数据
      const pixels = this.getPixels();

      // 返回画布的状态
      return {
        pixels: pixels,
      };
    },
    setState(state) {
      // 设置画布的像素数据
      this.setPixels(state.pixels);
    },
    getPixels() {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 获取画布的像素数据
      const pixels = context.getImageData(0, 0, canvas.width, canvas.height).data;

      // 返回像素数据
      return pixels;
    },
    setPixels(pixels) {
      const canvas = document.getElementById('canvas');
      const context = canvas.getContext('2d');

      // 创建一个新的图像数据对象
      const imageData = new ImageData(new Uint8ClampedArray(pixels), canvas.width, canvas.height);

      // 将图像数据对象绘制到画布上
      context.putImageData(imageData, 0, 0);
    },
    saveDesign