Skip to content

Commit f75425d

Browse files
committed
perf: review tinymce code
1 parent 9c02d8e commit f75425d

File tree

26 files changed

+349
-534
lines changed

26 files changed

+349
-534
lines changed

src/components/Tinymce/src/Editor.vue

Lines changed: 129 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,169 @@
11
<template>
22
<div class="tinymce-container" :style="{ width: containerWidth }">
3-
<tinymce-editor
4-
:id="id"
5-
:init="initOptions"
6-
:modelValue="tinymceContent"
7-
@update:modelValue="handleChange"
8-
:tinymceScriptSrc="tinymceScriptSrc"
9-
></tinymce-editor>
3+
<textarea :id="tinymceId" visibility="hidden" ref="elRef"></textarea>
104
</div>
115
</template>
126

137
<script lang="ts">
14-
import TinymceEditor from './lib'; // TinyMCE vue wrapper
15-
import { defineComponent, computed } from 'vue';
8+
import {
9+
defineComponent,
10+
computed,
11+
onMounted,
12+
nextTick,
13+
ref,
14+
unref,
15+
watch,
16+
onUnmounted,
17+
onDeactivated,
18+
} from 'vue';
1619
import { basicProps } from './props';
1720
import toolbar from './toolbar';
1821
import plugins from './plugins';
22+
import { getTinymce } from './getTinymce';
23+
import { useScript } from '/@/hooks/web/useScript';
24+
import { snowUuid } from '/@/utils/uuid';
25+
import { bindHandlers } from './helper';
1926
2027
const CDN_URL = 'https://cdn.bootcdn.net/ajax/libs/tinymce/5.5.1';
28+
2129
const tinymceScriptSrc = `${CDN_URL}/tinymce.min.js`;
2230
2331
export default defineComponent({
2432
name: 'Tinymce',
25-
components: { TinymceEditor },
2633
props: basicProps,
27-
setup(props, { emit }) {
34+
emits: ['change', 'update:modelValue'],
35+
setup(props, { emit, attrs }) {
36+
const editorRef = ref<any>(null);
37+
const elRef = ref<Nullable<HTMLElement>>(null);
38+
39+
const tinymceId = computed(() => {
40+
return snowUuid('tiny-vue');
41+
});
42+
2843
const tinymceContent = computed(() => {
29-
return props.value;
44+
return props.modelValue;
3045
});
31-
function handleChange(value: string) {
32-
emit('change', value);
33-
}
46+
3447
const containerWidth = computed(() => {
3548
const width = props.width;
36-
// Test matches `100`, `'100'`
3749
if (/^[\d]+(\.[\d]+)?$/.test(width.toString())) {
3850
return `${width}px`;
3951
}
4052
return width;
4153
});
54+
4255
const initOptions = computed(() => {
43-
const { id, height, menubar } = props;
56+
const { height, menubar } = props;
4457
return {
45-
selector: `#${id}`,
58+
selector: `#${unref(tinymceId)}`,
4659
height: height,
4760
toolbar: toolbar,
61+
theme: 'silver',
4862
menubar: menubar,
4963
plugins: plugins,
5064
// 语言包
5165
language_url: 'resource/tinymce/langs/zh_CN.js',
5266
// 中文
5367
language: 'zh_CN',
68+
default_link_target: '_blank',
69+
link_title: false,
70+
advlist_bullet_styles: 'square',
71+
advlist_number_styles: 'default',
72+
object_resizing: false,
73+
setup: (editor: any) => {
74+
editorRef.value = editor;
75+
editor.on('init', (e: Event) => initSetup(e));
76+
},
5477
};
5578
});
56-
return { containerWidth, initOptions, tinymceContent, handleChange, tinymceScriptSrc };
79+
80+
const { toPromise } = useScript({
81+
src: tinymceScriptSrc,
82+
});
83+
84+
watch(
85+
() => attrs.disabled,
86+
() => {
87+
const editor = unref(editorRef);
88+
if (!editor) return;
89+
editor.setMode(attrs.disabled ? 'readonly' : 'design');
90+
}
91+
);
92+
93+
onMounted(() => {
94+
nextTick(() => {
95+
init();
96+
});
97+
});
98+
99+
onUnmounted(() => {
100+
destory();
101+
});
102+
103+
onDeactivated(() => {
104+
destory();
105+
});
106+
107+
function destory() {
108+
if (getTinymce() !== null) {
109+
getTinymce().remove(unref(editorRef));
110+
}
111+
}
112+
113+
function init() {
114+
toPromise().then(() => {
115+
initEditor();
116+
});
117+
}
118+
119+
function initEditor() {
120+
getTinymce().init(unref(initOptions));
121+
}
122+
123+
function initSetup(e: Event) {
124+
const editor = unref(editorRef);
125+
if (!editor) return;
126+
const value = props.modelValue || '';
127+
128+
editor.setContent(value);
129+
bindModelHandlers(editor);
130+
bindHandlers(e, attrs, unref(editorRef));
131+
}
132+
133+
function bindModelHandlers(editor: any) {
134+
const modelEvents = attrs.modelEvents ? attrs.modelEvents : null;
135+
const normalizedEvents = Array.isArray(modelEvents) ? modelEvents.join(' ') : modelEvents;
136+
watch(
137+
() => props.modelValue,
138+
(val: string, prevVal: string) => {
139+
if (
140+
editor &&
141+
typeof val === 'string' &&
142+
val !== prevVal &&
143+
val !== editor.getContent({ format: attrs.outputFormat })
144+
) {
145+
editor.setContent(val);
146+
}
147+
}
148+
);
149+
150+
editor.on(normalizedEvents ? normalizedEvents : 'change keyup undo redo', () => {
151+
emit('update:modelValue', editor.getContent({ format: attrs.outputFormat }));
152+
});
153+
}
154+
155+
function handleChange(value: string) {
156+
emit('change', value);
157+
}
158+
return {
159+
containerWidth,
160+
initOptions,
161+
tinymceContent,
162+
handleChange,
163+
tinymceScriptSrc,
164+
elRef,
165+
tinymceId,
166+
};
57167
},
58168
});
59169
</script>
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
const getGlobal = (): any => (typeof window !== 'undefined' ? window : global);
22

3-
const getTinymce = () => {
3+
export const getTinymce = () => {
44
const global = getGlobal();
5-
65
return global && global.tinymce ? global.tinymce : null;
76
};
8-
9-
export { getTinymce };
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const validEvents = [
2+
'onActivate',
3+
'onAddUndo',
4+
'onBeforeAddUndo',
5+
'onBeforeExecCommand',
6+
'onBeforeGetContent',
7+
'onBeforeRenderUI',
8+
'onBeforeSetContent',
9+
'onBeforePaste',
10+
'onBlur',
11+
'onChange',
12+
'onClearUndos',
13+
'onClick',
14+
'onContextMenu',
15+
'onCopy',
16+
'onCut',
17+
'onDblclick',
18+
'onDeactivate',
19+
'onDirty',
20+
'onDrag',
21+
'onDragDrop',
22+
'onDragEnd',
23+
'onDragGesture',
24+
'onDragOver',
25+
'onDrop',
26+
'onExecCommand',
27+
'onFocus',
28+
'onFocusIn',
29+
'onFocusOut',
30+
'onGetContent',
31+
'onHide',
32+
'onInit',
33+
'onKeyDown',
34+
'onKeyPress',
35+
'onKeyUp',
36+
'onLoadContent',
37+
'onMouseDown',
38+
'onMouseEnter',
39+
'onMouseLeave',
40+
'onMouseMove',
41+
'onMouseOut',
42+
'onMouseOver',
43+
'onMouseUp',
44+
'onNodeChange',
45+
'onObjectResizeStart',
46+
'onObjectResized',
47+
'onObjectSelected',
48+
'onPaste',
49+
'onPostProcess',
50+
'onPostRender',
51+
'onPreProcess',
52+
'onProgressState',
53+
'onRedo',
54+
'onRemove',
55+
'onReset',
56+
'onSaveContent',
57+
'onSelectionChange',
58+
'onSetAttrib',
59+
'onSetContent',
60+
'onShow',
61+
'onSubmit',
62+
'onUndo',
63+
'onVisualAid',
64+
];
65+
66+
const isValidKey = (key: string) => validEvents.indexOf(key) !== -1;
67+
68+
export const bindHandlers = (initEvent: Event, listeners: any, editor: any): void => {
69+
Object.keys(listeners)
70+
.filter(isValidKey)
71+
.forEach((key: string) => {
72+
const handler = listeners[key];
73+
if (typeof handler === 'function') {
74+
if (key === 'onInit') {
75+
handler(initEvent, editor);
76+
} else {
77+
editor.on(key.substring(2), (e: any) => handler(e, editor));
78+
}
79+
}
80+
});
81+
};

src/components/Tinymce/src/lib/ScriptLoader.ts

Lines changed: 0 additions & 72 deletions
This file was deleted.

0 commit comments

Comments
 (0)