透過 100 多個技巧的集合來學習 Nuxt!

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。如果您的環境不支援,您需要安裝類似 isomorphic-fetch 的 polyfill。關於 storyblok-js-client 文件 的更多資訊。

選項

當您初始化模組時,您可以傳遞所有 @storyblok/vue 選項,以及在我們的 JS SDK Storyblok bridge 區段 中說明的 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 { apiPlugin, StoryblokVue } 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 目錄。在程式碼中使用 Pascal case(例如 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 的實際 blok 資料。

2. 取得 Storyblok Stories 並監聽可視化編輯器事件

組合式 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>

這相當於分別在 useStateuseStoryblokBridge 函式內使用 useStoryblokApi 的簡寫形式

<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 替代方案。它的值會在伺服器端渲染(在用戶端水合作用期間)後保留。

渲染 Rich Text

您可以使用 StoryblokRichText 元件來渲染 rich text 欄位

<template>
  <StoryblokRichText :doc="blok.articleContent" />
</template>

或者,您可以使用 useStoryblokRichText 可組合函式來獲得更多控制權

<script setup>
  const { render } = useStoryblokRichText({
    // options like resolvers
  })

  const root = () => render(blok.articleContent);
</script>

<template>
  <root />
</template>

如需傳遞至 useStoryblokRichText 的更多驚人選項,請參閱 完整選項 文件。

覆寫預設解析器

您可以透過將 resolver prop 傳遞至 StoryblokRichText 元件來覆寫預設解析器,例如,使用 vue-router 連結或新增自訂程式碼 blok 元件:

<script setup>
  import { NuxtLink } from '#components';
  import type { StoryblokRichTextNode } from '@storyblok/vue';
  import CodeBlok from "./components/CodeBlok.vue";

  const resolvers = {
    // NuxtLink example:
    [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
      h(NuxtLink, {
        to: node.attrs?.href,
        target: node.attrs?.target,
      }, node.text),
    // Custom code block component example:
    [BlockTypes.CODE_BLOCK]: (node: Node) => {
      return h(CodeBlock, {
        class: node?.attrs?.class,
      }, node.children)
    },
  }
</script>

<template>
  <StoryblokRichText :doc="blok.articleContent" :resolvers="resolvers" />
</template>

如果您想要使用 useStoryblokRichText 可組合函式,您可以透過 options 物件傳遞 resolvers

<script setup>
  import CodeBlok from "./components/CodeBlok.vue";

  const { render } = useStoryblokRichText({
    resolvers: {
      // NuxtLink example:
      [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
        h(NuxtLink, {
          to: node.attrs?.href,
          target: node.attrs?.target,
        }, node.text),
      // Custom code block component example:
      [BlockTypes.CODE_BLOCK]: (node: Node) => 
        h(CodeBlock, {
          class: node?.attrs?.class,
        }, node.children)
    }
  });

  const root = () => render(blok.articleContent);
</script>

舊版渲染 Rich Text

!警告
舊版 richTextResolver 即將被棄用。我們建議您改為遷移至上述的新方法。

您可以使用 @storyblok/nuxt 隨附的 renderRichText 函式和 Vue 計算屬性來輕鬆渲染 rich text

<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 可視化編輯器上發生任何變更時,更新 story。

Storyblok JavaScript SDK 生態系統

A visual representation of the Storyblok JavaScript SDK Ecosystem

更多資源

支援

貢獻

請參閱我們的貢獻指南以及我們的行為準則。此專案使用semantic-release,透過 commit 訊息產生新版本,並且我們使用 Angular Convention 來命名 commit。請參考 這個問題,關於 semantic-release 常見問題中的說明。