将 plotly fig.to_html 嵌入到 Vue 组件中

Embed plotly fig.to_html into Vue component

我生成了一个名为 fig 的绘图图,它在 django 模型中保存为 fig.to_html,我正在使用 graphql 将其导出到 Vue。

Vue 接收数据没有问题,但在显示元素时我得到的是 HTML 代码而不是图形图像。

显示图表而不是 HTML 代码的正确方法是什么?

这些是我将图表保存到 HTML:

的设置
        config = dict({
            'displayModeBar': True,
            'displaylogo': False,
            'modeBarButtonsToRemove': [
                'toImage',
                'select2d',
                'lasso2d',
            ],

        })
    
        fig.to_html(config=config, include_plotlyjs=False, full_html=False)

这是我的 Vue 组件。 signal.signalChart 是 plotly HTML 元素:

<template>
  <div class="signal" v-if="signal">
    <h2>{{ signal.symbol }}: {{ signal.marketOpen }}</h2>
    <div>{{ displayableDate(signal.date) }}</div>
    <ul>
      <li>{{ signal.bias }}</li>
      <li>{{ signal.tradeType }}</li>
    </ul>
    <p v-html="signal.signalChart">{{ signal.signalChart }}</p>
  </div>
</template>

<script>
import gql from "graphql-tag";

export default {
  name: "Signal",
  data() {
    return {
      signal: null,
    };
  },
  async created() {
    const signal = await this.$apollo.query({
      query: gql`
        query ($slug: String!) {
          signalBySlug(slug: $slug) {
            symbol
            marketOpen
            date
            bias
            tradeType
            signalChart
          }
        }
      `,
      variables: {
        slug: this.$route.params.slug,
      },
    });
    this.signal = signal.data.signalBySlug;
  },
  methods: {
    displayableDate(date) {
      return new Intl.DateTimeFormat("en-US", { dateStyle: "full" }).format(
        new Date(date)
      );
    },
  },
};
</script>

已提出此解决方案here

他们的解决方案的后半部分确实是答案,也是我没有考虑到的。

理论上,您可以使用观察者、ref、DOM api 和 eval() 来执行您想要的操作。不过,更好的方法是获取图表的数据,而不是其 html,并使用 vue 组件安全地构建图表。

<template>
  <div class="signal" v-if="signal">
    <h2>{{ signal.symbol }}: {{ signal.marketOpen }}</h2>
    <div>{{ displayableDate(signal.date) }}</div>
    <ul>
      <li>{{ signal.bias }}</li>
      <li>{{ signal.tradeType }}</li>
    </ul>
    <p ref="chart" v-html="signal.signalChart"></p>
  </div>
</template>

<script>
import gql from "graphql-tag";
import Vue from 'vue';

export default {
  name: "Signal",
  data() {
    return {
      signal: null,
    };
  },
  async created() {
    const signal = await this.$apollo.query({
      query: gql`
        query ($slug: String!) {
          signalBySlug(slug: $slug) {
            symbol
            marketOpen
            date
            bias
            tradeType
            signalChart
          }
        }
      `,
      variables: {
        slug: this.$route.params.slug,
      },
    });
    this.signal = signal.data.signalBySlug;
  },
  methods: {
    displayableDate(date) {
      return new Intl.DateTimeFormat("en-US", { dateStyle: "full" }).format(
        new Date(date)
      );
    },
  },

  watch: {
    'signal.signalChart': {
      async handler() {
        if (this.$refs.chart) {
          await Vue.nextTick();

          [...this.$refs.chart.querySelectorAll('script')].forEach((scriptElement) => {
            if (scriptElement.textContent) {
              eval(scriptElement.textContent);
            }
          })
        }
      }
    }
  }
};
</script>