|
|
@@ -87,8 +87,20 @@
|
|
|
|
|
|
<el-form-item label="内容">
|
|
|
<div class="rich-editor" :class="{ 'is-disabled': readonly }">
|
|
|
- <Toolbar :editor="editorInstance" :defaultConfig="toolbarConfig" />
|
|
|
- <Editor :defaultConfig="editorConfig" v-model="form.content" @onCreated="handleEditorCreated" :disabled="readonly" style="min-height: 400px;" />
|
|
|
+ <Toolbar
|
|
|
+ style="border-bottom: 1px solid #ccc"
|
|
|
+ :editor="editorInstance"
|
|
|
+ :defaultConfig="toolbarConfig"
|
|
|
+ :mode="editorMode"
|
|
|
+ />
|
|
|
+ <Editor
|
|
|
+ :defaultConfig="editorConfig"
|
|
|
+ :mode="editorMode"
|
|
|
+ v-model="form.content"
|
|
|
+ @onCreated="handleEditorCreated"
|
|
|
+ :disabled="readonly"
|
|
|
+ style="height: 400px; overflow-y: hidden;"
|
|
|
+ />
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
|
|
|
@@ -161,6 +173,7 @@ export default {
|
|
|
tagOptions: [],
|
|
|
editorConfig: null,
|
|
|
toolbarConfig: {},
|
|
|
+ editorMode: 'default',
|
|
|
editorInstance: null,
|
|
|
form: {
|
|
|
id: null,
|
|
|
@@ -221,43 +234,18 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
beforeRouteLeave(to, from, next) {
|
|
|
- // 离开前清空表单数据,避免浏览器弹出"离开页面?未保存更改"原生提示
|
|
|
- this.form = {
|
|
|
- id: null,
|
|
|
- categoryId: '',
|
|
|
- title: '',
|
|
|
- summary: '',
|
|
|
- coverImage: '',
|
|
|
- content: '',
|
|
|
- tags: '',
|
|
|
- contentType: 'article',
|
|
|
- difficultyLevel: 0,
|
|
|
- tagIds: [],
|
|
|
- author: '',
|
|
|
- readTime: 3,
|
|
|
- relatedDimensions: [],
|
|
|
- dimensionWeights: [],
|
|
|
- visibility: 'public',
|
|
|
- visibleTo: []
|
|
|
- }
|
|
|
- this.isEdit = false
|
|
|
- this.loading = false
|
|
|
- this.saving = false
|
|
|
- this.publishing = false
|
|
|
+ this.destroyEditor()
|
|
|
next()
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
- this.unbindVideoFullscreen()
|
|
|
- if (this.editorInstance && this.editorInstance.destroy) {
|
|
|
- this.editorInstance.destroy()
|
|
|
- this.editorInstance = null
|
|
|
- }
|
|
|
+ this.destroyEditor()
|
|
|
},
|
|
|
methods: {
|
|
|
initEditorConfig() {
|
|
|
const baseURL = process.env.VUE_APP_BASE_API || ''
|
|
|
const token = localStorage.getItem('token')
|
|
|
this.editorConfig = {
|
|
|
+ autoFocus: false,
|
|
|
hoverbarKeys: {
|
|
|
video: {
|
|
|
menuKeys: []
|
|
|
@@ -314,8 +302,21 @@ onError: (file, err, res) => {
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ destroyEditor() {
|
|
|
+ this.unbindVideoFullscreen()
|
|
|
+ const editor = this.editorInstance
|
|
|
+ this.editorInstance = null
|
|
|
+ if (!editor) return
|
|
|
+ try {
|
|
|
+ if (typeof editor.blur === 'function') editor.blur()
|
|
|
+ } catch (e) {}
|
|
|
+ try {
|
|
|
+ if (typeof editor.destroy === 'function') editor.destroy()
|
|
|
+ } catch (e) {}
|
|
|
+ },
|
|
|
handleEditorCreated(editor) {
|
|
|
- this.editorInstance = editor
|
|
|
+ // Vue 2 必须 seal,否则会把 editor 做成响应式,内部 WeakMap 取不到实例
|
|
|
+ this.editorInstance = Object.seal(editor)
|
|
|
this.bindVideoInteractions(editor)
|
|
|
},
|
|
|
bindVideoInteractions(editor) {
|
|
|
@@ -394,6 +395,7 @@ onError: (file, err, res) => {
|
|
|
}
|
|
|
},
|
|
|
onVideoDragMouseMove(editor, e) {
|
|
|
+ if (!this.editorInstance || !editor) return
|
|
|
const state = this._videoDragState
|
|
|
if (!state) return
|
|
|
const dx = e.clientX - state.startX
|
|
|
@@ -409,6 +411,10 @@ onError: (file, err, res) => {
|
|
|
this.updateVideoDropIndicator(editor, e)
|
|
|
},
|
|
|
onVideoDragMouseUp(editor, e) {
|
|
|
+ if (!this.editorInstance || !editor) {
|
|
|
+ this._videoDragState = null
|
|
|
+ return
|
|
|
+ }
|
|
|
const state = this._videoDragState
|
|
|
this._videoDragState = null
|
|
|
const wrap = this.$el && this.$el.querySelector('.rich-editor')
|
|
|
@@ -541,7 +547,6 @@ onError: (file, err, res) => {
|
|
|
},
|
|
|
unbindVideoFullscreen() {
|
|
|
const root = this._videoEditorRoot
|
|
|
- || (this.editorInstance && this.editorInstance.getEditableContainer && this.editorInstance.getEditableContainer())
|
|
|
|| (this.$el && this.$el.querySelector('.w-e-text-container'))
|
|
|
if (root && this._onVideoDblClick) root.removeEventListener('dblclick', this._onVideoDblClick)
|
|
|
if (root && this._onVideoFsClick) root.removeEventListener('click', this._onVideoFsClick, true)
|
|
|
@@ -742,6 +747,7 @@ onError: (file, err, res) => {
|
|
|
}
|
|
|
}
|
|
|
this.$message.success(publishNow ? '文章已发布' : (this.articleStatus === 'published' ? '修改已保存' : '草稿已保存'))
|
|
|
+ this.destroyEditor()
|
|
|
this.$router.push('/article-manage')
|
|
|
} catch (e) {
|
|
|
this.$message.error(e.message || '保存失败')
|
|
|
@@ -857,9 +863,7 @@ onError: (file, err, res) => {
|
|
|
}
|
|
|
.rich-editor /deep/ .w-e-text-container {
|
|
|
position: relative;
|
|
|
- min-height: 400px;
|
|
|
- max-height: 600px;
|
|
|
- overflow-y: auto;
|
|
|
+ height: 400px;
|
|
|
}
|
|
|
.rich-editor /deep/ .w-e-scroll {
|
|
|
position: relative;
|