Sanity Studio自定义视图:如何获取引用文档的字段?
如何在Sanity自定义预览视图中展开引用的figure文档字段?
当然可以展开引用并展示对应的资产,核心是要主动获取引用的完整文档数据,而非仅使用默认返回的引用ID。以下是两种可行方案:
方案一:使用useDocument钩子获取引用文档
利用Sanity提供的useDocument钩子,直接通过引用ID拉取完整的figure文档数据:
import React from 'react' import { useDocument } from '@sanity/react-hooks' const CampaignBannerPreview = ({ document }) => { // 通过引用ID获取figure文档 const { data: figure, loading } = useDocument(document.image._ref) if (loading) return <div>加载中...</div> if (!figure) return <div>未选择图片</div> // 拼接Sanity图片CDN地址,替换项目ID和数据集 const imageUrl = figure.image?.asset?._ref ? `https://cdn.sanity.io/images/你的项目ID/你的数据集/${figure.image.asset._ref.split('-')[1]}.${figure.image.asset._ref.split('-')[2]}` : '' return ( <div style={{ padding: '2rem' }}> <h2>{document.title}</h2> <p style={{ margin: '1rem 0' }}>{document.bodyText}</p> {imageUrl && ( <img src={imageUrl} alt={figure.caption || figure.title} style={{ maxWidth: '100%', marginBottom: '1rem' }} /> )} {figure.caption && <p><em>{figure.caption}</em></p>} <a href={document.callToAction.url} style={{ display: 'inline-block', padding: '0.5rem 1rem', background: '#0055cc', color: 'white', textDecoration: 'none' }} > {document.callToAction.text} </a> </div> ) } // 在defaultDocumentNodeResolver中注册自定义视图 export default function defaultDocumentNodeResolver(S, { schemaType }) { if (schemaType === 'campaignBanner') { return S.document().views([ S.view.form(), S.view.component(CampaignBannerPreview).title('横幅预览') ]) } return S.document() }
方案二:使用GROQ查询预展开引用
通过GROQ查询主动指定要展开的引用字段,更灵活地控制返回的数据结构:
import React, { useEffect, useState } from 'react' import { useClient } from '@sanity/react-hooks' const CampaignBannerPreview = ({ documentId }) => { const client = useClient() const [bannerData, setBannerData] = useState(null) const [loading, setLoading] = useState(true) useEffect(() => { const fetchFullBannerData = async () => { const data = await client.fetch(` *[_id == $documentId][0]{ title, bodyText, callToAction, // 展开figure引用,并进一步展开image的asset image->{ title, caption, image{ asset-> } } } `, { documentId }) setBannerData(data) setLoading(false) } fetchFullBannerData() }, [client, documentId]) if (loading) return <div>加载中...</div> if (!bannerData) return <div>未找到横幅数据</div> const imageUrl = bannerData.image?.image?.asset?._id ? `https://cdn.sanity.io/images/你的项目ID/你的数据集/${bannerData.image.image.asset._id.split('-')[1]}.${bannerData.image.image.asset._id.split('-')[2]}` : '' return ( <div style={{ padding: '2rem' }}> <h2>{bannerData.title}</h2> <p style={{ margin: '1rem 0' }}>{bannerData.bodyText}</p> {imageUrl && ( <img src={imageUrl} alt={bannerData.image.caption || bannerData.image.title} style={{ maxWidth: '100%', marginBottom: '1rem' }} /> )} {bannerData.image?.caption && <p><em>{bannerData.image.caption}</em></p>} <a href={bannerData.callToAction.url} style={{ display: 'inline-block', padding: '0.5rem 1rem', background: '#0055cc', color: 'white', textDecoration: 'none' }} > {bannerData.callToAction.text} </a> </div> ) } // 注册自定义视图 export default function defaultDocumentNodeResolver(S, { schemaType }) { if (schemaType === 'campaignBanner') { return S.document().views([ S.view.form(), S.view.component(CampaignBannerPreview).title('横幅预览') ]) } return S.document() }
注意事项
- 替换代码中的
你的项目ID和你的数据集为你Sanity项目的实际信息 - 确保已安装
@sanity/react-hooks依赖:npm install @sanity/react-hooks - 两种方案都能实现需求,GROQ方案更适合需要精准控制数据字段的场景
内容的提问来源于stack exchange,提问作者Alejandro Aburto
相关产品推荐
相关产品推荐

