# Classic 快速接入

将 Core、分页视图和产品界面组合成完整编辑体验。

Classic 是框架之上的分页产品壳层。`@quirekit/classic-editor` 提供挂载、工作区与产品插件；可选 `@quirekit/classic-docx` 装配 Word schema、界面与文件服务。它们不能与 Core 的普通 Extension 混为一谈。

希望自己实现类似 Classic 的产品界面，请先读[从 Core 构建产品](/build)；本页讲接入现有 Classic 壳层。自定义功能区、面板和文件服务的完整实现见[产品插件](/build/product-plugin)。

## 获取与装配

Classic 壳层使用 AGPL-3.0-only，Word 预设与 Pro 是独立商业包。以下 Word 体验使用工作区包；外部项目需要先取得相应包和授权，不应假定它们都能从公共 npm 安装。当前能力见 [Word 插件](/plugins/word)。

使用方式分别见[免费评估与社区授权](/classic/free)与[付费使用](/classic/commercial)；完成挂载后继续[配置与生命周期](/classic/configuration)。

## 最小挂载

在 Vue 的 `onMounted` 中取得已有元素后，使用共享 Vue runtime 的入口创建产品：

```ts [创建 Word 产品实例]
import { createClassicEditor } from '@quirekit/classic-editor/vue'
import {
  createClassicWordPreset,
  createClassicWordDefaultDocument,
  createClassicWordDocxPlugin,
} from '@quirekit/classic-docx/vue'
import '@quirekit/classic-editor/styles.css'
import '@quirekit/classic-docx/styles.css'

const instance = createClassicEditor({
  element,
  preset: createClassicWordPreset({ proofing: false }),
  document: createClassicWordDefaultDocument('zh-CN'),
  locale: 'zh-CN',
  plugins: [createClassicWordDocxPlugin()],
  webFonts: false,
})
instance.ui.setZoomMode('fit-width')
```

`element` 是宿主元素，例如 Vue 的 `ref` 在挂载后取得的值。给它一个实际高度，如 `height: 640px`。`preset` 安装 Word 模型与视图，`document` 提供匹配的初始正文，`plugins` 另行装配 DOCX 文件服务。这里关闭校对和外部字体库，避免把宿主服务准备混进入门步骤；需要时按对应插件配置开启。

在 `onBeforeUnmount` 中调用 `instance.destroy()`。普通脚本应用可使用根入口创建产品；Nuxt 将挂载放在客户端，完整异步加载与退出处理见下方示例。

## 实际效果

这是公开 Word preset 的默认文档，可输入、格式化、切换只读并下载当前 JSON。文件菜单由正式 DOCX 插件提供。修改仅在本页面会话内保留。

### classic/editor.vue

```vue
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from "vue";
import { QuireButton, useQuireKitTheme } from "@quirekit/ui/vue";
import type { ClassicEditorInstance, ClassicEditorLocale } from "@quirekit/classic-editor";
import { downloadJson } from "../shared/download";

const props = withDefaults(defineProps<{
  /** Interface language; changing it never replaces document content. */ locale?: ClassicEditorLocale;
  /** Deployed host license; local evaluation works without a key. */ licenseKey?: string;
}>(), { locale: "zh-CN" });
const host = ref<HTMLElement>();
const instance = shallowRef<ClassicEditorInstance>();
const theme = useQuireKitTheme();
const loading = ref(false);
const failed = ref(false);
const readOnly = ref(false);
let disposed = false;
const text = computed(() => props.locale === "en" ? {
  loading: "Preparing Classic…", failure: "The editor could not load. Reload this page to try again.",
  retry: "Reload page", read: "Read only", edit: "Resume editing", download: "Download JSON",
  note: "A live Word preset. Edits stay on this page; download JSON before leaving.",
} : {
  loading: "正在准备 Classic…", failure: "编辑器加载失败，请重新加载页面后再试。", retry: "重新加载页面",
  read: "只读预览", edit: "继续编辑", download: "下载 JSON",
  note: "真实 Word 预设。修改仅保留在当前页面，离开前可下载 JSON。",
});

/** Loads the public product only in the browser, respecting the owning component's lifetime. */
async function mount(): Promise<void> {
  if (loading.value || disposed || instance.value) return;
  loading.value = true;
  failed.value = false;
  let created: ClassicEditorInstance | undefined;
  try {
    const [classic, word, license] = await Promise.all([
      import("@quirekit/classic-editor/vue"), import("@quirekit/classic-docx/vue"), import("@quirekit/license"),
      import("@quirekit/classic-editor/styles.css"), import("@quirekit/classic-docx/styles.css"),
    ]);
    if (disposed || !host.value) return;
    if (props.licenseKey !== undefined) license.setQuireKitLicense(props.licenseKey || null);
    created = classic.createClassicEditor({
      element: host.value,
      locale: props.locale,
      preset: word.createClassicWordPreset({ proofing: false }),
      document: word.createClassicWordDefaultDocument(props.locale),
      theme: theme?.value,
      webFonts: false,
      plugins: [word.createClassicWordDocxPlugin()],
      shell: { leftSidebar: false, rightSidebar: false, toolbar: false, ribbonOverflow: "collapse" },
    });
    created.ui.setZoomMode("fit-width");
    instance.value = created;
  } catch {
    created?.destroy();
    failed.value = true;
  } finally {
    loading.value = false;
  }
}
/** Changes editability through the product contract without replacing the current document. */
function toggleReadOnly(): void {
  readOnly.value = !readOnly.value;
  instance.value?.update({ editable: !readOnly.value });
}
/** Downloads the current canonical content, including edits made in the live preview. */
function download(): void {
  if (instance.value) downloadJson(instance.value.getJSON(), "classic-document.json");
}
/** Retries failed module fetching in a fresh browser module map before any document is mounted. */
function reload(): void {
  if (!instance.value) window.location.reload();
}
watch(() => props.locale, locale => instance.value?.update({ locale }));
if (theme) watch(theme, value => instance.value?.update({ theme: value }));
onMounted(mount);
onBeforeUnmount(() => { disposed = true; instance.value?.destroy(); instance.value = undefined; });
</script>
<template>
  <div class="classic-example" :data-editor-ready="Boolean(instance)">
    <div class="classic-example-actions">
      <span class="classic-example-note">{{ text.note }}</span>
      <QuireButton variant="outline" size="sm" :disabled="!instance" :aria-pressed="readOnly" @click="toggleReadOnly">{{ readOnly ? text.edit : text.read }}</QuireButton>
      <QuireButton variant="outline" size="sm" :disabled="!instance" @click="download">{{ text.download }}</QuireButton>
    </div>
    <div v-if="!instance" class="classic-example-state" role="status">
      <p>{{ failed ? text.failure : text.loading }}</p>
      <QuireButton v-if="failed" variant="outline" @click="reload">{{ text.retry }}</QuireButton>
    </div>
    <div ref="host" class="classic-editor-host" :class="{ 'classic-editor-pending': !instance }" />
  </div>
</template>
<style scoped>
.classic-example { width: 100%; min-width: 0; }
.classic-example-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding: 12px 16px; background: var(--qk-color-surface-page); border-bottom: 1px solid var(--qk-color-border-subtle); }
.classic-example-note { flex: 1 1 240px; font-size: 12px; line-height: 1.6; color: var(--qk-color-text-secondary); }
.classic-editor-host { height: 640px; min-width: 0; text-align: start; }
.classic-editor-pending { height: 0; overflow: hidden; }
.classic-example-state { display: grid; align-content: center; justify-items: center; height: 420px; padding: 24px; background: var(--qk-color-surface-subtle); color: var(--qk-color-text-secondary); }
@media (max-width: 600px) { .classic-editor-host { height: 540px; } .classic-example-actions { padding: 12px; } }
</style>

```

### shared/download.ts

```ts
/**
 * Downloads canonical JSON through a short-lived browser URL.
 * @param document - Serializable canonical content.
 * @param name - Download filename chosen by the host.
 */
export function downloadJson(document: unknown, name: string): void {
  const url = URL.createObjectURL(new Blob([JSON.stringify(document, null, 2)], { type: "application/json" }));
  const link = window.document.createElement("a");
  link.href = url;
  link.download = name;
  link.click();
  window.setTimeout(() => URL.revokeObjectURL(url), 1000);
}

```

Vue 宿主使用 `/vue` 入口共享 Vue runtime。动态导入完成前检查宿主是否还存在；结束时 `destroy()`。示例通过 `update()` 更新主题、语言与只读，保留同一个 Core、正文和撤销历史。更改文档模型或其他结构配置仍会重建，详见[配置与生命周期](/classic/configuration)。

同时导入 `@quirekit/classic-editor/styles.css` 与所用 Word 包的 `@quirekit/classic-docx/styles.css`，如源码所示。公开样式入口包含组件抽取样式，功能区、块控件、浮层和面板都依赖它；不要只复制正文画布的样式。自建 Core 工作区则使用 View 自己的公开基础样式，见[View 接入](/build/view)。

## 公共入口

### createClassicEditor

`@quirekit/classic-editor` · AGPL-3.0-only

创建框架无关的 Classic 产品实例。options 提供文档、预设、能力、插件与挂载设置，返回支持挂载、更新、卸载和最终销毁的实例。

```ts
function createClassicEditor(options?: ClassicEditorOptions): ClassicEditorInstance
```

### createClassicWordPreset

`@quirekit/classic-docx` · Commercial

为宿主配置创建可选的完整 Word 产品预设。options 提供宿主设置，返回冻结预设；每次挂载解析独立扩展集合。

```ts
function createClassicWordPreset(options?: ClassicWordPresetOptions): ClassicEditorPreset
```

### createClassicWordDefaultDocument

`@quirekit/classic-docx` · Commercial

创建 Word 产品的规范初始文档。locale 仅决定初始文案，返回包含一节和命名页眉页脚 story 的 Quire JSON。

```ts
function createClassicWordDefaultDocument(locale?: ClassicEditorLocale): QuireJSONContent
```

## 产品插件

普通 Extension 拥有文档语义；Classic 产品插件组合功能区、菜单、侧栏和文档服务。

### defineClassicEditorPlugin

`@quirekit/classic-editor` · AGPL-3.0-only

定义 Classic 产品插件，并保留 contribution 的字面量类型。plugin 为声明，返回可组合到预设或实例选项中的同一声明。

```ts
function defineClassicEditorPlugin<Plugin extends ClassicEditorPlugin>(plugin: Plugin): Plugin
```

### createClassicWordDocxPlugin

`@quirekit/classic-docx` · Commercial

创建正式 DOCX 导入导出插件。options 可指定二进制 codec 和产品标识，返回包含 Word 文档、模板服务与菜单入口的 Classic 插件。

```ts
function createClassicWordDocxPlugin(options?: ClassicWordDocxPluginOptions): ClassicEditorPlugin
```

Pro 审阅面板、内容控件界面，及可选 AI、PDF/OFD 适配器需要单独装配，本示例不声称已安装它们。

下一步接入[保存、打开与文件转换](/classic/files)，再按[配置说明](/classic/configuration)调整产品界面。
