FrontEnd/Vue

Toast UI Editor _ Vue2

Raconer 2023. 4. 16. 23:12
728x90

개요

Toast UI Editor은 기본적은로 MarkDown 기반의 Editor이다.
그래서 Image를 추가 하게 되면 MarkDown 형식으로 저장이 되는데
이러면 Image의 align을 셋팅을 할수 가 없다.
마크다운을 div Tag 로 덮은다음 align을 설정해도 원하는데로 적용이 되질 않았다.
그래서 Button 커스텀을 하였다.
기존의 이미지 업로드 버튼을 제거 하고 새로 비슷하게 만들어 버튼을 추가해 주었다.

코드

<template>
    <editor
      ref="editor"
      :initialValue="value"
      :options="options"
      height="auto"
      initialEditType="markdown"
      @change="change"
    />
</template>

<script>
import {uploadFile} from "~/service/api/fileService";

export default {
  name: "EditorForm",
  props : {
    value : {
      type : String,
      default : ""
    },
  },
  data(){
    // 이미지 툴바 버튼 생성
    let imageToolBar = () => {
      // javascript 코드를 통해 File Input을 생성한다.
      const file = document.createElement("input");
      file.setAttribute("type", "file");
      file.style.display = 'none';
      file.accept="image/png, image/gif, image/jpeg";

      // 파일 업로드시 진행 되는 이벤트 이다.
      file.addEventListener("change", async (value, data) =>{
        let files = value.target.files;
        if(files.length > 0){
          await this.fileUpload(files[0]);
        }
      });

      // 버튼을 생성한다.
      const button = document.createElement('button');

      button.className = 'toastui-editor-toolbar-icons';
      button.setAttribute('type', 'button');
      button.style.backgroundImage = 'none';
      button.style.margin = '0';
      // 버튼 코드는 Icon을 사용하기 위해 그냥 간단한 코드로 작성하였다.
      button.innerHTML = `<i aria-hidden="true" file="v-icon/usage" class="v-icon notranslate mdi mdi-file-image theme--light"></i>`;
      // 버튼 안에 File Input을 넣습니다.
      button.appendChild(file);
      // 버튼을 클릭하면 file (상단의 const file입니다.)
      // input:type=file 인 input이 클릭 되는 이벤트를 설정합니다.
      // button click 은 input:type=file click 이벤트와 같다.
      button.addEventListener('click', () => {
        file.click();
      });
      // 이후에 element를 Return한다.
      return {
        el: button,
        tooltip: 'Image Upload'
      }
    }

    return {
      options: {
        minHeight:"1500px",
        hideModeSwitch: true,
        toolbarItems: [
          ['heading', 'bold', 'italic', 'strike'],
          ['hr', 'quote'],
          ['ul', 'ol', 'task', 'indent', 'outdent'],
          ['table', 'link'],
          ['code', 'codeblock'],
          // Custom한 Image Tool Bar를 추가한다.
          [
            imageToolBar()
          ]
        ],

      }
    }
  },
  methods : {
    change(){
      let markdown = this.$refs.editor.invoke("getMarkdown");
      this.$emit("change", markdown);
    },
    // 파일을 실질적인 API를 통하여 전송한다.
    async fileUpload(file){

      if(!file){
        alert("File Is Null");
        return;
      }

      let formData = await new FormData();
      formData.set('img', file);

      await uploadFile(formData)
        .then((data) => {
          console.log(data);
          // image tag를 구성하여 
          let img = `<img src="${data.path}" alt="${data.name}"/>`
          // Editor에 Invoke 하면 이미지가 HTML 코드로 생성 됩니다.
          this.$refs.editor.invoke("insertText", img);
        })
        .catch((error) => {
          alert("Error");
        });
    }
  }
}
</script>
728x90

'FrontEnd > Vue' 카테고리의 다른 글

Template Data Binding & Event  (0) 2023.04.16
메소드 안에서 Vue2 Component 추가 하기  (0) 2023.04.15
Vue.js Module  (0) 2023.04.15
Vue.js 프로젝트 생성  (0) 2023.04.15
[Vue.js] Router 기초  (0) 2023.04.15