我是Vue.js的新手,我学习了一些基本技能。现在,我正在尝试解决实际问题。
我正在尝试使用Vue.js绘制一些甜甜圈。在没有Vue的情况下,我可以轻松实现它,但是在我尝试使用Vue.js时,这使我感到困惑。
/*
canvas: HTMLCanvas node
ratio: number range: [0, 1]
*/
function pie (canvas, ratio) {
function arc (ctx, color, radius, radian) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, radius, 0, radian);
ctx.closePath();
ctx.fill();
}
var width = canvas.clientWidth,
height = canvas.clientHeight,
outRadius = Math.ceil(width / 2 - 10),
innerRadius = Math.ceil(outRadius * 0.8);
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
ctx.translate(width / 2, height / 2);
ctx.rotate(-Math.PI / 2);
arc(ctx, "steelblue", outRadius, Math.PI * 2);
arc(ctx, "yellow", outRadius + 5, Math.PI * 2 * ratio);
arc(ctx, "white", innerRadius, Math.PI * 2);
ctx.restore();
}
Vue.component("pie", {
props: ["pies"],
methods: {
draw: pie
},
template: `
<ul class="pie">
<li v-for="pie in pies">
<div class="pie__content">
<h3 class="pie__header">{{pie.ratio}}</h3>
<canvas v-on:click="draw($event.target, pie.ratio)" width="200" height="200"></canvas>
</div>
<h3 class="pie__name">{{pie.name}}</h3>
</li>
</ul>
`
});
var vm = new Vue({
el: "#app",
data: {
pies: [
{ratio: 0.45, name: "CPU"},
{ratio: 0.75, name: "Memory"},
{ratio: 0.15, name: "Drive"},
]
}
});
canvas { border: 1px solid gray; }
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<pie v-bind:pies="pies"></pie>
</div>
首先,我不知道如何初始化这些画布。在上面运行这些代码,除非用户单击它们,否则它们将是空白的。绝对不是我想要的,但是看来 event 是使它起作用的唯一方法;
其次,如果我更改了比率,例如:vm.pies[0].ratio = 0.78
,
相关画布没有响应。
任何评论将不胜感激!
答案 0 :(得分:0)
我想念的是Vue Instance Lifecycle。 Vue实例提供一个mounted
属性,该属性将在呈现组件之后运行。
canvas
元素提供一个ref
属性,以便在以后的操作中易于引用。mounted
属性函数,该函数将在呈现组件后运行。这可能是初始化函数。computed
getter函数formatRatio
,该函数将重绘画布(如果可用)并最终以百分比格式返回格式化的ratio
字符串。这部分将使饼图对绑定数据具有反应性。代码如下:
function pie (canvas, ratio) {
function arc (ctx, color, radius, radian) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, radius, 0, radian);
ctx.closePath();
ctx.fill();
}
var width = canvas.clientWidth,
height = canvas.clientHeight,
outRadius = Math.ceil(width / 2 - 10),
innerRadius = Math.ceil(outRadius * 0.8);
var ctx = canvas.getContext("2d");
ctx.save();
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
ctx.translate(width / 2, height / 2);
ctx.rotate(-Math.PI / 2);
arc(ctx, "steelblue", outRadius, Math.PI * 2);
arc(ctx, "yellow", outRadius + 5, Math.PI * 2 * ratio);
arc(ctx, "white", innerRadius, Math.PI * 2);
ctx.restore();
}
Vue.component("pie-canvas", {
props: ["pie"],
computed: {
formatRatio: function () {
// when component is rendered canvas element will be avaible
if (this.$refs.canvas) {
pie(this.$refs.canvas, this.pie.ratio);
}
return Math.round(this.pie.ratio * 1000) / 10 + "%";
}
},
mounted: function () {
pie(this.$refs.canvas, this.pie.ratio);
},
template: `
<div class="pie__content">
<h3 class="pie__header">{{ formatRatio }}</h3>
<canvas ref="canvas" width="200" height="200"></canvas>
</div>
`
});
var vm = new Vue({
el: "#app",
data: {
pies: [
{ratio: 0.45, name: "CPU"},
{ratio: 0.75, name: "Memory"},
{ratio: 0.15, name: "Drive"},
]
}
});
canvas { border: 1px solid gray; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="pie">
<li v-for="pie in pies">
<pie-canvas v-bind:pie="pie"></pie-canvas>
<h3 class="pie__name">{{pie.name}}</h3>
</li>
</ul>
</div>