
用于 Nuxt 的 Contentstack 集成。
注意:这是一个由 @timbenniks 维护的开源项目,而不是 Contentstack 团队官方维护的包。支持请求可以通过 Github issues 和直接渠道联系 @timbenniks。
useImageTransform Composables 进行图像转换npx nuxi module add nuxt-contentstack
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["nuxt-contentstack"],
"nuxt-contentstack": {
// Required
apiKey: "your_contentstack_api_key",
deliveryToken: "your_delivery_token",
environment: "your_environment",
// Optional
region: "eu", // 'us' | 'eu' | 'au' | 'azure-na' | 'azure-eu' | 'gcp-na' | 'gcp-eu'
branch: "main",
locale: "en-us",
// Live Preview
livePreview: {
enable: true,
previewToken: "your_preview_token",
editableTags: true,
editButton: true, // or object with enable, position, exclude, includeByQueryParameter
mode: "builder", // 'builder' | 'preview'
ssr: false,
},
// Personalization
personalization: {
enable: true,
projectUid: "your_project_uid",
},
debug: true,
},
});
| 选项 | 类型 | 必需 | 默认 | 描述 |
|---|---|---|---|---|
apiKey | string | 是 | - | Contentstack 栈 API 密钥(以“blt”开头) |
deliveryToken | string | 是 | - | 交付令牌(以“cs”开头) |
environment | string | 是 | - | 目标环境(“preview”|“production”) |
region | string | 否 | 'us' | Contentstack 区域 |
branch | string | 否 | 'main' | 内容分支 |
locale | string | 否 | 'en-us' | 默认区域设置 |
调试 | boolean | 否 | false | 启用调试日志记录 |
| 选项 | 类型 | 默认 | 描述 |
|---|---|---|---|
enable | boolean | false | 启用实时预览 |
previewToken | string | - | 预览令牌(如果启用则必需) |
editableTags | boolean | false | 为可视化构建添加可编辑标签 |
editButton | boolean | object | false | 启用/编辑按钮配置 |
模式 | 'builder' | 'preview' | 'builder' | 实时预览模式 |
ssr | boolean | false | 启用 SSR 模式(实验性) |
编辑按钮对象
editButton: {
enable: boolean
position?: 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'top-center' | 'bottom-left' | 'bottom-right' | 'bottom-center'
exclude?: ('insideLivePreviewPortal' | 'outsideLivePreviewPortal')[]
includeByQueryParameter?: boolean
}
| 选项 | 类型 | 必需 | 描述 |
|---|---|---|---|
enable | boolean | 是 | 启用个性化 |
projectUid | string | 是 | 个性化项目 UID |
通过 useNuxtApp().$contentstack 访问
const {
stack, // Delivery SDK Stack instance
ContentstackLivePreview, // Live Preview Utils SDK
Personalize, // Personalize SDK
livePreviewEnabled, // boolean
editableTags, // boolean
variantAlias, // Variant manifest for personalization
VB_EmptyBlockParentClass, // Visual Builder empty block class
} = useNuxtApp().$contentstack;
const { Personalize } = useNuxtApp().$contentstack;
// Set user attributes
await Personalize.set({ age: 20 });
// Trigger impression
await Personalize.triggerImpression(experienceShortId);
// Trigger conversion event
await Personalize.triggerEvent("eventKey");
所有 Composable 都支持实时预览更新、个性化变体和 Nuxt 的缓存系统。
useGetEntryByUrl按 URL 字段获取条目。
const { data, status, refresh } = await useGetEntryByUrl<Page>({
contentTypeUid: "page",
url: "/about",
referenceFieldPath: ["author", "category"],
jsonRtePath: ["rich_text_field"],
locale: "en-us",
replaceHtmlCslp: true,
});
useGetEntry按 UID 获取单个条目。
const { data } = await useGetEntry<Article>({
contentTypeUid: "article",
entryUid: "your_entry_uid",
referenceFieldPath: ["author"],
jsonRtePath: ["content"],
locale: "en-us",
});
useGetEntries通过筛选、分页和排序获取多个条目。
const { data } = await useGetEntries<Article>({
contentTypeUid: "article",
referenceFieldPath: ["author"],
locale: "en-us",
limit: 10,
skip: 0,
orderBy: "created_at",
includeCount: true,
where: {
status: "published",
view_count: { $gt: 1000 },
created_at: { $gte: "2024-01-01", $lt: "2024-12-31" },
featured_image: { $exists: true },
title: { $regex: "nuxt.*contentstack" },
tags: ["tech", "news"],
author: { $ne: "guest" },
},
});
// Access results
console.log(data.value?.entries); // Article[]
console.log(data.value?.count); // number (if includeCount: true)
useGetAsset按 UID 获取单个资产。
const { data } = await useGetAsset<Asset>({
assetUid: "your_asset_uid",
locale: "en-us",
});
useGetAssets通过筛选获取多个资产。
const { data } = await useGetAssets<Asset>({
locale: "en-us",
limit: 20,
orderBy: "created_at",
includeCount: true,
where: {
content_type: "image/jpeg",
// Note: Most asset filters are applied client-side
},
});
在条目 Composable 的 where 子句中受支持
field: "value"tags: ["tech", "news"]field: { $gt: 100, $gte: 50, $lt: 200, $lte: 150, $ne: "value" }field: { $exists: true }field: { $regex: "pattern" }useImageTransform以编程方式转换 Contentstack 图像。
const { transformedUrl, updateTransform, resetTransform } = useImageTransform(
imageUrl,
{
width: 800,
height: 600,
quality: 80,
format: "webp",
fit: "crop",
blur: 5,
saturation: 10,
brightness: 5,
overlay: {
relativeURL: "/watermark.png",
align: "bottom-right",
width: "20p",
},
sharpen: {
amount: 5,
radius: 2,
threshold: 0,
},
}
);
// Update reactively
updateTransform({ width: 1200, quality: 90 });
ContentstackModularBlocks将 Contentstack 模块化块渲染为具有自动获取功能的 Vue 组件。默认情况下,自动获取已启用,其中 contentTypeUid: 'page' 和 url: '/'。在使用预获取块时,要禁用自动获取,请将这些 prop 设置为 undefined。
模式 1:自动获取条目
<script setup>
const componentMapping = {
hero: Hero,
grid: Grid,
text_block: TextBlock,
};
</script>
<template>
<ContentstackModularBlocks
content-type-uid="page"
:url="$route.path"
blocks-field-path="components"
:reference-field-path="['author']"
:json-rte-path="['rich_text']"
:auto-seo-meta="true"
:component-map="componentMapping"
>
<template #loading>Loading...</template>
<template #error>Failed to load</template>
<template #empty>No content</template>
</ContentstackModularBlocks>
</template>
模式 2:预获取块
<script setup>
const { data: page } = await useGetEntryByUrl({
contentTypeUid: "page",
url: useRoute().path,
});
const componentMapping = {
hero: Hero,
grid: Grid,
};
</script>
<template>
<ContentstackModularBlocks
:blocks="page.components"
:component-map="componentMapping"
/>
</template>
| 属性 | 类型 | 默认 | 描述 |
|---|---|---|---|
blocks | ContentstackBlock[] | [] | 模块化块数组 |
componentMap | ComponentMapping | {} | 块类型 → Vue 组件映射 |
fallbackComponent | 组件 | ContentstackFallbackBlock | 用于未映射块的组件 |
contentTypeUid | string | 'page' | 用于自动获取的内容类型 |
url | string | '/' | 用于自动获取的 URL |
blocksFieldPath | string | 'components' | 提取块的字段路径 |
referenceFieldPath | string[] | [] | 要包含的引用字段 |
jsonRtePath | string[] | [] | JSON RTE 字段路径 |
locale | string | 'en-us' | Locale |
replaceHtmlCslp | boolean | editableTags | 替换 HTML CSLP 标签 |
seoMeta | SeoMetaInput | - | SEO 元数据(传递给 useSeoMeta) |
autoSeoMeta | boolean | Record<string, string> | false | 从条目自动生成 SEO |
containerClass | string | 'contentstack-modular-blocks' | 容器 CSS 类 |
emptyBlockClass | string | 'visual-builder__empty-block-parent' | 空块 CSS 类 |
showEmptyState | boolean | true | 显示空状态 |
keyField | string | '_metadata.uid' | 块的关键字段 |
autoExtractBlockName | boolean | true | 自动提取块名称 |
手动 SEO
<ContentstackModularBlocks
:seo-meta="{
title: 'Page Title',
description: 'Page description',
ogImage: 'https://example.com/image.jpg',
}"
/>
自动生成 SEO
<!-- Default field mapping -->
<ContentstackModularBlocks :auto-seo-meta="true" />
<!-- Custom field mapping -->
<ContentstackModularBlocks
:auto-seo-meta="{
title: 'seo_title|title|name',
description: 'meta_description|description',
ogImage: 'featured_image.url',
}"
/>
默认自动 SEO 映射
title: seo_title → title → namedescription: seo_description → description → summaryogImage: featured_image.url → og_image.url → image.urlloading - 自定义加载状态(自动获取模式)error - 自定义错误状态(自动获取模式)empty - 自定义空状态ContentstackFallbackBlock内置的未映射块类型回退组件。显示块标题、类型徽章和格式化为 JSON 的属性。
npm install @nuxt/image
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["nuxt-contentstack", "@nuxt/image"],
image: {
providers: {
contentstack: {
name: "contentstack",
provider:
"node_modules/nuxt-contentstack/dist/runtime/providers/contentstack",
},
},
provider: "contentstack", // Optional: set as default
},
});
<template>
<!-- Basic usage -->
<NuxtImg
:src="image.url"
:alt="image.title"
width="800"
height="400"
:modifiers="{ auto: 'webp,compress', quality: 90 }"
provider="contentstack"
/>
<!-- Responsive -->
<NuxtImg
:src="image.url"
sizes="100vw sm:50vw lg:33vw"
:modifiers="{ auto: 'webp,compress' }"
/>
<!-- Art direction -->
<NuxtPicture
:src="image.url"
sizes="100vw md:50vw"
:modifiers="{ auto: 'webp,compress' }"
/>
</template>
auto: 'webp' | 'webp,compress'quality: numberformat: 'webp' | 'png' | 'jpg' | 'jpeg' | 'gif' | 'auto'width, height, dpr: numberfit: 'bounds' | 'crop'blur, brightness, contrast, saturation: numbersharpen: { amount, radius, threshold }overlay: { relativeURL, align, repeat, width, height, pad }# Install dependencies
npm install
# Generate type stubs
npm run dev:prepare
# Develop with playground
npm run dev
# Build playground
npm run dev:build
# Lint
npm run lint
# Test
npm run test
npm run test:watch
# Release
npm run release