Skip to content

Documentation for SoEditor 1.3.0

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 vue

Select “Start editing” to run the published packages. Download complete example sources, extract, run pnpm install and pnpm dev, then open vue.html.

Try it

  1. Edit the article and watch bound HTML update below it.
  2. Select “Replace HTML” to apply external state, then toggle readonly to stop editing.
  3. “Submit form” reads canonical textarea HTML. “Reset form” restores the initial value for the current mount.
  4. “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>

Integration guide

HTML editing for website CMS · MIT