윤개발

Vue에서 외부 Markdown 보여주기(class 설정 포함) 본문

프론트/Vue.js

Vue에서 외부 Markdown 보여주기(class 설정 포함)

DEV_SJ 2021. 4. 9. 13:39

이번에 진행하는 프로젝트의 요구사항이 다음과 같습니다.

  • gitlab에 public으로 Markdown(이하 md) 업로드 - 로그인 없이 볼 수 있는 페이지여야함
  • Vue에서 gitlab markdown을 로딩하여 보여줌 - gitlab 페이지 호출

이렇게 진행하면 다음과 같은 장단점이 있습니다.

장점

  • html을 수정할 필요 없이 바라보는 gitlab md 파일만 수정하여도 운영환경에 반영(재배포가 필요없음)
  • 프로젝트 초기 자주 수정될 수 있는 Guide, Faq등은 md로 간단하게 표현 가능

단점

  • gitlab(또는 github) 에서 md를 가져오므로 정적파일을 로딩하는 것보다는 시간이 조금 더 걸림
  • md를 이용하다 보니 style 적용은 힘듬

Vue에서 Markdown을 불러오며 단점을 극복하기 위해 Class 를 적용하여 스타일을 먹이는 방법을 알아보겠습니다.

1. 생성 및 가져오기

  • gitlab 또는 github에 public으로 접근 가능한 Repository를 생성합니다
  • test용 markdown을 작성하여 업로드합니다.

그리고 오른쪽 상단에 Raw를 클릭하면 아래와 같이 Md만 보여주게 됩니다. (gitlab의 경우 다운로드 후 url 확보)

 

이제 Vue에서 raw 주소로 get요청을 보내고 받은 text를 보여주면 됩니다.

 

2. 의존성 설치

md를 가져오고 보여주기 위해서 2개의 의존성을 설치해야합니다.

  • axios - vue http 통신을 위한 라이브러리
  • marked - markdown을 html 형식으로 변경해주는 라이브러리
npm install axios
npm install marked --save-dev

 

3. 컴포넌트 생성

새로운 vue 컴포넌트를 생성하고 axios를 이용하여 주소의 md를 불러옵니다.

<template>
  <div class="test">
    <textarea rows="10" v-model="mdText"></textarea>
  </div>
</template>

<script>
import axios from "axios";
export default {
  name: "ShowMdPage",
  data() {
    return {
      mdText: ""
    };
  },
  mounted() {
    this.getMarkdown();
  },
  methods: {
    getMarkdown() {
      const url =
        "https://raw.githubusercontent.com/sungjaeyoon/show-md/main/README.md";
      axios.get(url).then(response => {
        this.mdText = response.data;
      });
    }
  }
};
</script>
  • data > mdText : markdown text가 저장
  • mounted() : 컴포넌트가 마운트될때 해당 함수를 호출
  • getMarkdown() : axios를 이용하여 URL을 호출하고 md_text에 넣어줌

아래와 같이 md를 잘 불러온 모습입니다.

이제 markdown을 html로 변경해야 합니다. 변경을 위해 marked 라이브러리를 이용합니다.

 

marked를 import 하고 아래와 같이 computed 함수를 작성합니다.

computed: {
    changeMarkdown() {
      marked.setOptions({
        renderer: new marked.Renderer(),
        gfm: true,
        headerIds: false,
        tables: true,
        breaks: true,
        pedantic: false,
        sanitize: true,
        smartLists: true,
        smartypants: false
      });
      return marked(this.mdText);
    }
}	

다음으로 template에 해당 함수를 바인딩하고 변경된 html 을 확인합니다.

또한 v-html 태그를 이용해서 실제 html로 렌더링 합니다.

    <div>
      <textarea rows="10" v-model="changeMarkdown"></textarea>
    </div>
    <div v-html="changeMarkdown"></div>

다음과 같이 md, html, 렌더링된 html이 모두 보여집니다.

 

4. 클래스 적용

이제 스타일을 입히기 위해 클래스를 적용해보겠습니다.

md 파일을 다음과 같이 수정하여 span 태그를 입히고 클래스를 적용합니다.

# show-md

## <span class="red-color">show-md</span>

### <span class="blue-color">show-md</span>

#### <span class="yellow-color">show-md</span>

 

그러면 보여지는 웹이 이상하게 변하게 됩니다.

< ,  " ,  > 3가지를 문자로 인식하여 다음과 같이 나오게 되므로 원래 문자열로 변경해주면 됩니다.

 

changeMarkdown 함수를 다음과 같이 변경합니다.

changeMarkdown() {
      marked.setOptions({
        renderer: new marked.Renderer(),
        gfm: true,
        headerIds: false,
        tables: true,
        breaks: true,
        pedantic: false,
        sanitize: true,
        smartLists: true,
        smartypants: false
      });
      let changedText =  marked(this.mdText);
      changedText = changedText.replaceAll("&lt;", "<");
      changedText = changedText.replaceAll("&gt;", ">");
      changedText = changedText.replaceAll("&quot;", '"');
      return changedText;
    }

 

그러면 다음과 같이 태그가 적용되고 실제 보여지는 html에서는 span태그가 표시되지 않는 모습입니다.

 

이제 css를 적용해보겠습니다.

 

아래와 같이 ::v-deep을 이용하여 css를 작성합니다.

::v-deep .red-color {
  color: red;
}
::v-deep .blue-color {
  color: blue;
}
::v-deep .yellow-color {
  color: yellow;
}

 

그러면 css가 색상이 적용됩니다.

이렇게 md 파일을 가져오고 class를 적용하는 법을 알아보았습니다.

감사합니다.

 

전체 소스코드

<template>
  <div class="test row">
    <div>
      <textarea rows="10" cols="20" v-model="mdText"></textarea>
    </div>
    <div>
      <textarea rows="10" v-model="changeMarkdown"></textarea>
    </div>
    <div v-html="changeMarkdown"></div>
  </div>
</template>

<script>
import axios from "axios";
import marked from "marked";
export default {
  name: "ShowMdPage",
  data() {
    return {
      mdText: ""
    };
  },
  mounted() {
    this.getMarkdown();
  },
  methods: {
    getMarkdown() {
      const url =
        "https://raw.githubusercontent.com/sungjaeyoon/show-md/main/README.md";
      axios.get(url).then(response => {
        this.mdText = response.data;
      });
    }
  },
  computed: {
    changeMarkdown() {
      marked.setOptions({
        renderer: new marked.Renderer(),
        gfm: true,
        headerIds: false,
        tables: true,
        breaks: true,
        pedantic: false,
        sanitize: true,
        smartLists: true,
        smartypants: false
      });
      let changedText = marked(this.mdText);
      changedText = changedText.replaceAll("&lt;", "<");
      changedText = changedText.replaceAll("&gt;", ">");
      changedText = changedText.replaceAll("&quot;", '"');
      return changedText;
    }
  }
};
</script>

<style scoped>
.test {
  background-color: white;
  color: black;
}
::v-deep .red-color {
  color: red;
}
::v-deep .blue-color {
  color: blue;
}
::v-deep .yellow-color {
  color: yellow;
}
</style>

 

Comments