reactjs gutenberg 自定义图像块,alt文本不显示在预览

oxiaedzo  于 2023-05-06  发布在  React
关注(0)|答案(1)|浏览(92)

试图从 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" }
    }
}
vmdwslir

vmdwslir1#

我明白了。通常当我遇到这种情况时,这是因为属性类型与我实际传递的属性类型不一样。因此,在您的示例中,属性“alt”应该是“string”类型,它就是这样。所以这不可能是问题所在。
尝试将其保存到块存储本身,而不是从DOM元素中获取:

"alt": {
        "type": "string",
        "default": "Alt Text"
      },

相关问题