文章目录
- 一、ueditor(百度富文本编辑器)
- 安装
- 使用并二次封装组件
- 二、KindEditor
- 下载文件
- 新建组件及使用
一、ueditor(百度富文本编辑器)
参考 ueditor 和 vue-ueditor-wrap
这里直接使用 封装好的vue组件vue-ueditor-wrap
vue3版本
安装
npm i vue-ueditor-wrap@3.x -S
or
yarn add vue-ueditor-wrap@3.x
使用并二次封装组件
- main.ts
import VueUeditorWrap from 'vue-ueditor-wrap';
import App from '@/App/index.vue';
const app = createApp(App).use(VueUeditorWrap)
- ueditor/index.vue
<template>
<vue-ueditor-wrap
v-model="content"
:config="VueUeditorWrapConfig"
:editor-id="editorId"
></vue-ueditor-wrap>
</template>
<script>
import { default as VueUeditorWrapConfig } from "./ueditor.js";
import { RandomNumber } from '@/utils'
export default {
props: {
value: [String],
property: {
type: Object,
default() {
return {};
},
},
},
model: {
prop: "value", // 指定 v-model 要绑定的参数叫什么名字,来自于 props 中定义的参数
event: "change", // 指定要触发的事件名字,将被用于 $emit
},
data() {
return {
show: false,
VueUeditorWrapConfig,
isPosting: false,
edit_show: true,
index: 0,
editorId: 'editor' + RandomNumber()
};
},
computed: {
content: {
get() {
return this.value;
},
set(val) {
this.$emit("change", val);
},
},
},
};
</script>
<style lang="less" scoped>
/* 弹框输入框长度 */
.lengthWidth {
width: 80%;
}
.editor_if {
width: 100%;
height: 400px;
}
.edui1 {
z-index: 90 !important;
}
</style>
- ueditor/ueditor.js
// let env = process.env.NODE_ENV || ''
let ueditorPath = ''
// if (env === 'development') {
// ueditorPath = '/static/UEditor/'
// } else if (env === 'production') {
// ueditorPath = '/static/UEditor/'
// } else {
// ueditorPath = '/static/UEditor/'
// }
ueditorPath = '/ueditor/'
export default {
UEDITOR_HOME_URL: ueditorPath,
maximumWords: 1000 * 100,
// toolbars: [
// [
// 'source', '|', 'undo', 'redo', '|',
// 'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
// 'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
// 'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
// 'directionalityltr', 'directionalityrtl', 'indent', '|',
// 'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
// 'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
// 'horizontal', 'date', 'time',
// 'inserttable', 'simpleupload', 'preview',
// ]
// ],
toolbars: [
[
'source', '|', 'undo', 'redo', '|',
'bold', 'italic', 'underline', 'fontborder', 'strikethrough', 'superscript', 'subscript', 'removeformat', 'formatmatch', 'autotypeset', 'blockquote', 'pasteplain', '|', 'forecolor', 'backcolor', 'insertorderedlist', 'insertunorderedlist', 'selectall', 'cleardoc', '|',
'rowspacingtop', 'rowspacingbottom', 'lineheight', '|',
'customstyle', 'paragraph', 'fontfamily', 'fontsize', '|',
'directionalityltr', 'directionalityrtl', 'indent', '|',
'justifyleft', 'justifycenter', 'justifyright', 'justifyjustify', '|', 'touppercase', 'tolowercase', '|',
'imagenone', 'imageleft', 'imageright', 'imagecenter', '|',
'horizontal'
]
],
enableAutoSave: false,
elementPathEnabled: false,
disabledTableInTable: false,
serverUrl: '' // 暂无接口 APP_CONFIG.baseURL + '/file/upload'
}
使用上述定义组件即可显示下图效果
二、KindEditor
下载文件
kindeditor
放在本地静态目录
新建组件及使用
在组件文件夹内新建以下文件夹及文件
- kind-editor/index.vue
<template>
<div class="kindeditor">
<textarea :id="id" name="content" v-model="state.outContent"></textarea>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, reactive, watch } from "vue"
import '@public/kind-editor/themes/default/default.css'
import '@public/kind-editor/kindeditor-all.js'
import '@public/kind-editor/lang/zh-CN.js'
import '@public/kind-editor/lang/en.js'
export default defineComponent({
name: 'kind-editor',
props: {
modelValue: {
type: String,
default: ''
},
id: {
type: String,
required: true
},
width: {
type: String
},
height: {
type: String
},
minWidth: {
type: Number,
default: 650
},
minHeight: {
type: Number,
default: 100
},
items: {
type: Array,
default: function () {
return [
'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'code', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image',
'media', 'insertfile', 'table', 'hr', 'pagebreak',
'anchor', 'link', 'unlink',
]
}
},
noDisableItems: {
type: Array,
default: function () {
return ['source', 'fullscreen']
}
},
filterMode: {
type: Boolean,
default: true
},
htmlTags: {
type: Object,
default: function () {
return {
font: ['color', 'size', 'face', '.background-color'],
span: ['style'],
div: ['class', 'align', 'style'],
table: ['class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'style'],
'td,th': ['class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor', 'style'],
a: ['class', 'href', 'target', 'name', 'style'],
embed: ['src', 'width', 'height', 'type', 'loop', 'autostart', 'quality',
'style', 'align', 'allowscriptaccess', '/'],
img: ['src', 'width', 'height', 'border', 'alt', 'title', 'align', 'style', '/'],
hr: ['class', '/'],
br: ['/'],
'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6': ['align', 'style'],
'tbody,tr,strong,b,sub,sup,em,i,u,strike': []
}
}
},
wellFormatMode: {
type: Boolean,
default: true
},
resizeType: {
type: Number,
default: 2
},
themeType: {
type: String,
default: 'default'
},
langType: {
type: String,
default: 'en'
},
designMode: {
type: Boolean,
default: true
},
fullscreenMode: {
type: Boolean,
default: false
},
basePath: {
type: String
},
themesPath: {
type: String
},
pluginsPath: {
type: String,
default: ''
},
langPath: {
type: String
},
minChangeSize: {
type: Number,
default: 5
},
loadStyleMode: {
type: Boolean,
default: true
},
urlType: {
type: String,
default: ''
},
newlineTag: {
type: String,
default: 'p'
},
pasteType: {
type: Number,
default: 2
},
dialogAlignType: {
type: String,
default: 'page'
},
shadowMode: {
type: Boolean,
default: true
},
zIndex: {
type: Number,
default: 811213
},
useContextmenu: {
type: Boolean,
default: true
},
syncType: {
type: String,
default: 'form'
},
indentChar: {
type: String,
default: '\t'
},
cssPath: {
type: [String, Array]
},
cssData: {
type: String
},
bodyClass: {
type: String,
default: 'ke-content'
},
colorTable: {
type: Array
},
afterCreate: {
type: Function
},
afterChange: {
type: Function
},
afterTab: {
type: Function
},
afterFocus: {
type: Function
},
afterBlur: {
type: Function
},
afterUpload: {
type: Function
},
uploadJson: {
type: String
},
fileManagerJson: {
type: Function
},
allowPreviewEmoticons: {
type: Boolean,
default: true
},
allowImageUpload: {
type: Boolean,
default: true
},
allowFlashUpload: {
type: Boolean,
default: true
},
allowMediaUpload: {
type: Boolean,
default: true
},
allowFileUpload: {
type: Boolean,
default: true
},
allowFileManager: {
type: Boolean,
default: false
},
fontSizeTable: {
type: Array,
default: function () {
return ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px']
}
},
imageTabIndex: {
type: Number,
default: 0
},
formatUploadUrl: {
type: Boolean,
default: true
},
fullscreenShortcut: {
type: Boolean,
default: false
},
extraFileUploadParams: {
type: Array,
default: function () {
return []
}
},
filePostName: {
type: String,
default: 'imgFile'
},
fillDescAfterUploadImage: {
type: Boolean,
default: false
},
afterSelectFile: {
type: Function
},
pagebreakHtml: {
type: String,
default: '<hr style=”page-break-after: always;” class=”ke-pagebreak” />'
},
allowImageRemote: {
type: Boolean,
default: true
},
autoHeightMode: {
type: Boolean,
default: false
},
fixToolBar: {
type: Boolean,
default: false
},
tabIndex: {
type: Number
}
},
setup(props, { emit }) {
const state = reactive({
editor: {} as any,
outContent: props.modelValue
})
console.log('state_state', state)
watch(() => props.modelValue, (val: any) => {
state.editor && val !== state.outContent && state.editor.html(val)
})
watch(() => state.outContent, (val: any) => {
emit('update:modelValue', val)
})
onMounted(async() => {
state.editor = (window as any).KindEditor.create('#' + props.id, {
width: props.width,
height: props.height,
minWidth: props.minWidth,
minHeight: props.minHeight,
items: props.items,
noDisableItems: props.noDisableItems,
filterMode: props.filterMode,
htmlTags: props.htmlTags,
wellFormatMode: props.wellFormatMode,
resizeType: props.resizeType,
themeType: props.themeType,
langType: props.langType,
designMode: props.designMode,
fullscreenMode: props.fullscreenMode,
basePath: props.basePath,
themesPath: props.cssPath,
pluginsPath: props.pluginsPath,
langPath: props.langPath,
minChangeSize: props.minChangeSize,
loadStyleMode: props.loadStyleMode,
urlType: props.urlType,
newlineTag: props.newlineTag,
pasteType: props.pasteType,
dialogAlignType: props.dialogAlignType,
shadowMode: props.shadowMode,
zIndex: props.zIndex,
useContextmenu: props.useContextmenu,
syncType: props.syncType,
indentChar: props.indentChar,
cssPath: props.cssPath,
cssData: props.cssData,
bodyClass: props.bodyClass,
colorTable: props.colorTable,
afterCreate: props.afterCreate,
afterChange: function () {
props.afterChange
state.outContent = this.html()
},
afterTab: props.afterTab,
afterFocus: props.afterFocus,
afterBlur: props.afterBlur,
afterUpload: props.afterUpload,
uploadJson: props.uploadJson,
fileManagerJson: props.fileManagerJson,
allowPreviewEmoticons: props.allowPreviewEmoticons,
allowImageUpload: props.allowImageUpload,
allowFlashUpload: props.allowFlashUpload,
allowMediaUpload: props.allowMediaUpload,
allowFileUpload: props.allowFileUpload,
allowFileManager: props.allowFileManager,
fontSizeTable: props.fontSizeTable,
imageTabIndex: props.imageTabIndex,
formatUploadUrl: props.formatUploadUrl,
fullscreenShortcut: props.fullscreenShortcut,
extraFileUploadParams: props.extraFileUploadParams,
filePostName: props.filePostName,
fillDescAfterUploadImage: props.fillDescAfterUploadImage,
afterSelectFile: props.afterSelectFile,
pagebreakHtml: props.pagebreakHtml,
allowImageRemote: props.allowImageRemote,
autoHeightMode: props.autoHeightMode,
fixToolBar: props.fixToolBar,
tabIndex: props.tabIndex
})
})
return {
state
}
}
})
</script>
<style>
</style>
- 使用
<KindEditor id="KindEditor012" />
import KindEditor from '@/component/kind-editor/index.vue'
export default defineComponent({
components: {
KindEditor
},
setup() {
return {
}
}
- 效果