后端获取的html标签页面如何正常显示?

如下图:
image.png
这一段html是通过后端返回得到的,我通过innerhtml添加进来的

/** @odoo-module **/
// html_to_text_widget.js
import { registry } from "@web/core/registry";
import { Component } from "@odoo/owl";
import { standardWidgetProps } from "@web/views/widgets/standard_widget_props";

/**
 * HtmlToTextWidget
 * 将 HTML 内容转换为纯文本显示的组件
 */
class HtmlToTextWidget extends Component {
    static template = "wits_html.HtmlToTextWidget";
    static props = {
        ...standardWidgetProps,
    };

    setup() {
    }

    get plainText() {
        const htmlContent = (this.props.record?.data[this.props.name] || '');
        
        if (!htmlContent) {
            return '';
        }
        
        try {
            // 使用textContent提取纯文本
            const tempDiv = document.createElement('div');
            tempDiv.innerHTML = htmlContent;
            return tempDiv.textContent || '';
        } catch (error) {
            console.error("Error converting HTML to text:", error);
            return '';
        }
    }

    // 生命周期钩子,确保组件正确初始化
    connectedCallback() {
        super.connectedCallback();
        // 初始化时刷新数据
        this.invalidate();
    }
}

export const htmlToTextWidget = {
    component: HtmlToTextWidget,
    extractProps: ({ attrs, node }) => ({
    }),
};

// 注册到 fields 类别
registry.category("fields").add("html_to_text", htmlToTextWidget);

我现在遇到一个问题:后端返回了一个包含HTML模板的字符串,但前端直接显示的时候,它并没有被渲染成正常的网页内容,而是作为纯文本显示出来。我需要找让这个HTML字符串能够在页面上正常显示,就像普通的HTML一样。

阅读 754
4 个回答

你应该把你创建的节点 tempDiv return出去吧

/** @odoo-module **/
import { registry } from "@web/core/registry";
import { Component } from "@odoo/owl";
import { standardWidgetProps } from "@web/views/widgets/standard_widget_props";

/**
 * HtmlWidget
 * 将 HTML 字符串渲染为实际 HTML 内容的组件
 */
class HtmlWidget extends Component {
    static template = "wits_html.HtmlToTextWidget";
    
    // 定义组件的属性
    static props = {
        ...standardWidgetProps,
    };

    setup() {
        super.setup();
    }

    /**
     * 获取HTML内容
     * @returns {string} HTML内容
     */
    get htmlContent() {
        return this.props.record?.data[this.props.name] || '';
    }
}

export const htmlWidget = {
    component: HtmlWidget,
    extractProps: ({ attrs }) => ({
    }),
};

// 注册组件到 fields 类别
registry.category("fields").add("html_viewer", htmlWidget);
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
    <t t-name="wits_html.HtmlToTextWidget">
      <div t-raw="widget.htmlContent"/>
      </t>
</templates>

你遇到的问题是因为在前端将包含 HTML 模板的字符串直接显示时,浏览器把它当作纯文本处理了。以下是几种可以让后端返回的 HTML 字符串在页面上正常渲染的方法:

使用 innerHTML 直接赋值(确保数据安全)

从你当前的代码来看,你已经尝试使用 innerHTML 了,但可能因为某些原因没有成功。确保在合适的位置将后端返回的 HTML 字符串赋值给目标元素的 innerHTML 属性。例如,如果你有一个 div 元素作为容器来显示 HTML 内容:

<div id="html - container"></div>

在 JavaScript 中可以这样做:

const htmlContainer = document.getElementById('html - container');
const htmlContent = // 从后端获取的 HTML 字符串,比如你代码中的 this.props.record?.data[this.props.name]
htmlContainer.innerHTML = htmlContent;

不过要注意,这种方式如果处理不当,可能会存在 XSS(跨站脚本攻击)风险。如果 HTML 字符串来自不可信的来源,务必对其进行安全过滤,比如使用像 DOMPurify 这样的库来清理字符串中的恶意代码:

import DOMPurify from 'dompurify';

const cleanHtml = DOMPurify.sanitize(htmlContent);
htmlContainer.innerHTML = cleanHtml;

使用 v-html(如果使用 Vue.js)

如果你使用的是 Vue.js 框架,你可以使用 v-html 指令来渲染 HTML 字符串:

<template>
  <div>
    <div v-html="htmlContent"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      htmlContent: '' // 从后端获取的 HTML 字符串
    };
  },
  mounted() {
    // 假设这里从后端获取数据并赋值给 htmlContent
    // 比如通过 axios 等方式获取
    this.htmlContent = // 后端返回的 HTML 字符串
  }
};
</script>

同样,使用 v-html 时也要注意安全问题,对数据进行必要的过滤。

在 Odoo 环境中调整组件逻辑

由于你使用的是 Odoo 框架,你可以在你的 HtmlToTextWidget 组件中进一步调整逻辑来实现正确渲染。例如,你可以在组件的模板中添加一个目标元素,然后在 setup 或其他生命周期钩子中直接将 HTML 字符串赋值给该元素的 innerHTML

class HtmlToTextWidget extends Component {
    static template = "wits_html.HtmlToTextWidget";
    static props = {
       ...standardWidgetProps,
    };

    setup() {
        const htmlContent = (this.props.record?.data[this.props.name] || '');
        if (htmlContent) {
            const targetElement = this.el.querySelector('.html - target'); // 假设模板中有一个类名为 html - target 的元素
            if (targetElement) {
                targetElement.innerHTML = htmlContent;
            }
        }
    }
}

然后在你的模板文件 wits_html.HtmlToTextWidget.xml 中添加对应的元素:

<template id="wits_html.HtmlToTextWidget">
  <div>
    <div class="html - target"></div>
  </div>
</template>

通过以上方法,应该能够让后端返回的 HTML 字符串在页面上正常渲染为网页内容。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏