封装svg图片展示及操作组件——svgComponent——js技能提升

template部分

js 复制代码
<template>
  <div class="canvas-wrapper" ref="canvasWrapper">
    <svg
        :viewBox="computedViewBox"
        ref="svgCanvas"
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        class="schematic-svg"
        @mousedown="startDrag"
        @mousemove="onDrag"
        @mouseup="endDrag"
        @wheel="onScroll"
        v-html="svgContent"
        preserveAspectRatio="xMinYMin meet"
    >
    </svg>
  </div>
</template>


this.klFile = "data:image/svg+xml;base64," + data[0].kl_svg
<svg-component v-if="klFile !== null" :svg-base64="klFile" view-box="0 0 2000 2000"></svg-component>

script部分

js 复制代码
<script>
export default {
  name:'SvgComponent',
  props: {
    svgBase64: {
      type: String,
      required: true
    },
    viewBox: {
      type: String,
      required: true
    },
  },
  data() {
    return {
      computedViewBox: this.viewBox, // 用于动态修改的 viewBox
      dragging: false,
      startX: 0,
      startY: 0,
      viewBoxX: 0,
      viewBoxY: 0,
      svgContent: "", // 存储解码后的 SVG 内容
    };
  },
  watch: {
    svgBase64() {
      // 响应 props 变化并重新渲染 SVG
      this.decodeSvgBase64();
    },
  },
  mounted() {
    this.decodeSvgBase64();
  },
  methods: {
    decodeSvgBase64() {
      // 解码 Base64 数据
      // 检查并移除可能存在的 Base64 数据头
      let base64String = this.svgBase64;
      const prefix = "data:image/svg+xml;base64,";

      if (base64String.startsWith(prefix)) {
        base64String = base64String.replace(prefix, "");
      }

      // 尝试解码 Base64 数据
      const decodedData = atob(base64String);

      this.svgContent = decodedData; // 将解码后的内容赋值给 svgContent
    },
    startDrag(event) {
      this.dragging = true;
      this.startX = event.clientX;
      this.startY = event.clientY;
    },
    onDrag(event) {
      if (this.dragging) {
        const dx = this.startX - event.clientX;
        const dy = this.startY - event.clientY;
        this.viewBoxX += dx;
        this.viewBoxY += dy;
        this.updateViewBox();
        this.startX = event.clientX;
        this.startY = event.clientY;
      }
    },
    endDrag() {
      this.dragging = false;
    },
    onScroll(event) {
      event.preventDefault();
      const zoomAmount = 1.1;
      const [x, y, w, h] = this.computedViewBox.split(" ").map(Number);

      // Zoom in or out
      if (event.deltaY < 0) {
        // Zoom in
        this.computedViewBox = `${x + w * (1 - 1 / zoomAmount) / 2} ${y + h * (1 - 1 / zoomAmount) / 2} ${w / zoomAmount} ${h / zoomAmount}`;
      } else {
        // Zoom out
        this.computedViewBox = `${x - w * (zoomAmount - 1) / 2} ${y - h * (zoomAmount - 1) / 2} ${w * zoomAmount} ${h * zoomAmount}`;
      }
    },
    updateViewBox() {
      const [x, y, w, h] = this.viewBox.split(" ").map(Number);
      this.computedViewBox = `${this.viewBoxX} ${this.viewBoxY} ${w} ${h}`;
    }
  },
};
</script>

css部分

css 复制代码
<style scoped>
.canvas-wrapper {
  border-radius: 10px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  overflow: hidden;
}

.schematic-svg {
  width: 100%;
  height: 100%;
}
</style>
相关推荐
一枚前端小能手6 分钟前
「周更第3期」实用JS库推荐:Lodash
前端·javascript
艾小码6 分钟前
Vue组件到底怎么定义?全局注册和局部注册,我踩过的坑你别再踩了!
前端·javascript·vue.js
鹏多多14 分钟前
前端复制功能的高效解决方案:copy-to-clipboard详解
前端·javascript
uhakadotcom18 分钟前
Rollup 从0到1:TypeScript打包完全指南
前端·javascript·面试
echoarts22 分钟前
Rayon Rust中的数据并行库入门教程
开发语言·其他·算法·rust
Mintopia24 分钟前
实时语音转写 + AIGC:Web 端智能交互的技术链路
前端·javascript·aigc
2503_9284115626 分钟前
9.15 ES6-变量-常量-块级作用域-解构赋值-箭头函数
前端·javascript·es6
Mintopia33 分钟前
Next.js 单元测试究竟该选 JTest 还是 Vitest?
前端·javascript·next.js
遂心_35 分钟前
深入浅出 querySelector:现代DOM选择器的终极指南
前端·javascript·react.js
遂心_38 分钟前
DOM元素内容修改全攻略:从innerHTML到现代API的最佳实践
前端·javascript·react.js