|
|
<template>
|
|
|
<div class="components-tiny-mce">
|
|
|
<div
|
|
|
class="tinymce-container"
|
|
|
:class="{ 'tox-fullscreen': toxFullscreen }"
|
|
|
>
|
|
|
<Editor
|
|
|
:id="props.id"
|
|
|
:init="init"
|
|
|
api-key="i6mv006qcwsfu1t7ebisntg5w261vpowkwirnx9cnse3ho5o"
|
|
|
/>
|
|
|
<!-- 增加图片区域 -->
|
|
|
<div
|
|
|
class="add-or-upload"
|
|
|
>
|
|
|
<el-upload
|
|
|
class="upload-demo"
|
|
|
list-type="picture"
|
|
|
:action="uploadAction"
|
|
|
:headers="uploadHeaders"
|
|
|
:on-success="imageSuccessCBK"
|
|
|
:show-file-list="false"
|
|
|
:before-upload="beforeAvatarUpload"
|
|
|
>
|
|
|
<el-button
|
|
|
size="small"
|
|
|
type="primary"
|
|
|
>
|
|
|
点击上传图片
|
|
|
</el-button>
|
|
|
</el-upload>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import Editor from '@tinymce/tinymce-vue'
|
|
|
import $cookie from 'vue-cookies'
|
|
|
|
|
|
const uploadHeaders = { Authorization: $cookie.get('Authorization') }
|
|
|
const uploadAction = http.adornUrl('/admin/file/upload/element')
|
|
|
|
|
|
const props = defineProps({
|
|
|
modelValue: {
|
|
|
type: String,
|
|
|
default: ''
|
|
|
},
|
|
|
id: {
|
|
|
type: String,
|
|
|
default: function () {
|
|
|
return 'vue-tinymce-' + +new Date() + ((Math.random() * 1000).toFixed(0) + '')
|
|
|
}
|
|
|
},
|
|
|
height: {
|
|
|
type: [Number, String],
|
|
|
required: false,
|
|
|
default: 360
|
|
|
},
|
|
|
width: {
|
|
|
type: [Number, String],
|
|
|
required: false,
|
|
|
default: 'auto'
|
|
|
}
|
|
|
})
|
|
|
|
|
|
const toxFullscreen = ref(false)
|
|
|
const hasChange = ref(false)
|
|
|
const hasInit = ref(false)
|
|
|
watch(
|
|
|
() => props.modelValue,
|
|
|
val => {
|
|
|
if (!hasChange.value && hasInit.value) {
|
|
|
nextTick(() => window.tinymce.get(props.id).setContent(val || ''))
|
|
|
}
|
|
|
}
|
|
|
)
|
|
|
|
|
|
const language = computed(() => {
|
|
|
return localStorage.getItem('b2cLang') || 'zh_CN'
|
|
|
})
|
|
|
watch(language, () => {
|
|
|
destroyTinymce()
|
|
|
})
|
|
|
const emit = defineEmits(['update:modelValue'])
|
|
|
const isLoaded = ref(false)
|
|
|
const init = reactive({
|
|
|
plugins: 'preview anchor autolink codesample emoticons image link lists media searchreplace table visualblocks pagebreak insertdatetime fullscreen', // 插件 preview anchor autolink codesample emoticons image link lists media searchreplace table visualblocks wordcount pagebreak insertdatetime fullscreen
|
|
|
content_css: 'default', // 主题tinymce-5-dark || tinymce-5 || default || writer || document || dark
|
|
|
custom_undo_redo_levels: 50, // 回退数量
|
|
|
end_container_on_empty_block: true, // 块级文本是否换行
|
|
|
keep_styles: false, // 回车是否保存原有样式,例如code块回车插件初始化失败: tinycomments是否截断
|
|
|
menubar: true, // 是否开启顶部菜单 > false 关闭菜单 | 'edit insert view format table tools help' 菜单按照这里排序 | 参考:https://www.tiny.cloud/docs/tinymce/6/menus-configuration-options/
|
|
|
toolbar_mode: 'wrap', // 功能栏是否换行 > | wrap 换行 | scrolling 滚动 | sliding 省略
|
|
|
toolbar: ' searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote undo redo removeformat subscript superscript code codesample hr numlist link image preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen',
|
|
|
powerpaste_word_import: 'clean',
|
|
|
toolbar_location: 'top', // 菜单栏位置 > bottom 底部 | top 顶部
|
|
|
style_formats_merge: true, // 是否开启默认功能
|
|
|
elementpath: false, // 是否展示编辑层级 > p span
|
|
|
advlist_bullet_styles: 'square',
|
|
|
resize: true, // 调整宽高 > true 调整高 | false 不可调整宽高 | both 宽高可调
|
|
|
language, // 中文
|
|
|
init_instance_callback: editor => {
|
|
|
isLoaded.value = true
|
|
|
if (props.modelValue) {
|
|
|
editor.setContent(props.modelValue)
|
|
|
}
|
|
|
hasInit.value = true
|
|
|
editor.on('NodeChange Change KeyUp SetContent', () => {
|
|
|
hasChange.value = true
|
|
|
emit('update:modelValue', editor.getContent())
|
|
|
})
|
|
|
},
|
|
|
setup (editor) {
|
|
|
const addOrupload = document.querySelectorAll('.components-tiny-mce .tinymce-container .add-or-upload')
|
|
|
addOrupload.forEach(v => {
|
|
|
v.style.zIndex = 10
|
|
|
})
|
|
|
editor.on('FullscreenStateChanged', e => {
|
|
|
toxFullscreen.value = e.state
|
|
|
handleFullScreenStateChange(e.state)
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
const handleFullScreenStateChange = (isFullscreen) => {
|
|
|
const addOrupload = document.querySelectorAll('.components-tiny-mce .tinymce-container .add-or-upload')
|
|
|
if (isFullscreen) {
|
|
|
// 进入全屏模式时执行的代码
|
|
|
addOrupload.forEach(v => {
|
|
|
v.style.zIndex = 0
|
|
|
})
|
|
|
} else {
|
|
|
// 退出全屏模式时执行的代码
|
|
|
addOrupload.forEach(v => {
|
|
|
v.style.zIndex = 10
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
const destroyTinymce = () => {
|
|
|
const tinymce = window.tinymce?.get(props.id)
|
|
|
if (toxFullscreen.value) {
|
|
|
tinymce.execCommand('mceFullScreen')
|
|
|
}
|
|
|
onUnmounted(() => {
|
|
|
destroyTinymce()
|
|
|
})
|
|
|
|
|
|
if (tinymce) {
|
|
|
tinymce.destroy()
|
|
|
}
|
|
|
}
|
|
|
const resourcesUrl = import.meta.env.VITE_APP_RESOURCES_URL
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
const imageSuccessCBK = (response, file, fileList) => {
|
|
|
window.tinymce.get(props.id).insertContent(`<img alt="" src="${resourcesUrl + file.response.data}" >`)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 限制图片上传大小
|
|
|
*/
|
|
|
const beforeAvatarUpload = (file) => {
|
|
|
const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/gif' || file.type === 'image/jpg'
|
|
|
if (!isJPG) {
|
|
|
this.$message.error('上传图片只能是jpeg/jpg/png/gif 格式!')
|
|
|
}
|
|
|
const isLt2M = file.size / 1024 / 1024 < 2
|
|
|
if (!isLt2M) {
|
|
|
this.$message.error('上传图片大小不能超过 2MB!')
|
|
|
}
|
|
|
return isLt2M && isJPG
|
|
|
}
|
|
|
</script>
|
|
|
<!--eslint-disable-next-line vue-scoped-css/enforce-style-type -->
|
|
|
<style lang="scss">
|
|
|
.components-tiny-mce {
|
|
|
.tox-fullscreen .add-or-upload {
|
|
|
z-index: 9999 !important;
|
|
|
position:fixed !important;
|
|
|
right: 0;
|
|
|
top: 0;
|
|
|
|
|
|
}
|
|
|
.tinymce-container {
|
|
|
position: relative;
|
|
|
.add-or-upload {
|
|
|
position: absolute;
|
|
|
top: 10px;
|
|
|
right: 10px;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
.tox-tinymce-aux {
|
|
|
z-index: 9999 !important;
|
|
|
}
|
|
|
</style>
|