Overriding a component method

删除回忆录丶 提交于 2021-01-27 05:38:32

问题


I'm using VueCharts which is a Google Charts plugin for vue.

I'm trying to give the newer Material Design looks to the charts. I've tried passing "google.charts.Bar" to chart-type prop and it did work. However, many of the options are ignored because, as stated in the Google Charts docs, the options object needs to be converted by using google.charts.Bar.convertOptions(options), something the plugin doesn't do.

Looking at the source, the plugin installs a 'vue-chart' component. This component uses ChartWrapper to handle loading the chart libraries, like so:

methods: {
    buildWrapper (chartType, dataTable, options, containerId) {
      let wrapper = new google.visualization.ChartWrapper({
        chartType: chartType,
        dataTable: dataTable,
        options: options,
        containerId: containerId
      })

      return wrapper
    },

So all I need is to override this method to convert the options before passing them to the ChartWrapper.

But how? I haven't found a way to simply override a component method in vue docs. I could create a new component and pass the converted options down, but I need access to the google object, which is only loaded internally by the plugin.

I have also read I could use mixins, but it's not clear how. This doesn't work:

Vue.component('MyCustomChart', {
    mixins: ['vue-chart'],
    methods: {
        buildWrapper (chartType, dataTable, options, containerId) {
            let wrapper = new google.visualization.ChartWrapper({
                chartType: chartType,
                dataTable: dataTable,
                options: google.charts.Bar.convertOptions(options), // that's all I need
                containerId: containerId
            })

            return wrapper
        },
    }
})

[Vue warn]: Failed to mount component: template or render function not defined. (found in MyCustomChart)


回答1:


You can use Vue's extend method to customize plugin components.

In your case:

import VueCharts from 'vue-charts'  
Vue.use(VueCharts);

const Base = Vue.options.components["vue-chart"];
const CustomChart = Base.extend({
  methods: {
    buildWrapper (chartType, dataTable, options, containerId) {
      let wrapper = new google.visualization.ChartWrapper({
        chartType: chartType,
        dataTable: dataTable,
        options: google.charts.Bar.coverOptions(options),
        containerId: containerId
      })

      return wrapper
    },
  })
}

Vue.component('MyCustomChart', CustomChart);

(credit to Bert Evans for noting that you need to reference the base component from Vue.options.components before extending to customize)




回答2:


I played around with this a bit and I misled @thanksd above with my recommendation on what to extend. One way that works is this:

import VueChart from "vue-charts";

Vue.use(VueChart);

const BaseChart = Vue.options.components["vue-chart"];
const CustomChart = BaseChart.extend({
  methods:{
    buildWrapper (chartType, dataTable, options, containerId) {
      let wrapper = new google.visualization.ChartWrapper({
        chartType: chartType,
        dataTable: dataTable,
        options: google.charts.Bar.convertOptions(options),
        containerId: containerId
      })

      return wrapper
    }
  }
});

Vue.component("custom-chart", CustomChart);

Further Explanation

As I thought, extending VueChart either through Vue's native extend, or through lodash, will not achieve the expected results. The result of importing VueChart is a plugin definition. Both lodash and Vue will happily accept that as an object to extend, but neither will result in a Vue component. Trying to use the result of either will result in the error mentioned in the question, "template or render function not defined". That error is absolutely true; extending VueChart extends an install function with a single method.

So how do you get the object to extend? vue-charts doesn't expose it. The install just calls Vue.component('vue-chart', Chart).

Fortunately, Vue makes the globally installed components through Vue.options.components. By extending Vue.options.components["vue-chart"] we get a proper Vue component definition.

Finally, I was surprised google was not available to @RegularEverydayNormalGuy. It has to be available; vue-chart uses it. But he's right, it's not available immediately. vue-chart loads the script asynchronously. Again, the plugin unfortunately doesn't make it available to you in any way, it just initializes itself after it's asynchronously loaded. There are ways to work around that, but at that point you should just probably submit a pull request.

Original Answer

options is a property on vue-chart. Why not just pass in the converted options?

new Vue({
    data:{
        convertedOptions: google.charts.Bar.convertOptions({<my options>})
    }
})

And in the template

<vue-chart :options="convertedOptions"></vue-chart>


来源:https://stackoverflow.com/questions/43116647/overriding-a-component-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!