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

Mithril递归View函数调用后子评论未正常渲染问题排查

问题根因

子评论无法正常渲染由3个核心问题导致:

  • 遍历子评论时使用了Array.prototype.forEach,该方法没有返回值,Mithril框架的view函数拿不到生成的虚拟节点数组,无法生成子评论DOM。
  • 直接修改commentStruct.showReplies状态后,没有触发Mithril的重绘逻辑,点击展开按钮后框架不会重新执行视图渲染。
  • 表格DOM结构不符合规范:<tr>标签的合法直接子元素只有<td>/<th>,原代码直接把展开箭头<i>、操作下拉框<select>放在<tr>下,浏览器自动修正DOM时会打乱节点结构。
修复方案

将遍历方法替换为返回数组的map,切换展开状态后手动调用重绘方法,同时修正表格结构,把非单元格元素放到对应<td>内部:

function DisplayComment(commentStruct, identity) {
  const comment = commentStruct.comment;
  return {
    oninit: (v) => {
      console.log(comment.mComment);
    },
    view: (v) => [
      m('tr', [
        // 展开箭头+评论内容放在同一个td内,符合表格规范
        m('td', [
          m('i.fas.fa-angle-right', {
            class: 'fa-rotate-' + (commentStruct.showReplies ? '90' : '0'),
            style: 'margin-right: 8px; cursor: pointer; margin-top:12px',
            onclick: () => {
              commentStruct.showReplies = !commentStruct.showReplies;
              // 手动触发框架重绘
              m.redraw();
            },
          }),
          comment.mComment
        ]),
        // 操作下拉框放在独立td内
        m('td', [
          m(
            'select[id=options]',
            {
              onchange: (e) => {
                if (e.target.selectedIndex === 1) {
                  // 回复逻辑
                  util.popupMessage(
                    m(AddComment, {
                      parent_comment: comment.mComment,
                      channelId: comment.mMeta.mGroupId,
                      authorId: identity,
                      threadId: comment.mMeta.mThreadId,
                      parentId: comment.mMeta.mMsgId,
                    })
                  );
                } else if (e.target.selectedIndex === 2) {
                  // 赞逻辑
                  AddVote(
                    util.GXS_VOTE_UP,
                    comment.mMeta.mGroupId,
                    comment.mMeta.mThreadId,
                    identity,
                    comment.mMeta.mMsgId
                  );
                } else if (e.target.selectedIndex === 3) {
                  // 踩逻辑
                  AddVote(
                    util.GXS_VOTE_DOWN,
                    comment.mMeta.mGroupId,
                    comment.mMeta.mThreadId,
                    identity,
                    comment.mMeta.mMsgId
                  );
                }
                // 重置下拉框默认选中项
                e.target.selectedIndex = 0;
              },
            },
            [
              m('option[hidden][selected]', 'Options'),
              util.optionSelect.opts.map((option) =>
                m('option', { value: option }, option.toLocaleString())
              ),
            ]
          )
        ]),
        m('td', rs.userList.userMap[comment.mMeta.mAuthorId]),
        m(
          'td',
          typeof comment.mMeta.mPublishTs === 'object'
            ? new Date(comment.mMeta.mPublishTs.xint64 * 1000).toLocaleString()
            : 'undefined'
        ),
        m('td', comment.mScore),
        m('td', comment.mUpVotes),
        m('td', comment.mDownVotes),
      ]),
      commentStruct.showReplies
        ? Data.ParentCommentMap[comment.mMeta.mMsgId]
          // 用map替换forEach,返回虚拟节点数组供框架渲染
          ? Data.ParentCommentMap[comment.mMeta.mMsgId].map(
              (value) =>
                Data.Comments[value.mMeta.mThreadId] &&
                Data.Comments[value.mMeta.mThreadId][value.mMeta.mMsgId]
                  ? m(DisplayComment(
                      Data.Comments[value.mMeta.mThreadId][value.mMeta.mMsgId],
                      identity
                    ))
                  : null
            )
          : null
        : null,
    ],
  };
}
可选优化
  • 递归渲染时传入层级参数,给子评论的第一个td增加对应倍数的左侧内边距,从视觉上明确评论的层级关系。
  • 空返回值统一用null替代空字符串'',避免框架渲染无用的空文本节点。

内容的提问来源于stack exchange,提问作者Sukhamjot Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 15:45:38