安装相关依赖
- yarn add tinymce
- yarn add @tinymce/tinymce-vue
复制依赖包
在vue3的项目 目录的 public 里新建 tinymce文件夹,把node_modules里的skins文件复制到 tinymce文件夹里
下载语言包
封装组件
<template>
<div class="tinymce-editor">
<textarea :id="tinymceId" class="tinymce-textarea" :placeholder="placeholder" />
</div>
</template>
<script lang='ts'>
import tinymce from 'tinymce/tinymce'
import 'tinymce/themes/silver'
import 'tinymce/plugins/image' // 插入上传图片插件
import 'tinymce/plugins/media' // 插入视频插件
import 'tinymce/plugins/table' // 插入表格插件
import 'tinymce/plugins/lists' // 列表插件
import 'tinymce/plugins/wordcount' // 字数统计插件
import 'tinymce/icons/default'
import { getToken } from '@/utils/auth'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import {
defineComponent,
nextTick,
onMounted,
reactive,
toRefs,
watch
} from 'vue'
import { useStore } from 'vuex'
export default defineComponent({
name: 'Tinymce',
props: {
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String],
default: 'lists image table wordcount'
},
value: {
type: String,
default: ''
},
height: {
type: [Number, String],
required: false,
default: 360
},
width: {
type: [Number, String],
required: false,
default: '100%'
},
type: {
type: [String],
default: 'img'
},
placeholder: {
type: [String],
default: ''
},
uid: {
type: String,
default: ''
},
toolbar1: {
type: [String],
default:
'undo redo | fontsizeselect | fontselect | formatselect | removeformat | bold italic forecolor backcolor | alignleft aligncenter alignright alignjustify | lists image table | bullist numlist outdent indent'
},
},
setup(props, context) {
const store = useStore()
const state: any = reactive({
tinymceId:
props.uid + 'tinymce-deitor-' + new Date().getTime().toString(),
hasChange: false,
hasInit: false,
axiosBaseUrl: store.getters.axiosBaseUrl
})
watch(
() => props.value,
(newVal, oldVal) => {
if (!state.hasChange && state.hasInit) {
nextTick(() => {
;(window as any).tinymce
.get(state.tinymceId)
.setContent(newVal || '')
})
}
}
)
const destroyTinymce = () => {
const tinymce = (window as any).tinymce.get(state.tinymceId)
if (tinymce) {
tinymce.destroy()
tinymce.remove()
}
}
const setContent = (value: any) => {
if ((window as any).tinymce) {
;(window as any).tinymce.get(state.tinymceId).setContent(value)
}
}
const getContent = () => {
;(window as any).tinymce.get(state.tinymceId).getContent()
}
const imageSuccessCBK = (arr: any) => {
arr.forEach((v: any) => {
;(window as any).tinymce
.get(state.tinymceId)
.insertContent(`<img class="wscnph" src="${v.url}" >`)
})
}
const clickTinymceEditor = () => {
alert('1')
context.emit('clickTinymceEditor')
}
onMounted(() => {
tinymce.init({
selector: '#' + state.tinymceId,
language_url: '/tinymce/langs/zh-Hans.js', // 语言包的路径
language: 'zh-Hans', //语言
skin_url: '/tinymce/skins/ui/oxide', // skin路径
height: props.height, //编辑器高度
width: props.width,
branding: false, //是否禁用“Powered by TinyMCE”
menubar: false, //顶部菜单栏显示
plugins: props.plugins,
toolbar1: props.toolbar1,
// toolbar2: props.toolbar2,
resize: false,
paste_data_images: true,
init_instance_callback: (editor) => {
if (props.value) {
editor.setContent(props.value)
}
state.hasInit = true
editor.on('NodeChange Change KeyUp SetContent', () => {
state.hasChange = true
context.emit('input', editor.getContent())
})
editor.on('click', () => {
context.emit('clickTinymceEditor')
})
},
setup(editor) {
editor.on('FullscreenStateChanged', (e) => {
// _this.fullscreen = e.state
})
},
images_upload_handler(blobInfo, success, failure, progress) {
if (progress) {
progress(0)
}
const token = getToken()
if (token) {
const formData = new FormData()
formData.append('file', blobInfo.blob(), blobInfo.filename())
formData.append('Type', props.type)
axios({
url: state.axiosBaseUrl + '/Common/UploadFile',
method: 'post',
headers: { 'Content-Type': 'multipart/form-data', token: token },
data: formData
})
.then((res: any) => {
if (res.data.code == 200) {
success(res.data.data.FileUrl)
if (progress) {
progress(100)
}
} else {
ElMessage({
showClose: true,
message: `${res.data.msg}`,
type: 'error'
})
}
})
.catch((err) => {
failure('出现未知问题,请刷新页面重新上传!')
console.log(err)
})
} else {
failure('登录失效,请重新登录!')
}
}
})
})
return {
...toRefs(state),
setContent,
clickTinymceEditor
}
}
})
</script>
<style lang="scss" scoped>
.tinymce-textarea {
font-size: 14px;
& > p {
text-indent: 2em;
}
touch-action: none;
}
</style>
调用
<tinymce-editor class="setTinymce" ref="tinymceEditor"
width="800" height="300" :value=info"
@input="value => { info= value }"></tinymce-editor>
// import TinymceEditor from '@/components/TinymceCom.vue'