Gatsby对接Contentful CMS时富文本内容中图片无法显示问题求助
解决方案
你的问题由两个核心原因导致:
- GraphQL查询没有拉取资源的唯一标识ID,无法和富文本中返回的asset ID做匹配
EMBEDDED_ASSET的渲染逻辑没有处理ID和实际资源的匹配关联,仅打印了node原始信息- 补充说明:
embedded-asset-block的content字段本身就是空设计,资源关联信息全部存储在data.target.sys.id中,不需要关注该字段为空的问题
第一步:修改GraphQL查询
补充references下的sys.id字段,用于关联匹配,同时可以补充文件名、资源类型字段方便后续使用:
query getThisProjectBySlug($slug: String) { allContentfulProject(filter: {slug: {eq: $slug}}) { nodes { slug id subtitle title details { raw references { sys { id } file { url fileName contentType } } } } } }
第二步:修改富文本图片渲染逻辑
重写BLOCKS.EMBEDDED_ASSET的处理函数,匹配对应ID的资源并渲染图片,注意Contentful返回的资源URL默认不带https协议头,需要手动拼接:
const options = { renderMark: { [MARKS.BOLD]: (text) => <Bold>{text}</Bold>, }, renderNode: { [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>, [BLOCKS.EMBEDDED_ASSET]: node => { // 获取当前嵌入资源的ID const assetId = node.data.target.sys.id // 从返回的资源列表中匹配对应ID的资源 const targetAsset = details.references.find(asset => asset.sys.id === assetId) // 仅当资源存在且为图片类型时渲染 if (targetAsset?.file?.url && targetAsset.file.contentType.startsWith('image/')) { return <img src={`https:${targetAsset.file.url}`} alt={targetAsset.file.fileName} style={{maxWidth: '100%', margin: '16px 0'}} /> } return null }, }, };
修改后完整代码
import React from 'react' import { graphql } from 'gatsby' import Layout from '../../components/layout' import { renderRichText } from "gatsby-source-contentful/rich-text" import { BLOCKS, MARKS } from '@contentful/rich-text-types'; export default function ProjectDetails({ data, location }) { const { title, subtitle, details } = data.allContentfulProject.nodes[0] const Bold = ({ children }) => <span className="bold">{children}</span>; const Text = ({ children }) => <p className="align-center">{children}</p>; const options = { renderMark: { [MARKS.BOLD]: (text) => <Bold>{text}</Bold>, }, renderNode: { [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>, [BLOCKS.EMBEDDED_ASSET]: node => { const assetId = node.data.target.sys.id const targetAsset = details.references.find(asset => asset.sys.id === assetId) if (targetAsset?.file?.url && targetAsset.file.contentType.startsWith('image/')) { return <img src={`https:${targetAsset.file.url}`} alt={targetAsset.file.fileName} style={{maxWidth: '100%', margin: '16px 0'}} /> } return null }, }, }; return ( <Layout> <div> <h1>{title}</h1> <h2>{subtitle}</h2> <p>{renderRichText(details, options)}</p> </div> </Layout> ) } export const query = graphql` query getThisProjectBySlug($slug: String) { allContentfulProject(filter: {slug: {eq: $slug}}) { nodes { slug id subtitle title details { raw references { sys { id } file { url fileName contentType } } } } } } `
内容的提问来源于stack exchange,提问作者KylianMbappe
相关产品推荐
相关产品推荐

