You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Wagtail中Draftail编辑器添加脚注功能报错求助

扩展Wagtail Draftail编辑器添加脚注功能及React报错排查

我来帮你梳理这个问题的排查方向,并给出修正后的实现代码。你遇到的React Error #130本质是组件渲染时传入了未定义的元素,结合你的代码来看,主要有几个关键问题需要修复:

一、报错核心排查点

  1. PropTypes未正确引入:你的footnote.js里使用了PropTypes但没有从Wagtail的全局环境中获取,Wagtail后台已经内置了PropTypes,不需要额外导入,直接调用全局对象即可。
  2. Python类方法语法错误:FootnoteEntityElementHandler的get_attribute_data方法缺少闭合的括号和大括号,导致后端语法错误,进而影响前端实体解析逻辑。
  3. Draft.js API调用逻辑问题:Modifier.applyEntity的返回值是ContentState,你的代码在传递给EditorState.push时存在参数错误,导致EditorState更新失败。
  4. React JSX属性错误:JSX规范中应该用className而非原生HTML的class属性,这是React的语法要求。

二、修正后的完整代码

1. wagtail_hooks.py 修正版

先确保导入必要模块,修复语法错误:

from wagtail import hooks
from wagtail.rich_text import features
from wagtail.rich_text.converters.html_to_contentstate import InlineEntityElementHandler
from wagtail.utils.widgets import DOM


@hooks.register('register_rich_text_features')
def register_footnote_feature(features):
    features.default_features.append('footnote')
    """
    Registering the `footnote` feature, which uses the `FOOTNOTE` Draft.js entity type, and is stored as HTML with a `<span data-footnote>` tag.
    """
    feature_name = 'footnote'
    type_ = 'FOOTNOTE'
    control = {
        'type': type_,
        'label': '$',
        'description': 'Footnote',
    }
    features.register_editor_plugin(
        'draftail', feature_name,
        features.EntityFeature(
            control, js=['js/footnote.js'], css={'all': []}
        )
    )
    features.register_converter_rule('contentstate', feature_name, {
        'from_database_format': {'span[data-footnote]': FootnoteEntityElementHandler(type_)},
        'to_database_format': {'entity_decorators': {type_: footnote_entity_decorator}},
    })


def footnote_entity_decorator(props):
    """
    Draft.js ContentState to database HTML.
    Converts the FOOTNOTE entities into a span tag.
    """
    return DOM.create_element('span', {
        'data-footnote': props['footnote'],
    }, props['children'])


class FootnoteEntityElementHandler(InlineEntityElementHandler):
    """
    Database HTML to Draft.js ContentState.
    Converts the span tag into a FOOTNOTE entity, with the right data.
    """
    mutability = 'MUTABLE'
    
    def get_attribute_data(self, attrs):
        """
        Take the ``footnote`` value from the ``data-footnote`` HTML attribute.
        """
        return {
            'footnote': attrs['data-footnote'],
        }  # 修复:添加缺失的闭合括号和大括号

2. footnote.js 修正版

修复PropTypes引用、EditorState更新逻辑和JSX属性:

const React = window.React;
const Modifier = window.DraftJS.Modifier;
const EditorState = window.DraftJS.EditorState;
const PropTypes = window.PropTypes;  // 从Wagtail全局环境获取PropTypes

class FootnoteSource extends React.Component {
    componentDidMount() {
        const { editorState, entityType, onComplete } = this.props;
        const currentContent = editorState.getCurrentContent();
        
        // 创建新实体并应用到选中内容
        const contentWithEntity = currentContent.createEntity(
            entityType.type, 
            'MUTABLE', 
            { footnote: '' }  // 初始化footnote数据,可后续扩展输入功能
        );
        const entityKey = contentWithEntity.getLastCreatedEntityKey();
        const newContent = Modifier.applyEntity(
            currentContent,
            editorState.getSelection(),
            entityKey
        );
        
        const nextState = EditorState.push(editorState, newContent, 'apply-entity');
        onComplete(nextState);
    }
    
    render() {
        return null;
    }
}

const Footnote = (props) => {
    const { children, entityKey, contentState } = props;
    const data = contentState.getEntity(entityKey).getData();
    
    return (
        <span role="button" className="FootnoteEntity">
            <span className="FootnoteEntity__label" aria-hidden="true">[Footnote]</span>
            {children}
        </span>
    );
};

Footnote.propTypes = {
    entityKey: PropTypes.string.isRequired,
    contentState: PropTypes.object.isRequired,
};

window.draftail.registerPlugin({
    type: 'FOOTNOTE',
    source: FootnoteSource,
    decorator: Footnote,
});

三、额外优化建议

  • 如果需要让用户输入自定义脚注内容,可以扩展FootnoteSource组件,添加模态框收集脚注文本后再更新实体数据。
  • 可以给脚注标记添加自定义CSS样式,让编辑器内的脚注标识更显眼。
  • 测试时建议开启Wagtail开发模式(DEBUG=True),这样能看到未压缩的React错误详情,更便于后续排查问题。

内容的提问来源于stack exchange,提问作者Savel Mtrx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 15:42:46