基于Vue实现海报上传,并且实现网格分割和水印定义

发布于:2025-05-22 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

📁 功能介绍

📁 项目结构

📁 快速搭建

🚀 启动项目


📁 功能介绍

  • 上传任意图片海报

  • 自动添加水印(文字 + 网格)图层

  • 使用原生 <canvas>,无依赖,适合本地项目

📁 项目结构

watermark-demo/
├── index.html
├── package.json
├── vite.config.js
├── src/
│   ├── main.js
│   ├── App.vue
│   └── components/
│       └── WatermarkOverlay.vue

📁 快速搭建

npm init vite@latest
# 选择 vue -> 名称为 "watermark-demo"
cd watermark-demo
npm install

App.vue

<template>
  <div class="app">
    <h1>🖼️ 海报上传 + 水印演示</h1>

    <input type="file" accept="image/*" @change="onUpload" />

    <div
      v-if="imageUrl"
      class="poster-container"
      :style="{ width: `${imgWidth}px`, height: `${imgHeight}px` }"
    >
      <img
        :src="imageUrl"
        :width="imgWidth"
        :height="imgHeight"
        @load="onImageLoad"
      />
      <WatermarkOverlay
          v-if="imgWidth && imgHeight"
          :width="imgWidth"
          :height="imgHeight"
          text="稿定"
      />

    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import WatermarkOverlay from './components/WatermarkOverlay.vue'

const imageUrl = ref(null)
const imgWidth = ref(0)
const imgHeight = ref(0)

const onUpload = (e) => {
  const file = e.target.files[0]
  if (file) {
    imageUrl.value = URL.createObjectURL(file)
  }
}

const onImageLoad = (e) => {
  imgWidth.value = e.target.naturalWidth
  imgHeight.value = e.target.naturalHeight
}
</script>

<style scoped>
.app {
  padding: 2rem;
}
.poster-container {
  position: relative;
  border: 1px solid #ddd;
  margin-top: 1rem;
  display: inline-block;
}
</style>

main.js

import { createApp } from 'vue'
import App from './App.vue'
import './style.css'

createApp(App).mount('#app')

WatermarkOverlay.vue

<template>
  <canvas ref="canvas" class="watermark-canvas" />
</template>

<script setup>
import { onMounted, ref, watch } from 'vue'

const props = defineProps({
  width: Number,
  height: Number,
  text: {
    type: String,
    default: '稿定'
  }
})

const canvas = ref(null)

const drawWatermark = () => {
  const el = canvas.value
  if (!el) return
  const ctx = el.getContext('2d')
  el.width = props.width
  el.height = props.height
  ctx.clearRect(0, 0, el.width, el.height)

  const spacing = 250
  const lineColor = 'rgba(255,255,255,0.3)'
  const textColor = 'rgba(255,255,255,0.3)'

  ctx.lineWidth = 1
  ctx.strokeStyle = lineColor

  // 画斜线(左上到右下)
  for (let x = -el.height; x < el.width + el.height; x += spacing) {
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x - el.height, el.height)
    ctx.stroke()
  }

  // 画斜线(右上到左下)
  for (let x = 0; x < el.width + el.height; x += spacing) {
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x + el.height, el.height)
    ctx.stroke()
  }

  // 画文字水印
  ctx.save()
  ctx.font = '24px sans-serif'
  ctx.fillStyle = textColor
  ctx.rotate(-Math.PI / 4)

  for (let x = -el.width; x < el.width * 2; x += spacing * 1.5) {
    for (let y = -el.height; y < el.height * 2; y += spacing * 1.5) {
      ctx.fillText(props.text, x, y)
    }
  }

  ctx.restore()
}

onMounted(drawWatermark)
watch(() => [props.width, props.height, props.text], drawWatermark)
</script>

<style scoped>
.watermark-canvas {
  position: absolute;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 10;
}
</style>

🚀 启动项目

npm install
npm run dev

打开浏览器访问:http://localhost:5173,上传一张图片,并看到实时水印叠加效果了。