试图从 gutenberg 自定义图像块中获取alt文本以进行渲染。我可以看到alt文本时,我检查从编辑器,但不是从预览。需要在预览和实时版本中看到alt文本。谢谢你的帮助
对不起所有的代码。详细信息在代码中。
edit.js
export default function Edit({ attributes, clientId, setAttributes }) {
const [block, setBlock] = useState();
const { action, url, newtab, popup, atts, alt} = attributes;
const blockRef = useCallback(node=>{ setBlock(node); },[]);
const blockProps = useBlockProps({ref:blockRef});
const [linkModal, editLink] = useState(false);
const dataAttributes = false;
const actionOptions = [
{ value: '', label: 'Select Action' },
{ value: 'link', label: 'Link' },
{ value: 'document', label: 'Document' },
{ value: 'popup', label: 'Popup' }
]
const options = (type, label = 'Select') => {
const attributes = { order: 'asc', orderby: 'title', post_status: 'publish', 'per_page': -1 };
const data = useSelect((select) => { return select('core').getEntityRecords('postType', 'smarttouch_'+type, attributes); });
let options = [];
if(data) { options.push({ value: '', label}); data.forEach(i=>{ options.push({ value: i.id.toString(), label: i.title.rendered }); }); }
else { options.push({ value: '', label: 'Loading...'}); }
return options;
}
const popupOptions = options('popup');
const [attsList, setAttsList] = useState([]);
useEffect(()=>{
if(!atts) return;
if(!linkModal) return;
window.attsList = atts;
},[linkModal,atts]);
useEffect(()=>{
if(!popup) return;
fetch('/wp-json/smarttouch/popup/'+popup).then(r=>r.json()).then((p) => {
let attslist = p.post_content.match(/\[\[[^\]]+\]\]/g);
attslist.forEach((att,i)=>{ att = att.replace(/[\[|\]]/g,''); attslist[i] = att; });
setAttsList(attslist);
});
},[popup]);
useEffect(()=>{
resp.link.action = action;
resp.link.url = url;
resp.link.alt = alt;
resp.link.newtab = newtab;
resp.link.popup = popup;
resp.link.atts = atts;
updateImage();
},[action, url, newtab, popup, atts, alt]);
if((action=='document')&&(!newtab)) setAttributes({newtab:true});
let { resp } = attributes;
const kitten = 'https://placekitten.com/1280/720?image='+Math.floor(Math.sin(parseInt(clientId.replace(/[^0-9]/,'')))*8+8);
resp = lodash.merge({
desktop: { url: kitten, alt:'Placeholder Kitten',caption:'Placeholder Kitten (For Position Only)', ratio: 56.25, focalx: 0.5, focaly: 0.5, scale: 1, fit: 'cover' },
tablet: { },
mobile: { },
svg: { colorMode: 'default', color: '#000' },
link: {}
}, JSON.parse(resp));
const disp = resp[document.preview];
const [ getResp, setResp] = useState();
const ratios = [
{ value: '', label: 'Quick Set Ratio'},
{ value: '', label: 'Auto' },
{ value: '25', label: '4:1'},
{ value: '33.33', label: '3:1'},
{ value: '50', label: '2:1'},
{ value: '56.25', label: '16:9'},
{ value: '66.66', label: '2:3'},
{ value: '75', label: '3:4'},
{ value: '100', label: '1:1'},
{ value: '133.33', label: '4:3'},
{ value: '150', label: '3:2'},
{ value: '177', label: '9:16'},
{ value: '200', label: '1:2'}
];
const fits = [
{ value: 'cover', label: 'Cover'},
{ value: 'contain', label: 'Contain'},
{ value: 'scale-down', label: 'Scale Down'},
{ value: 'fill', label: 'Stretch'}
];
const svgColorModes = [
{ value: 'default', label: 'Keep SVG Colors' },
{ value: 'css', label: 'Use Theme CSS Color' },
{ value: 'select', label: 'Select Color' }
];
useEffect(()=>{
if(!block) return;
const figure = block.querySelector('figure');
const img = disp.url||resp.desktop.url;
const prevFigure = figure.innerHTML;
figure.style.setProperty('--focalx', (disp.focalx||resp.desktop.focalx)*100+'%');
figure.style.setProperty('--focaly', (disp.focaly||resp.desktop.focaly)*100+'%');
figure.style.setProperty('--scale', disp.scale||resp.desktop.scale);
figure.style.setProperty('--fit', disp.fit||resp.desktop.fit||'cover');
let ratio = disp.ratio||resp.desktop.ratio;
if(ratio=='auto') {
let i = document.createElement('img');
i.onload = () => {
disp.ratio = Math.floor(i.height / i.width * 10000) / 100;
console.log('Save To Update Image Ratio');
updateImage();
}
i.src = img;
}
figure.style.setProperty('--ratio', ratio+'%');
if(img.split('.').pop()=='svg') {
fetch(img).then(res=>res.text()).then((svg)=>{
svg = svg.replace(/<\?xml[^\?]*\?>/,'');
svg = svg.replace(/<!--[\s\S]*?-->\r?\n?/g,'');
if(resp.svg.colorMode!=='default') {
svg = svg.replace(/\#[a-f0-9A-F]{3,6}/g,'currentColor');
if(svg.search(/currentColor/)<0) svg = svg.replace(/(<svg.*?>)(.*)<\/svg>/gs,'$1<g fill="currentColor">$2</g></svg>');
}
if(disp.ratio=='auto') {
const svgDom = new DOMParser().parseFromString(svg,'image/svg+xml').firstChild;
let v = svgDom.getAttribute('viewBox');
if(v) { v = v.split(' '); figure.paddingBottom = ((v[3] - v[1]) / (v[2] - v[0])) * 100 + '%'; }
}
if(prevFigure!=svg) figure.innerHTML = svg;
if(resp.svg.colorMode=='select') { figure.querySelector('svg').setAttribute('color', resp.svg.color); }
});
} else {
const newFigure = '<img src="'+img+'" alt="'+resp.desktop.alt+'">';
if(prevFigure!=newFigure) figure.innerHTML = newFigure;
}
figure.classList.add('loaded');
},[getResp]);
useEffect(()=>{
setResp(LZUTF8.compress(JSON.stringify(resp),{outputEncoding:'Base64'}));
},[block]);
const updateImage = () => {
setAttributes({resp:JSON.stringify(resp)});
setResp(LZUTF8.compress(JSON.stringify(resp),{outputEncoding:'Base64'}));
};
document.onpreview[clientId] = () => {
setResp(LZUTF8.compress(JSON.stringify(resp),{outputEncoding:'Base64'}));
}
return (
<>
<InspectorControls>
<PanelBody initialOpen={true}>
{(~(resp[document.preview.url]||resp.desktop.url).indexOf('.svg')) && (
<div class="squareImage"><img src={disp.url||resp.desktop.url} /></div>
)||(
<>
<FocalPointPicker
url={disp.url||resp.desktop.url}
dimensions={{width:disp.width,height:disp.height}}
value={{x:disp.focalx,y:disp.focaly}}
onDrag={focalPoint => {
const figure = block.querySelector('figure');
figure.style.setProperty('--focalx',focalPoint.x*100+'%');
figure.style.setProperty('--focaly',focalPoint.y*100+'%');
}}
onChange={focalPoint => {
disp.focalx = focalPoint.x;
disp.focaly = focalPoint.y;
updateImage();
}}
/>
<RangeControl renderTooltipContent={()=>{ return Math.round(disp.scale*100)+'%';}} step={0.01} withInputField={false} min={0.5} max={2} value={disp.scale} onChange={scale=>{ disp.scale = scale; updateImage(); }} />
</>
)}
<div className="flex">
{(document.preview=='desktop')&&(
<MediaUpload className="block" value={resp.desktop.id||false} allowedTypes={['image/jpeg','image/png','image/svg+xml']} onSelect={(media)=>{
if(media.id!=resp.desktop.id) {
resp.desktop.id = media.id; delete resp.tablet.id; delete resp.mobile.id;
resp.desktop.url = media.url.replace(location.origin,''); delete resp.tablet.url; delete resp.mobile.url;
resp.desktop.alt = media.alt;
resp.desktop.caption = media.caption;
resp.desktop.focalx = 0.5; delete resp.tablet.focalx; delete resp.mobile.focalx;
resp.desktop.focaly = 0.5; delete resp.tablet.focaly; delete resp.mobile.focaly;
resp.desktop.scale = 1; delete resp.tablet.scale; delete resp.mobile.scale;
if(!resp.desktop.ratio) resp.desktop.ratio = Math.floor(media.height / media.width * 10000) / 100; delete resp.tablet.ratio; delete resp.mobile.ratio;
updateImage();
}
}} render={({open})=>(<Button isPrimary={true} onClick={open}><Dashicon icon={(resp.desktop.id||false)?'format-image':'upload'} /> {(resp.desktop.id||false)?'UPDATE':'UPLOAD'} IMAGE</Button>)} />
)}
{(document.preview!='desktop')&&(
<MediaUpload className="block" value={disp.id||resp.desktop.id} allowedTypes={['image/jpeg','image/png','image/svg+xml']} onSelect={(media)=>{
if(media.id!=disp.id) {
disp.id = media.id;
disp.alt = media.alt;
disp.url = media.url.replace(location.origin,'');
disp.focalx = 0.5;
disp.focaly = 0.5;
disp.scale = 1;
if(!disp.ratio) disp.ratio = Math.floor(media.height / media.width * 10000) / 100;
updateImage();
}
}} render={({open})=>(<Button isSecondary={true} onClick={open}><Dashicon icon={document.preview=='mobile'?'smartphone':document.preview} /> CHANGE {document.preview.toUpperCase()} IMAGE</Button>)} />
)}
</div>
<div className="flex">
<SelectControl label="Ratio" options={ratios} value="" onChange={ratio=>{
if(!ratio) {
let img = document.createElement('img');
img.onload = () => {
disp.ratio = Math.floor(img.height / img.width * 10000) / 100;
updateImage();
}
img.src = disp.url||resp.desktop.url;
} else {
disp.ratio = ratio;
updateImage();
}
}} />
<SelectControl label="Fit" options={fits} value={disp.fit||resp.desktop.fit} onChange={fit=>{ disp.fit = fit; updateImage(); }} />
</div>
<div class="flex">
<RangeControl renderTooltipContent={()=>{ return (disp.ratio||resp.desktop.ratio)+'%'; }} step={1} withInputField={false} min={0} max={100} value={+(disp.ratio||resp.desktop.ratio)} onChange={ratio=>{disp.ratio = ratio; updateImage(); }} />
</div>
{(~(disp.url||resp.desktop.url).indexOf('.svg')) && (
<>
<SelectControl label="SVG Color Mode" options={svgColorModes} value={resp.svg.colorMode} onChange={e=>{ resp.svg.colorMode = e; updateImage(); }} />
{(resp.svg.colorMode=='select') && (
<ColorPaletteControl value={resp.svg.color} onChange={(e)=>{ resp.svg.color = e; updateImage(); }} />
) || ''}
</>
) || ''}
<div class="flex">
<Button name="link" variant="primary" title="Link" icon="edit-large" onClick={e=>editLink(true)}>Edit Link Action</Button>
</div>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
<figure className="ratio" data-resp={getResp}></figure>
</div>
{linkModal&&(<>
<Modal title={"Button Action"} onRequestClose={e=>{if(e.type=='click') editLink(false); }} isDismissible={true}>
<div className="cta-config">
<div className="flex">
<SelectControl help={"Click Through Action"} options={actionOptions} value={action}
onChange={e=>{ setAttributes({action: e}); }} __nextHasNoMarginBottom />
{(action=='popup')&&(
<SelectControl help="Popup" options={popupOptions} value={popup}
onChange={e=>{ setAttributes({popup: e, newtab: false}); }} __nextHasNoMarginBottom />
)}
</div>
{(action=='link')&&(
<LinkControl
value={{url: url, opensInNewTab: newtab}}
onChange={({ url: url = '', opensInNewTab: opensInNewTab}) => {
setAttributes({url, newtab: opensInNewTab });
}}
onRemove={(e)=>{
setAttributes({url:'', newtab:false});
}}
/>
)}
{(action=='document')&&(
<MediaUpload
multiple={false}
gallery={false}
allowedTypes={[
'application/pdf',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'text/csv',
'text/plain',
'application/rtf',
'application/zip'
]}
onSelect={(doc) => { setAttributes({ url: doc.url.replace(location.origin,''), newtab: true }) }}
render={ ({open}) => { return <div className="uploadDoc"><Button icon="upload" variant="primary" onClick={e=>open()}>{url?'Change':'Upload'} Document</Button><span>{url}</span></div> }}
/>
)}
{attsList&&(
<div>
<label className="dataLabel" onClick={e=>{e.target.classList.toggle('active')}}>Requested Data Attributes</label>
<div className="data">
<label>ATTRIBUTE</label>
<label>SET VALUE</label>
{attsList.map((key, i) => (<>
<label>{"[["+key+"]]"}</label>
<div><input type="text" value={atts[key]||''} onChange={e=>{atts[key]=e.target.value;setAttributes({atts: {...atts}})}}/></div>
</>))}
</div>
</div>
)}
{action&&(
<div class="flex">
{['link','anchor','document'].includes(action)&&(
<a className="cta-test" href={url} target="_blank">TEST LINK</a>
)}
{(action=='popup')&&(
<a className="cta-test" onClick={e=>{openPopup(popup,[],(base)=>{
processAccordians(base);
processButtons(base);
processForms(base);
processGalleries(base);
processHomes(base);
processImages(base);
processSlides(base);
processTabs(base);
processConditions(base);
})}}>TEST LINK</a>
)}
</div>
)}
</div>
</Modal>
</>)||''}
</>
);
}
save.js
export default function save({ attributes }) {
const blockProps = useBlockProps.save();
let { resp, alt } = attributes;
const respData = LZUTF8.compress(resp,{outputEncoding:'Base64'})
return (
<div { ...blockProps }>
<figure className="ratio" data-resp={respData}>
<img src="#" alt={alt} />
</figure>
</div>
);
}
block.json
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "smarttouch/image",
"version": "0.1.0",
"title": "Image",
"category": "smarttouch",
"description": "Advanced image block",
"textdomain": "image",
"editorScript": "file:../../build/image.js",
"editorStyle": "file:../../build/image.css",
"supports": {
"html": false,
"anchor": false,
"align": ["wide","full"],
"lock": false
},
"attributes": {
"resp": {
"type": "string",
"default": "{}"
},
"alt": {
"type": "string",
"default": "Alt Text",
"source": "attribute",
"selector": "figure img",
"attribute": "alt"
},
"svgColorMode": {
"type": "string",
"default": "default"
},
"svgColor": {
"type": "string",
"default": "#000"
},
"atts": { "type": "object", "default": {} },
"label": { "type": "string" },
"action": { "type": "string" },
"url": { "type": "string" },
"newtab": { "type": "boolean" },
"popup": { "type": "string" }
}
}
1条答案
按热度按时间vmdwslir1#
我明白了。通常当我遇到这种情况时,这是因为属性类型与我实际传递的属性类型不一样。因此,在您的示例中,属性“alt”应该是“string”类型,它就是这样。所以这不可能是问题所在。
尝试将其保存到块存储本身,而不是从DOM元素中获取: