问题
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