Nuxt Nation 大会即将到来。加入我们,时间为 11 月 12 日至 13 日。

storyblok
@storyblok/nuxt

Storyblok Nuxt 模块
Storyblok Logo

@storyblok/nuxt

用于 Storyblok(无头 CMS)的 Nuxt 3 模块。


Storyblok JS Client npm

Follow @Storyblok
Follow @Storyblok

启动新项目

您是否渴望深入编码?按照这些步骤使用 Storyblok 和 Nuxt 启动新项目,只需几分钟即可开始!

终极教程

您是否正在寻找一个动手实践的逐步教程?Nuxt 终极教程 可以满足您的需求!它提供了关于使用 Storyblok 和 Nuxt 从头到尾构建完整的多语言网站的全面说明。

安装

安装 @storyblok/nuxt

npx nuxi@latest module add storyblok

将以下代码添加到 nuxt.config.js 的 modules 部分,并将 accessToken 替换为 Storyblok 空间中的 API 令牌。

import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: [
    ["@storyblok/nuxt", { accessToken: "<your-access-token>" }]
    // ...
  ]
});

如果您愿意,也可以使用 storyblok 配置

import { defineNuxtConfig } from "nuxt";

export default defineNuxtConfig({
  modules: ["@storyblok/nuxt"],
  storyblok: {
    accessToken: "<your-access-token>"
  }
});

警告 此 SDK 在后台使用 Fetch API。如果您的环境不支持它,则需要安装 polyfill,例如 isomorphic-fetch。更多信息请参阅 storyblok-js-client 文档

选项

初始化模块时,您可以传递所有 @storyblok/vue 选项,以及我们在 JS SDK Storyblok 桥接部分 中解释的 bridge 选项,以及一个 enableSudoMode 选项来定义您自己的插件(见下文)。

注意 如果您想在 nuxt-devtools 中使用 Storyblok,您可以使用选项 devtools,如果启用,请确保已安装 @nuxt/devtools 模块并在您的 nuxt 配置中启用它。

// Defaults
["@storyblok/nuxt", {
  {
    accessToken: "<your-access-token>",
    bridge: true,
    devtools: true,
    apiOptions: {}, // storyblok-js-client options
  }
}]

定义您自己的插件

虽然推荐的方法涵盖了大多数情况,但在某些特定情况下,您可能需要使用 enableSudoMode 选项并禁用我们的插件,从而允许您整合自己的插件。

// nuxt.config.ts
modules: [
  [
    "@storyblok/nuxt",
    {
      accessToken: "<your-access-token>",
      enableSudoMode: true
    }
  ]
];

要将其他功能包含在 SDK 的 apiOptions 中,例如自定义缓存方法,您可以在 plugins 文件夹(自动导入)中实现以下解决方案

// plugins/storyblok.js
import { StoryblokVue, apiPlugin } from "@storyblok/vue";

export default defineNuxtPlugin(({ vueApp }) => {
  vueApp.use(StoryblokVue, {
    accessToken: "<your-access-token>",
    apiOptions: {
      cache: {
        type: "custom",
        custom: {
          flush() {
            console.log("all right");
          }
        }
      }
    },
    use: [apiPlugin]
  });
});

区域参数

可能的值

  • eu(默认):适用于在欧盟创建的空间
  • us:适用于在美国创建的空间
  • ap:适用于在澳大利亚创建的空间
  • ca:适用于在加拿大创建的空间
  • cn:适用于在中国创建的空间

在美国创建的空间的完整示例

["@storyblok/nuxt", {
  {
    accessToken: "<your-access-token>",
    apiOptions: {
      region: "us"
    }
  }
}]

重要 对于在美国或中国创建的空间,必须指定 region 参数。

入门

1. 创建组件并将它们链接到 Storyblok 可视化编辑器

要将您的 Vue 组件链接到 Storyblok 空间中的等效组件

  • 首先,您需要将它们全局加载,并将它们添加到 ~/storyblok 目录中。务必在代码中使用帕斯卡命名法为它们命名 ExampleComponent.vue,并在 Storyblok 空间中使用连字符 example-component,这样它们将被自动导入。
    如果要为与 Storyblok 相关的组件定义自己的目录,可以在 nuxt.config.js 中使用选项 componentsDir
    // nuxt.config.ts
    modules: [
      [
        "@storyblok/nuxt",
        {
          accessToken: "<your-access-token>",
          componentsDir: '~/components',
        }
      ]
    ],
    components: {
      dirs: [
        {
          path: '~/components/storyblok',
          global: true,
        }
      ]
    },
    

    否则,您可以设置另一个目录并手动加载它们(例如,通过 使用 Nuxt 插件)。

    警告 请注意,如果在 storyblok 文件夹中命名的组件与 components 文件夹中的另一个组件名称相同,则它将无法正常工作。提示:使用不同的名称保留 Nuxt 项目中的组件。

  • 对于每个组件,在其根元素上使用 v-editable 指令,传递它们接收到的 blok 属性
<div v-editable="blok"></div>
  • 最后,使用 <StoryblokComponent>,它在 Nuxt 应用中全局可用
<StoryblokComponent :blok="blok" />

blok 是来自 Storblok 内容交付 API 的实际块数据。

2. 获取 Storyblok 故事并侦听可视化编辑器事件

组合式 API

最简单的方法是使用 useAsyncStoryblok 单行组合式函数(它会自动导入)。您需要将 slug 作为第一个参数传递,而第二个和第三个参数 apiOptionsbridgeOptions 分别是可选的。

在我们的 API 文档中查看可用的 apiOptions,以及传递给 Storyblok Bridge 的 bridgeOptions

注意 如果您想了解有关版本控制 { version: "draft" /* 或 "publish" */ } 的更多信息,请转到 处理预览和/或生产环境 部分

<script setup>
  const story = await useAsyncStoryblok(
    "vue",
    { version: "draft", resolve_relations: "Article.author" }, // API Options
    { resolveRelations: ["Article.author"], resolveLinks: "url" } // Bridge Options
  );

  if (story.value.status) {
    throw createError({
      statusCode: story.value.status,
      statusMessage: story.value.response
    });
  }
</script>

<template>
  <StoryblokComponent v-if="story" :blok="story.content" />
</template>

这是在 useState 内部分别使用 useStoryblokApiuseStoryblokBridge 函数的简写等价物

<script setup>
  const story = useState();
  const storyblokApi = useStoryblokApi();

  const { data } = await storyblokApi.get(
    `cdn/stories/vue`,
    {
      version: "draft"
    }
  );
  story.value = data.story;

  onMounted(() => {
    useStoryblokBridge(
      story.value.id,
      (evStory) => (story.value = evStory),
      { resolveRelations: ["Article.author"], resolveLinks: "url" } // Bridge Options
    );
  });
</script>

<template>
  <StoryblokComponent v-if="story" :blok="story.content" />
</template>

useState 是一个对 SSR 友好的 ref 替换。其值将在服务器端渲染后(在客户端水化期间)保留。

渲染富文本

您可以通过使用随 @storyblok/nuxt 提供的 renderRichText 函数和 Vue 计算属性轻松渲染富文本

<template>
  <div v-html="articleContent"></div>
</template>

<script setup>
  const props = defineProps({ blok: Object });
  const articleContent = computed(() =>
    renderRichText(props.blok.articleContent)
  );
</script>

您还可以通过将选项作为 renderRichText 函数的第二个参数传递来设置自定义 Schema 和组件解析器

<script setup>
  import cloneDeep from "clone-deep";

  const mySchema = cloneDeep(RichTextSchema); // you can make a copy of the default RichTextSchema
  // ... and edit the nodes and marks, or add your own.
  // Check the base RichTextSchema source here https://github.com/storyblok/storyblok-js-client/blob/v4/source/schema.js

  const props = defineProps({ blok: Object });

  const articleContent = computed(() =>
    renderRichText(props.blok.articleContent, {
      schema: mySchema,
      resolver: (component, blok) => {
        switch (component) {
          case "my-custom-component":
            return `<div class="my-component-class">${blok.text}</div>`;
          default:
            return "Resolver not defined";
        }
      }
    })
  );
</script>

3. 处理预览和/或生产环境

请记住,桥接仅在使用 version: 'draft'预览访问令牌时有效。

对于生产站点(不作为内容编辑器的预览使用),应使用 version: 'published'公共访问令牌

注意 如果您将生产环境用作营销人员和公共网站的预览,则需要一个插件来处理不同的 .env 变量或使用预览访问令牌的版本,检查您是否位于 Storyblok 内部。例如,类似于 if (window.location.search.includes(_storyblok_tk[token]=<YOUR_TOKEN>)

查看官方文档,了解如何 访问不同的内容版本

使用 Nuxt 处理不同内容版本的推荐方法是结合使用环境变量和 Nuxt 运行时配置,以在您的应用程序中公开配置和机密

在您的 nuxt.config.ts

export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      storyblokVersion: process.env.STORYBLOK_VERSION || "published"
    }
  }
});

然后您可以在组件中访问运行时配置

const config = useRuntimeConfig();

const story = await useAsyncStoryblok(
  "blog",
  {
    version: config.public.storyblokVersion,
    resolve_relations: "overview.featured_story"
  },
  { resolveRelations: "overview.featured_story" }
);

//or

const { data: articles } = await storyblokApi.get("cdn/stories", {
  version: config.public.storyblokVersion,
  starts_with: "blog",
  is_startpage: false
});

API

useAsyncStoryblok(slug, apiOptions, bridgeOptions)

(推荐选项)在后台使用 useState 以帮助实现 SSR 兼容性。

查看可用的 apiOptions(传递给 storyblok-js-client)和 bridgeOptions(传递给 Storyblok Bridge)。

useStoryblok(slug, apiOptions, bridgeOptions)

当我们需要进行完整的客户端请求时,例如获取已登录用户的个性化数据,使用 useStoryblok 而不是 useAsyncStoryblok 可能会有所帮助。

查看可用的 apiOptions(传递给 storyblok-js-client)和 bridgeOptions(传递给 Storyblok Bridge)。

useStoryblokApi()

返回 storyblok-js-client 的实例。

useStoryblokBridge(storyId, callback, bridgeOptions)

使用此单行函数来涵盖最常见的使用案例:在 Storyblok 可视化编辑器中发生任何类型的更改时更新故事。

Storyblok JavaScript SDK 生态系统

A visual representation of the Storyblok JavaScript SDK Ecosystem

更多资源

支持

贡献

请参阅我们的 贡献指南 和我们的 行为准则。此项目使用 semantic-release 通过使用提交消息生成新版本,并且我们使用 Angular 约定为提交命名。查看 此问题,了解 semantic-release 常见问题解答中的相关信息。