Vue: SVG사용하기

calico·2025년 5월 22일

Vue

목록 보기
5/9

출처


Loading a standard HTML SVG


  • vue의 template부분에 직접적으로 svg파일을 사용하는 방식으로 크게 아래 두가지가 있다.

    1. vue의 template안에 직접 <svg> 태그 작성

    2. <img>태그의 src에 svg파일의 위치 연결

  • 장점

    • 어려움 없이 사용 가능

    • svg 코드 값을 직접 수정, 변수를 전달 가능

  • 단점

    • svg파일이 조금만 복잡해져도 가독성이 매우 저하



vue-svg-loader 사용


vue에서 직접적으로 svg를 load 할 수 있도록 도와주는 vue-svg-loader 라이브러리가 있다.

  • 아래 코드 예시에서 볼 수 있듯이 import한 svg파일을 바로 template태그 안에 사용할 수 있다.

<template>
	<div>
    	<plus-svg>
    </div>
</template>

<script lang="ts">
import PlusSvg from '@/icons/svg/Plus.svg';

export default defineComponent({
	components: { PlusSvg, CheckBox },
	props: {
	},
})
</script>

  • 장점

    • 직관적이다.

    • 가독성이 좋다.

  • 단점

    • 초기 설정해줘야 하는 부분들이 존재한다. 어렵진 않지만, 귀찮을 수 있다.

    • Vue컴포넌트 내의 변수를 Svg파일에 전달할 수가 없다. (e.g. 사이즈 변수 등)



Svg Vue Component


Best Practice

  • Svg파일만을 위한 VueComponent를 만들고 이를 import해서 사용한다.

  • 아래코드는 히어로즈아이콘에서 다운받은 Plus Svg 파일을 Vue 컴포넌트화한 예시이다.

    • 코드에서 볼 수 있듯이, props로 변수를 전달할 수 있어 원하는 대로 값을 변경 가능하다.

<template>
	<svg
		xmlns="http://www.w3.org/2000/svg"
		:width="size"
		:height="size"
		viewBox="0 0 24 24"
		fill="none"
		stroke="currentColor"
		stroke-width="2.5"
		stroke-linecap="round"
		stroke-linejoin="round"
		class="feather feather-plus"
	>
		<line x1="12" y1="5" x2="12" y2="19"></line>
		<line x1="5" y1="12" x2="19" y2="12"></line>
	</svg>
</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
	name: 'plusSvg',
	props: {
		size: { type: String, required: true },
	},
	setup() {
		return {};
	},
});
</script>

<style lang="scss"></style>
  • 장점

    • props를 이용할 수 있다.

    • 가독성이 좋다.

    • import가 직관적이다.

  • 단점

    • 관리해야 하는 컴포넌트 수가 늘어날 수 있다.(하지만, 이 부분은 어쩔 수 없다고 생각한다.)



예제: AnimatedFlowArrow.vue


<template>
  <svg
      :style="{ position: 'absolute', left: 0, top: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 200 }"
  >
    <defs>
      <linearGradient
          :id="gradientId"
          x1="0"
          y1="0"
          x2="1"
          y2="0"
      >
        <stop offset="0%" :stop-color="color" stop-opacity="0.6"/>
        <stop offset="80%" :stop-color="color" stop-opacity="1"/>
        <stop offset="100%" stop-color="#fff" stop-opacity="0.4"/>
      </linearGradient>
      <marker
          id="arrowhead"
          markerWidth="5"
          markerHeight="5"
          refX="2.5"
          refY="1.5"
          orient="auto"
          markerUnits="strokeWidth"
      >
        <polygon points="0 0, 5 1.5, 0 3" :fill="color" />
      </marker>
    </defs>
    <g>
      <path
          :d="path"
          :stroke="'url(#' + gradientId + ')'"
          stroke-width="3"
          fill="none"
          :style="animatedStroke"
          marker-end="url(#arrowhead)"
      />
    </g>
  </svg>
</template>

<script>
export default {
  props: {
    path: {type: String, required: true},
    color: {type: String, default: '#ff3333'},
    isReverse: {type: Boolean, default: false}
  },
  data() {
    return {
      dashoffset: 0,
      gradientId: 'flow-grad-' + Math.random().toString(36).substr(2,6)
    }
  },
  computed: {
    animatedStroke() {
      return {
        strokeDasharray: '11,9',
        strokeDashoffset: `${this.isReverse ? -this.dashoffset : this.dashoffset}`,
        transition: 'stroke-dashoffset 0.18s linear'
      }
    }
  },
  mounted() {
    setInterval(() => {
      this.dashoffset = (this.dashoffset + 3) % 20;
    }, 45);
  }
}
</script>



사용 방법



<AnimatedFlowArrow
path="M10,20 C30,10 60,10 80,20"
color="#00aaff"
/>
                      
                      



profile
All views expressed here are solely my own and do not represent those of any affiliated organization.

0개의 댓글