Vue form example
SoEditor 1.3.0
BUILT FOR YOUR CMS
Make room for your content
An article, a product story, or your next announcement. Familiar tools for the work you do every day.
WYSIWYGHTML SourceCMS
Loads on demand · Content stays in this page
Install and run
The /cms components are released in 1.3.0. The existing useSoEditorWorkspace entry remains compatible.
sh
pnpm add @soeditor/editor@1.3.0 @soeditor/vue@1.3.0 vueSelect “Start editing” to run the published packages. Download complete example sources, extract, run pnpm install and pnpm dev, then open vue.html.
Try it
- Edit the article and watch bound HTML update below it.
- Select “Replace HTML” to apply external state, then toggle readonly to stop editing.
- “Submit form” reads canonical textarea HTML. “Reset form” restores the initial value for the current mount.
- “HTML Source” loads Source on demand. “Recreate demo” mounts a new instance with the current value. Closing the demo removes the entire iframe.
Complete example source
The runnable demo uses Vue h() without an SFC compiler plugin. modelValue and onUpdate:modelValue are the render-function form of template v-model.
ts
import { createApp, defineComponent, h, ref, shallowRef } from 'vue';
import { SoEditor } from '@soeditor/vue/cms';
import type { ClassicEditor } from '@soeditor/editor/cms';
import { createEditor, initial, label, options } from './shared.js';
const ArticleForm = defineComponent({
setup() {
const html = ref(initial);
const readonly = ref(false);
const version = ref(0);
const output = ref('');
const status = ref(label('正在加载', 'Loading'));
const editor = shallowRef<ClassicEditor>();
const button = (zh: string, en: string, onClick: () => void) =>
h('button', { type: 'button', onClick }, label(zh, en));
return () =>
h(
'form',
{
onSubmit: (event: Event) => {
event.preventDefault();
if (event.currentTarget instanceof HTMLFormElement)
output.value = String(
new FormData(event.currentTarget).get('body'),
);
},
},
[
h(
'p',
{ className: 'notice' },
label(
'Vue 组件预览:内容仅保存在本页。',
'Vue component preview: content stays in this page.',
),
),
h('div', { className: 'controls' }, [
button('替换 HTML', 'Replace HTML', () => {
html.value =
'<h2>Updated article</h2><p>External value</p>';
}),
button('切换只读', 'Toggle readonly', () => {
readonly.value = !readonly.value;
}),
button('读取 HTML', 'Read HTML', () => {
output.value = editor.value?.getData() ?? '';
}),
button('HTML Source', 'HTML Source', () => {
void editor.value?.setWorkspaceView('source');
}),
button('重建示例', 'Recreate demo', () => {
editor.value = undefined;
version.value++;
}),
h(
'button',
{ type: 'submit' },
label('提交表单', 'Submit form'),
),
h(
'button',
{ type: 'reset' },
label('重置表单', 'Reset form'),
),
]),
h('p', { role: 'status' }, status.value),
h(SoEditor, {
key: version.value,
name: 'body',
modelValue: html.value,
'onUpdate:modelValue': (value: string) => {
html.value = value;
},
readonly: readonly.value,
options,
createEditor,
onReady: (instance: ClassicEditor) => {
editor.value = instance;
status.value = label('就绪', 'Ready');
document.body.dataset.ready = 'true';
},
onError: (error: unknown) => {
status.value = String(error);
},
}),
h('output', { 'data-bound-value': '' }, html.value),
h('pre', null, output.value),
],
);
},
});
const app = createApp(ArticleForm);
app.mount('#app');
window.addEventListener('pagehide', () => app.unmount(), { once: true });ts
import '@soeditor/editor/cms/styles.css';
import '../style.css';
import type { CreateClassicEditorOptions } from '@soeditor/editor/cms';
export const locale =
new URLSearchParams(location.search).get('lang') === 'en' ? 'en' : 'zh-CN';
document.documentElement.lang = locale;
export const label = (zh: string, en: string) => (locale === 'en' ? en : zh);
export const initial = '<h2>CMS article</h2><p>Edit this content.</p>';
export const options: CreateClassicEditorOptions = {
locale,
ariaLabel: label('文章正文', 'Article HTML'),
editingModes: ['wysiwyg', 'source'],
minHeight: 240,
};
export const createEditor = async (
host: HTMLElement,
configuration: CreateClassicEditorOptions,
) => {
const cms = await import('@soeditor/editor/cms/optional');
return cms.createClassicEditor(host, configuration);
};html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<title>SoEditor vue demo</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="./frameworks/vue.ts"></script>
</body>
</html>