mod: rebuild editor

This commit is contained in:
KUN1007 2023-09-03 18:50:57 +08:00
parent f944b4cc1a
commit 07ce954a2d
10 changed files with 207 additions and 123 deletions

View file

@ -0,0 +1,86 @@
<script setup lang="ts">
import { onBeforeMount, ref } from 'vue'
import WangEditor from '@/components/wang-editor/WangEditor.vue'
import KUNGalgameFooter from '@/components/KUNGalgameFooter.vue'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia'
//
import { debounce } from '@/utils/debounce'
const topicData = storeToRefs(useKUNGalgameEditStore())
//
const topicTitle = ref('')
//
const maxInputLength = 40
onBeforeMount(() => {
if (topicData.isSave.value) {
topicTitle.value = topicData.title.value
}
})
//
const handelInput = () => {
// 40
if (topicTitle.value.length > maxInputLength) {
topicTitle.value = topicTitle.value.slice(0, maxInputLength)
}
//
if (topicTitle.value.trim() === '') {
return
}
//
const debouncedInput = debounce(() => {
// xss
topicData.title.value = topicTitle.value
}, 300)
//
debouncedInput()
}
</script>
<template>
<!-- 话题的标题 -->
<div class="title">
<input
type="text"
placeholder="请输入话题的标题40字以内"
v-model="topicTitle"
@input="handelInput"
:maxlength="maxInputLength"
/>
</div>
</template>
<style lang="scss" scoped>
/* 话题的发布标题 */
.title {
width: 100%;
}
/* 话题标题的输入框 */
.title input {
color: var(--kungalgame-font-color-2);
/* 距离外轮廓的距离 */
padding: 7px;
/* 内边距盒子 */
box-sizing: border-box;
width: 100%;
/* 标题输入字体大小 */
font-size: 40px;
border: none;
margin-bottom: 10px;
}
/* 标题输入框 focus 之后的样式 */
.title input:focus {
box-shadow: 0px 0px 5px var(--kungalgame-blue-4);
}
</style>

View file

@ -2,14 +2,32 @@
编辑器实例共用组件 编辑器实例共用组件
--> -->
<script setup lang="ts"> <script setup lang="ts">
import {
defineAsyncComponent,
onBeforeMount,
onBeforeUnmount,
ref,
shallowRef,
} from 'vue'
//
import '@wangeditor/editor/dist/css/style.css' import '@wangeditor/editor/dist/css/style.css'
import '@/styles/editor/editor.scss' import '@/styles/editor/editor.scss'
import { IDomEditor } from '@wangeditor/editor' import { IDomEditor, IEditorConfig } from '@wangeditor/editor'
import { onBeforeMount, onBeforeUnmount, ref, shallowRef } from 'vue' import { Editor } from '@wangeditor/editor-for-vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
//
import { IToolbarConfig } from '@wangeditor/editor'
import { Toolbar } from '@wangeditor/editor-for-vue'
//
const Title = defineAsyncComponent(
() => import('@/components/wang-editor/Title.vue')
)
// store // store
import { useKUNGalgameEditStore } from '@/store/modules/edit' import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
// xss // xss
import DOMPurify from 'dompurify' import DOMPurify from 'dompurify'
// //
@ -18,7 +36,12 @@ import { debounce } from '@/utils/debounce'
const topicData = storeToRefs(useKUNGalgameEditStore()) const topicData = storeToRefs(useKUNGalgameEditStore())
// //
const props = defineProps(['height', 'isShowToolbar', 'isShowAdvance']) const props = defineProps<{
height: number
isShowToolbar: boolean
isShowAdvance: boolean
isShowTitle: boolean
}>()
// //
const editorHeight = `height: ${props.height}px` const editorHeight = `height: ${props.height}px`
@ -32,7 +55,7 @@ const valueHtml = ref('')
const textCount = ref(0) const textCount = ref(0)
// //
const editorConfig = { const editorConfig: Partial<IEditorConfig> = {
placeholder: 'Moe Moe Moe!', placeholder: 'Moe Moe Moe!',
readOnly: false, readOnly: false,
MENU_CONF: { MENU_CONF: {
@ -53,7 +76,18 @@ const editorConfig = {
}, },
} }
const handleCreated = (editor: IDomEditor) => {} const keys: string[] = []
//
const toolbarConfig: Partial<IToolbarConfig> = {
excludeKeys: ['uploadVideo'].concat(keys),
}
const handleCreated = (editor: IDomEditor) => {
console.log(editor.getAllMenuKeys())
editorRef.value = editor // editor
}
// //
onBeforeMount(() => { onBeforeMount(() => {
@ -92,9 +126,11 @@ const handleChange = (editor: IDomEditor) => {
<Toolbar <Toolbar
class="toolbar-container" class="toolbar-container"
:editor="editorRef" :editor="editorRef"
:defaultConfig="toolbarConfig"
:mode="$props.isShowAdvance ? 'default' : 'simple'" :mode="$props.isShowAdvance ? 'default' : 'simple'"
v-show="props.isShowToolbar" v-show="props.isShowToolbar"
/> />
<Title />
<Editor <Editor
:style="editorHeight" :style="editorHeight"
v-model="valueHtml" v-model="valueHtml"
@ -109,16 +145,11 @@ const handleChange = (editor: IDomEditor) => {
<style lang="scss" scoped> <style lang="scss" scoped>
/* 编辑器的样式 */ /* 编辑器的样式 */
.editorwrapper { .editorwrapper {
/* 编辑器的 border */
border: 1px solid var(--kungalgame-blue-4);
box-sizing: border-box; box-sizing: border-box;
/* 编辑器的宽度 */ /* 编辑器的宽度 */
width: 100%; width: 100%;
margin: 0 auto; margin: 0 auto;
z-index: 1008; /* 按需定义 */ z-index: 9999;
}
.toolbar-container {
border-bottom: 1px solid var(--kungalgame-blue-4);
} }
.count { .count {
@ -128,7 +159,7 @@ const handleChange = (editor: IDomEditor) => {
align-items: center; align-items: center;
justify-content: end; justify-content: end;
color: var(--kungalgame-font-color-0); color: var(--kungalgame-font-color-0);
background-color: var(--kungalgame-white); background-color: var(--kungalgame-white-9);
} }
@media (max-width: 700px) { @media (max-width: 700px) {

View file

@ -0,0 +1,62 @@
;[
'bold',
'underline',
'italic',
'through',
'code',
'sub',
'sup',
'clearStyle',
'color',
'bgColor',
'fontSize',
'fontFamily',
'indent',
'delIndent',
'justifyLeft',
'justifyRight',
'justifyCenter',
'justifyJustify',
'lineHeight',
'insertImage',
'deleteImage',
'editImage',
'viewImageLink',
'imageWidth30',
'imageWidth50',
'imageWidth100',
'divider',
'emotion',
'insertLink',
'editLink',
'unLink',
'viewLink',
'codeBlock',
'blockquote',
'headerSelect',
'header1',
'header2',
'header3',
'header4',
'header5',
'todo',
'redo',
'undo',
'fullScreen',
'enter',
'bulletedList',
'numberedList',
'insertTable',
'deleteTable',
'insertTableRow',
'deleteTableRow',
'insertTableCol',
'deleteTableCol',
'tableHeader',
'tableFullWidth',
'insertVideo',
'uploadVideo',
'editVideoSize',
'uploadImage',
'codeSelectLang',
]

View file

@ -5,7 +5,7 @@ import 'animate.css'
import { currBackground } from '@/hooks/useBackgroundPicture' import { currBackground } from '@/hooks/useBackgroundPicture'
import KUNGalgameTopBar from '@/components/TopBar/KUNGalgameTopBar.vue' import KUNGalgameTopBar from '@/components/top-bar/KUNGalgameTopBar.vue'
</script> </script>
<template> <template>

View file

@ -29,12 +29,12 @@ u {
:root { :root {
/* textarea - css vars */ /* textarea - css vars */
--w-e-textarea-bg-color: var(--kungalgame-white); --w-e-textarea-bg-color: var(--kungalgame-white-9);
--w-e-textarea-color: var(--kungalgame-font-color-3); --w-e-textarea-color: var(--kungalgame-font-color-3);
--w-e-textarea-border-color: var(--kungalgame-blue-1); --w-e-textarea-border-color: var(--kungalgame-blue-1);
--w-e-textarea-slight-border-color: var(--kungalgame-blue-4); --w-e-textarea-slight-border-color: var(--kungalgame-blue-4);
--w-e-textarea-slight-color: var(--kungalgame-font-color-0); --w-e-textarea-slight-color: var(--kungalgame-font-color-0);
--w-e-textarea-slight-bg-color: var(--kungalgame-white); --w-e-textarea-slight-bg-color: var(--kungalgame-white-9);
--w-e-textarea-selected-border-color: var(--kungalgame-blue-1); --w-e-textarea-selected-border-color: var(--kungalgame-blue-1);
/* 选中的元素,如选中了分割线 */ /* 选中的元素,如选中了分割线 */
--w-e-textarea-handler-bg-color: var(--kungalgame-blue-4); --w-e-textarea-handler-bg-color: var(--kungalgame-blue-4);
@ -42,9 +42,9 @@ u {
/* toolbar - css vars */ /* toolbar - css vars */
--w-e-toolbar-color: var(--kungalgame-font-color-1); --w-e-toolbar-color: var(--kungalgame-font-color-1);
--w-e-toolbar-bg-color: var(--kungalgame-white); --w-e-toolbar-bg-color: var(--kungalgame-trans-blue-0);
--w-e-toolbar-active-color: var(--kungalgame-font-color-3); --w-e-toolbar-active-color: var(--kungalgame-font-color-3);
--w-e-toolbar-active-bg-color: var(--kungalgame-white); --w-e-toolbar-active-bg-color: var(--kungalgame-trans-blue-1);
--w-e-toolbar-disabled-color: var(--kungalgame-red-4); --w-e-toolbar-disabled-color: var(--kungalgame-red-4);
--w-e-toolbar-border-color: var(--kungalgame-blue-4); --w-e-toolbar-border-color: var(--kungalgame-blue-4);

View file

@ -1,80 +1,22 @@
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeMount, ref } from 'vue' import WangEditor from '@/components/wang-editor/WangEditor.vue'
import WangEditor from '@/components/WangEditor.vue'
import Tags from './components/Tags.vue' import Tags from './components/Tags.vue'
import Footer from './components/Footer.vue' import Footer from './components/Footer.vue'
import KUNGalgameFooter from '@/components/KUNGalgameFooter.vue' import KUNGalgameFooter from '@/components/KUNGalgameFooter.vue'
// store
import { useKUNGalgameEditStore } from '@/store/modules/edit'
import { storeToRefs } from 'pinia'
//
import { debounce } from '@/utils/debounce'
const topicData = storeToRefs(useKUNGalgameEditStore())
//
const topicTitle = ref('')
//
const maxInputLength = 40
onBeforeMount(() => {
if (topicData.isSave.value) {
topicTitle.value = topicData.title.value
}
})
//
const handelInput = () => {
// 40
if (topicTitle.value.length > maxInputLength) {
topicTitle.value = topicTitle.value.slice(0, maxInputLength)
}
//
if (topicTitle.value.trim() === '') {
return
}
//
const debouncedInput = debounce(() => {
// xss
topicData.title.value = topicTitle.value
}, 300)
//
debouncedInput()
}
</script> </script>
<template> <template>
<div class="root"> <div class="root">
<!-- 内容区容器 --> <!-- 内容区容器 -->
<div class="container"> <div class="container">
<!-- 内容区容器 --> <!-- 编辑器 -->
<div class="content"> <WangEditor
<!-- 内容区的头部 --> class="editor"
<div class="header"> :height="400"
<!-- 话题的标题 --> :isShowToolbar="true"
<div class="title"> :isShowAdvance="true"
<input :isShowTitle="true"
type="text" />
placeholder="请输入话题的标题40字以内"
v-model="topicTitle"
@input="handelInput"
:maxlength="maxInputLength"
/>
</div>
</div>
<!-- 编辑器 -->
<WangEditor
class="editor"
:height="400"
:isShowToolbar="true"
:isShowAdvance="true"
/>
</div>
<!-- 内容区的底部 --> <!-- 内容区的底部 -->
<div class="content-footer"> <div class="content-footer">
@ -92,10 +34,6 @@ const handelInput = () => {
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.content {
margin: 0 auto;
}
.root { .root {
height: 100vh; height: 100vh;
min-height: 1200px; min-height: 1200px;
@ -117,39 +55,6 @@ const handelInput = () => {
padding: 10px; padding: 10px;
} }
/* 容器的顶部 */
.header {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
/* 话题的发布标题 */
.title {
width: 100%;
}
/* 话题标题的输入框 */
.title input {
color: var(--kungalgame-font-color-2);
/* 距离外轮廓的距离 */
padding: 7px;
/* 内边距盒子 */
box-sizing: border-box;
width: 100%;
/* 标题输入字体大小 */
font-size: 40px;
border: 1px solid var(--kungalgame-blue-4);
background-color: var(--kungalgame-white);
margin-bottom: 10px;
}
/* 标题输入框 focus 之后的样式 */
.title input:focus {
box-shadow: 0px 0px 5px var(--kungalgame-blue-4);
}
.content-footer { .content-footer {
/* 距离内容区的距离 */ /* 距离内容区的距离 */
margin-top: 17px; margin-top: 17px;

View file

@ -9,7 +9,7 @@ import 'animate.css'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
// //
import WangEditor from '@/components/WangEditor.vue' import WangEditor from '@/components/wang-editor/WangEditor.vue'
// //
const Tags = defineAsyncComponent( const Tags = defineAsyncComponent(