2022. 3. 23. 08:00ใFront-End ์์ ์ค/Vue.js
๐ tiptap Editor
์ด ์๋ํฐ๋ก ์์ฑ๋๋ ๋ด์ฉ์ Form์ textarea์ ์จ์ง๋ ๊ฒ์ด ์๋๊ณ div์ HTML๋ก ์จ์ง๊ณ ๋ฏธ๋ฆฌ ์ ์๋์ด ์๋ CSS Style๋ก ํํ๋ฅผ ๋ฐ๋ก๋ฐ๋ก ๋ณด์ฌ์ฃผ๋ ์์ธ๊ฒ ๊ฐ์ ๋ณด์ด๋ ๊ฒ์ด์์. ๋ ๋๋ฆฌ์ค๋ผ๋๊ฒ ์ด๋ฐ ๋ฐฉ์์ ๋งํ๋๊ฒ์ด ์๋๊ฐ ์๊ฐ์ด ๋๋ ๊ฒ์ด์์.
Tiptap์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก CSS์คํ์ผ์ด ์ ์ ๋์ด ์์ง ์๋ค๊ณ ํฉ๋๋ค. ๋ณธ์ธ์ ๋ง๊ฒ ์ค์ ์ ํด์ผ ํ๋ ๊ฒ์ด์์.
๋ค๋ง ์ํ๋ก ์ ๊ณตํ๊ณ ์๋ css๋ฅผ ๊ฐ์ ธ๋ค ์ฌ์ฉํ ์๋ ์์ ๊ฒ ๊ฐ์ ๊ฒ์ด์์.
๐ฝ ์ค์น
โ npm ์ด์ฉ ์ค์น
npm install @tiptap/vue-3 @tiptap/starter-kit
โ yarn ์ด์ฉ ์ค์น
yarn add @tiptap/vue-3 @tiptap/starter-kit
โ junyharang_dev_commnunity_client git:(master) โ npm uninstall @tiptap/vue-3
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: junyharang_dev_commnunity_client@0.1.0
npm ERR! Found: vue@3.2.31
npm ERR! node_modules/vue
npm ERR! vue@"^3.2.13" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer vue@"^2.5.17" from tiptap@1.32.2
npm ERR! node_modules/tiptap
npm ERR! tiptap@"^1.32.2" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See /Users/juny/.npm/eresolve-report.txt for a full report.
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/juny/.npm/_logs/2022-03-22T21_59_03_868Z-debug-0.log
โ junyharang_dev_commnunity_client git:(master) โ npm uninstall @tiptap/vue-3 --force
npm WARN using --force Recommended protections disabled.
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: tiptap@1.32.2
npm WARN Found: vue@3.2.31
npm WARN node_modules/vue
npm WARN peerOptional vue@"^2 || ^3.2.13" from @vue/babel-preset-app@5.0.1
npm WARN node_modules/@vue/babel-preset-app
npm WARN @vue/babel-preset-app@"^5.0.1" from @vue/cli-plugin-babel@5.0.1
npm WARN node_modules/@vue/cli-plugin-babel
npm WARN 5 more (@vue/server-renderer, vue-cookie-next, vue-router, vuex, the root project)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer vue@"^2.5.17" from tiptap@1.32.2
npm WARN node_modules/tiptap
npm WARN tiptap@"^1.32.2" from the root project
npm WARN 1 more (tiptap-extensions)
npm WARN
npm WARN Conflicting peer dependency: vue@2.6.14
npm WARN node_modules/vue
npm WARN peer vue@"^2.5.17" from tiptap@1.32.2
npm WARN node_modules/tiptap
npm WARN tiptap@"^1.32.2" from the root project
npm WARN 1 more (tiptap-extensions)
npm WARN ERESOLVE overriding peer dependency
npm WARN While resolving: tiptap-extensions@1.35.2
npm WARN Found: vue@3.2.31
npm WARN node_modules/vue
npm WARN peerOptional vue@"^2 || ^3.2.13" from @vue/babel-preset-app@5.0.1
npm WARN node_modules/@vue/babel-preset-app
npm WARN @vue/babel-preset-app@"^5.0.1" from @vue/cli-plugin-babel@5.0.1
npm WARN node_modules/@vue/cli-plugin-babel
npm WARN 5 more (@vue/server-renderer, vue-cookie-next, vue-router, vuex, the root project)
npm WARN
npm WARN Could not resolve dependency:
npm WARN peer vue@"^2.5.17" from tiptap-extensions@1.35.2
npm WARN node_modules/tiptap-extensions
npm WARN tiptap-extensions@"^1.35.2" from the root project
npm WARN
npm WARN Conflicting peer dependency: vue@2.6.14
npm WARN node_modules/vue
npm WARN peer vue@"^2.5.17" from tiptap-extensions@1.35.2
npm WARN node_modules/tiptap-extensions
npm WARN tiptap-extensions@"^1.35.2" from the root project
added 113 packages, removed 54 packages, changed 23 packages, and audited 988 packages in 7s
104 packages are looking for funding
run `npm fund` for details
9 vulnerabilities (8 moderate, 1 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Run `npm audit` for details.
โ junyharang_dev_commnunity_client git:(master) โ npm install @tiptap/vue-3 @tiptap/starter-kit
added 36 packages, and audited 1024 packages in 17s
128 packages are looking for funding
run `npm fund` for details
9 vulnerabilities (8 moderate, 1 high)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
โ junyharang_dev_commnunity_client git:(master) โ
์ฃผ๋ํ๋์ npm์ ์ด์ฉํด์ ์ค์น๋ฅผ ํด ์ค ๊ฒ์ด์์.
๐ฝ ์ฌ์ฉ ๋ฐฉ๋ฒ
<template>
<editor-content :editor="editor" />
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
content: '<p>I’m running Tiptap with Vue.js. ๐</p>',
extensions: [
StarterKit,
],
})
},
beforeUnmount() {
this.editor.destroy()
},
}
</script>
๊ธฐ๋ณธ์ ์ธ Code๋ ์์ ๊ฐ์ด ์ด์ฉํ ์ ์๋๋ฐ, component/Tiptap.vue์ ๊ฐ์ Component๋ฅผ ๋ง๋ค์ด์ ์์ ์์ ์ฝ๋๋ฅผ ์ ๋ ฅํด์ ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด์์.
๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ Compositon API๋ฅผ ์ด์ฉํ์ฌ `useEditor`๋ฅผ ์ด์ฉํ ์ ์๋ ๊ฒ์ด์์.
<template>
<editor-content :editor="editor" />
</template>
<script>
import { useEditor, EditorContent } from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
export default {
components: {
EditorContent,
},
setup() {
const editor = useEditor({
content: '<p>I’m running Tiptap with Vue.js. ๐</p>',
extensions: [
StarterKit,
],
})
return { editor }
},
}
</script>
์ฃผ๋ํ๋์ ์๋์ ๊ฐ์ด ์ด์ฉํ ๊ฒ์ด์์. ์ด์ ๋ง์ถ์ด์ ๋ด์ฉ์ ์์ฑํด ๋ณผ ๊ฒ์ด์์.
<template>
<div class="editor" v-if="editor">
<menu-bar class="editor__header" :editor="editor" />
<!-- ์์์ ํ -->
<input
type="color"
@input="
editor
.chain()
.focus()
.setColor($event.target.value)
.run()
"
:value="editor.getAttributes('textStyle').color"
/>
<!-- ํฐํธ ํฌ๊ธฐ -->
<floating-menu
class="floating-menu"
:tippy-options="{ duration: 100 }"
:editor="editor"
v-if="editor"
>
<button
@click="
editor
.chain()
.focus()
.toggleHeading({ level: 1 })
.run()
"
:class="{ 'is-active': editor.isActive('heading', { level: 1 }) }"
>
H1
</button>
<button
@click="
editor
.chain()
.focus()
.toggleHeading({ level: 2 })
.run()
"
:class="{ 'is-active': editor.isActive('heading', { level: 2 }) }"
>
H2
</button>
<button
@click="
editor
.chain()
.focus()
.toggleBulletList()
.run()
"
:class="{ 'is-active': editor.isActive('bulletList') }"
>
Bullet List
</button>
</floating-menu>
<!-- ํฐํธ ์ ํ -->
<editor-content class="editor__content" :editor="editor" />
</div>
</template>
<script>
import { Editor, EditorContent, FloatingMenu } from "@tiptap/vue-3";
import StarterKit from "@tiptap/starter-kit";
import TaskList from "@tiptap/extension-task-list";
import TaskItem from "@tiptap/extension-task-item";
import Highlight from "@tiptap/extension-highlight";
import CharacterCount from "@tiptap/extension-character-count";
import TextStyle from "@tiptap/extension-text-style";
import MenuBar from "@/components/tiptap/MenuBar.vue";
import { Color } from "@tiptap/extension-color";
export default {
components: {
EditorContent,
FloatingMenu,
MenuBar
},
data() {
return {
editor: null
};
},
mounted() {
this.editor = new Editor({
extensions: [
StarterKit,
Highlight,
TaskList,
TaskItem,
CharacterCount.configure({
limit: 10000
}),
TextStyle,
Color
],
content: `
<h2>
Hi there,
</h2>
<p>
this is a <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
</p>
<p>
Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
</p>
<p>
I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
</p>
<blockquote>
Wow, that’s amazing. Good work, boy! ๐
<br />
— Mom
</blockquote>
`
});
},
methods: {
beforeUnmount() {
this.editor.destroy();
}
}
};
</script>
์์ง Extention Module์ ์ค์นํ์ง ์์๊ธฐ ๋๋ฌธ์ Error๊ฐ ์๊ฒ ๋ฉ๋๋ค.
๐ ํ์ฅ Module ์ค์นํ๊ธฐ
Prosemirror Editor์ ๊ฐ์ ์ด์ tiptap์ ๊ฐ์ ์ ํ์ํ ๊ธฐ๋ฅ๋ง ๋ถ๋ฌ์ ์ด์ฉํ ์ ์๋ค๋ ๊ฒ์ด์์.
ํ์ฅ ๊ธฐ๋ฅ์ ์ด์ฉํ๊ธฐ ์ํด์๋ ํ์ฅ Module์ ์ถ๊ฐ๋ก ์ค์นํด์ผ ํ๋ ๊ฒ์ด์์.
๐ฝ ์ค์น
โ npm ์ด์ฉ ์ค์น
npm install tiptap-extensions --save
โ yarn ์ด์ฉ ์ค์น
์ด๋ฒ์๋ ์ฃผ๋ํ๋์ yarn์ ์ด์ฉํด์ ์ค์น ํด ๋ณผ ๊ฒ์ด์์.
๐ฝ ์ฌ์ฉ ๋ฐฉ๋ฒ
์ต์ด ์ค์นํ tiptap์ ์ถ๊ฐ๋ก extensions๋ฅผ ์ ์ฉํ๋ฉด ๋๋ ๊ฒ์ด์์.
import { Editor, EditorContent } from 'tiptap'
import { Heading } from 'tiptap-extensions'
const editor = new Editor({
extensions: [ new Heading(), ],
})
`extensions: [ new Heading() ]`์ฒ๋ผ ํ์ํ ๊ธฐ๋ฅ์ ๊ฐ์ฒด(์ธ์คํด์ค)๋ฅผ ์ถ๊ฐํด์ ๋ถ๋ฌ์์ ์ด์ฉํ๋ฉด ๋๋ ๊ฒ์ด์์.
๋ํ ๊ฐ ๊ธฐ๋ฅ์ ์ธ์คํด์ค๋ ์์ ๋ง์ ์ค์ ์ ์ถ๊ฐ / ๋ณ๊ฒฝํ ์ ์๋ ๊ฒ์ด์์. ๊ทธ๋์ ๋ถ๋ฌ ์ฌ ๊ธฐ๋ฅ์ ์ค์ ๊ฐ๋ ์ ์ดํด๋ด์ผ Error๋ฅผ ์ต์ํ ํ ์ ์๋ ๊ฒ์ด์์. `Heaing()`์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ด `level` Option`๋ ์๋ ๊ฒ์ด์์.
const editor = new Editor({
new Heading({
leve: [1, 2, 3],
}),
})
`tiptap-extensions`์๋ ๋ค์ํ ๊ธฐ๋ฅ๋ค์ด ์ค๋น ๋์ด ์๋ ๊ฒ์ด์์.
import { Editor, EditorContent } from 'tiptap'
import { Bold, Italic, Link, HardBreak, Heading } from 'tiptap-extensions'
const editor = new Editor({
extensions: [
new Bold(),
new Italic(),
new Link(),
new HardBread(),
new Haading()
],
})
๐ฝ ํ๋ฉด
๐ฆ DevInquryReplyVO.java
์๋ ํ์ธ์.
์ฃผ๋ํ๋์ด ์์ฑํ ๋ด์ฉ์ด ๋์์ด ๋์
จ์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค!
ํน์๋ผ๋ ์ ๋ชป๋ ์ ๋ณด๊ฐ ์๋ค๋ฉด ๋๊ธ์ ์์คํ ํผ๋๋ฐฑ ๋ถํ ๋๋ฆฌ๊ฒ ์ต๋๋ค!
'์ฃผ๋ํ๋'์ Blog ๊ธ์ ๋ฐ๋ก ๋ณด๊ดํ์์ง ๋ง์๊ณ , '์ฃผ๋ํ๋' Blog์์ ์ฌ๋ฌ๋ถ์ ํญ์ ๊ธฐ๋ค๋ฆฌ๊ณ ์์ผ๋ ์ด ๊ณณ์์ ์ด์ฉ ํด ์ฃผ์๋ฉด ๊ณ ๋ง๊ฒ ์ต๋๋ค.
์ผ๋ถ ์ ๋ณด๋ฅผ ํผ๊ฐ์ ์ ์ ๋ฆฌ๋ฅผ ํ๊ณ ์ ํ์ค ๋๋ ๋ฐ๋์ ์๋์ ๊ฐ์ด ์ถ์ฒ๋ฅผ ๋จ๊ฒจ ์ฃผ์๊ธฐ ๋ฐ๋ผ๊ฒ ์ต๋๋ค.
์ถ์ฒ : ์ฃผ๋ํ๋ ๊ฐ๋ฐ Blog - '[Blog URL]'
โ 2022. '์ฃผ๋ํ๋' all rights reserved.
junyharang8592@gmail.com
'Front-End ์์ ์ค > Vue.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Vue.js] Vue-Cookies (0) | 2022.04.02 |
---|---|
[Vue.js] Template refs (0) | 2022.03.19 |
[Vue.js] Props (0) | 2022.03.19 |
[Vue.js] axios ์ค์น (0) | 2022.03.18 |
[Vue.js] vue-router.esm-bundler.js?ec2d:72 [Vue Router warn]: No match found for location with path "/support/devInquryList" (0) | 2022.03.15 |