用 vue.js 在 canvas 上绘图
Drawing onto a canvas with vue.js
我认为这不一定是基于 Vue 的问题,但我 运行 遇到了一些麻烦。
我想向 canvas 写入一个 Vue 变量。如果我删除 vue,我的初始代码可以正常工作,但是如果我添加 Vue,canvas 实际上不会启动。
这是我的代码
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText("Hello World!",10,50);
var v = new Vue({
el: '#app',
data: {
'exampleContent': 'This is TEXT'
},
watch: {
exampleContent: function(val, oldVal) {
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText(this.exampleContent,10,50);
}
}
});
如果我注释掉 /* var v = new Vue({ ...
初始位有效。如果我在观察者中记录 exampleContent
的值,那也可以。但是关于 canvas 的某些东西不起作用。
要玩的演示:
http://codepen.io/EightArmsHQ/pen/EgGbgR?editors=1010
请检查这个 jsFiddle:https://jsfiddle.net/mani04/r4mbh6nu/
编辑: 使用动态文本更新:https://jsfiddle.net/mani04/r4mbh6nu/1/
在上面的示例中,我可以写入 canvas,并确保 input
文本如您所料进入 span
,全部使用 Vue.js
回到你的例子,HTML 是:
<div id="app">
<canvas id="canvas" width="800" height="600"></canvas>
<input type="text" v-model="exampleContent" />
<span>{{ exampleContent }}</span>
</div>
Vue.js 读取 #app
中的元素并将其作为您的 Vue 应用程序 的模板。因此,您的 canvas
、input
和 span
元素现在将由 Vue.js 在构建 DOM.
时重新呈现
在此过程中,您的原始 canvas 文本 - 您在启动 Vue 应用程序之前设置的文本会丢失。
除了在我的 jsFiddle 示例中使用 directive
之外,没有明确的方法可以解决此问题。 Vue 指令可帮助您捕获 DOM 元素。
在我的示例中,我定义了一个名为 insert-message
的 Vue 指令,我在 canvas 上将其用作 v-insert-message
。这允许我捕获 DOM 元素,然后执行其他步骤:getContext
和 fillText
。不需要 id
,或者 getElementById
.
没有 javascript 代码
还有一件事 - 您的 canvas 太大了,因此您无法看到 input
和 span
元素。他们在您的示例中也正常工作!
编辑:指令绑定示例
我刚刚找到了一种使用指令的方法,并且仍然将动态内容写入 canvas。
检查更新后的 jsFiddle:https://jsfiddle.net/mani04/r4mbh6nu/1/
如 中所述,Vue 删除并重新呈现调用 Vue 实例的 DOM 元素。
如果您将 canvas 更新抽象为 Vue 实例 method
,您可以在 mounted
生命周期挂钩处触发它(以获取 exampleContent
的初始值),当 exampleContent
发生变化时,在您的 watch
中重新调用它。
var v = new Vue({
el: '#app',
data: {
'exampleContent': 'This is TEXT'
},
methods: {
updateCanvas: function (){
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText(this.exampleContent,10,50);
}
},
watch: {
exampleContent: function(val, oldVal) {
this.updateCanvas();
}
},
mounted: function (){
this.updateCanvas();
}
});
canvas{
background:red;
width:800px;
height:600px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script>
<div id="app">
<canvas id="canvas" width="800" height="600"></canvas>
<input type="text" v-model="exampleContent" />
<span>{{ exampleContent }}</span>
</div>
前面的 SO 代码片段是从 OP 的分叉版本创建的 CodePen
这里有一个使用 Vuejs 2 的简单方法:
将 canvas 添加到具有引用属性的模板:
ref="myCanvas"
然后您可以使用
在组件内的任何位置访问它
var canvas = this.$refs.myCanvas
这个问题已经被看过几次了,自从我第一次问这个问题以来,我已经使用 canvases 和 Vue 数千次了。这是我在实践中找到的最佳选择。
给canvas一个ref
,有几个人提到过:
<div id="app">
<canvas width="800" height="600" ref="nameOfCanvas"></canvas>
</div>
在挂载函数中设置canvas的context
:
mounted(){
this.canvas = this.$refs.nameOfCanvas;
this.ctx = this.canvas.getContext("2d");
this.render();
}
不需要把ctx放在data
对象里,除非你想看
就是这样。从那里,可以创建一个 render
方法并在您的组件中引用数据...
render(){
this.ctx.clearRect(0,0,this.canvas.width, this.canvas.height);
this.ctx.fillRect(0, 0, 20, 20);
}
您还可以在此方法中设置一个 requestAnimationFrame
循环,如下所示:
render(){
this.ctx.clearRect(0,0,this.canvas.width, this.canvas.height);
this.ctx.fillRect(0, 0, 20, 20);
requestAnimationFrame(this.render);
}
我认为这不一定是基于 Vue 的问题,但我 运行 遇到了一些麻烦。
我想向 canvas 写入一个 Vue 变量。如果我删除 vue,我的初始代码可以正常工作,但是如果我添加 Vue,canvas 实际上不会启动。
这是我的代码
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText("Hello World!",10,50);
var v = new Vue({
el: '#app',
data: {
'exampleContent': 'This is TEXT'
},
watch: {
exampleContent: function(val, oldVal) {
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText(this.exampleContent,10,50);
}
}
});
如果我注释掉 /* var v = new Vue({ ...
初始位有效。如果我在观察者中记录 exampleContent
的值,那也可以。但是关于 canvas 的某些东西不起作用。
要玩的演示: http://codepen.io/EightArmsHQ/pen/EgGbgR?editors=1010
请检查这个 jsFiddle:https://jsfiddle.net/mani04/r4mbh6nu/
编辑: 使用动态文本更新:https://jsfiddle.net/mani04/r4mbh6nu/1/
在上面的示例中,我可以写入 canvas,并确保 input
文本如您所料进入 span
,全部使用 Vue.js
回到你的例子,HTML 是:
<div id="app">
<canvas id="canvas" width="800" height="600"></canvas>
<input type="text" v-model="exampleContent" />
<span>{{ exampleContent }}</span>
</div>
Vue.js 读取 #app
中的元素并将其作为您的 Vue 应用程序 的模板。因此,您的 canvas
、input
和 span
元素现在将由 Vue.js 在构建 DOM.
在此过程中,您的原始 canvas 文本 - 您在启动 Vue 应用程序之前设置的文本会丢失。
除了在我的 jsFiddle 示例中使用 directive
之外,没有明确的方法可以解决此问题。 Vue 指令可帮助您捕获 DOM 元素。
在我的示例中,我定义了一个名为 insert-message
的 Vue 指令,我在 canvas 上将其用作 v-insert-message
。这允许我捕获 DOM 元素,然后执行其他步骤:getContext
和 fillText
。不需要 id
,或者 getElementById
.
还有一件事 - 您的 canvas 太大了,因此您无法看到 input
和 span
元素。他们在您的示例中也正常工作!
编辑:指令绑定示例
我刚刚找到了一种使用指令的方法,并且仍然将动态内容写入 canvas。
检查更新后的 jsFiddle:https://jsfiddle.net/mani04/r4mbh6nu/1/
如
如果您将 canvas 更新抽象为 Vue 实例 method
,您可以在 mounted
生命周期挂钩处触发它(以获取 exampleContent
的初始值),当 exampleContent
发生变化时,在您的 watch
中重新调用它。
var v = new Vue({
el: '#app',
data: {
'exampleContent': 'This is TEXT'
},
methods: {
updateCanvas: function (){
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "black";
ctx.font="20px Georgia";
ctx.fillText(this.exampleContent,10,50);
}
},
watch: {
exampleContent: function(val, oldVal) {
this.updateCanvas();
}
},
mounted: function (){
this.updateCanvas();
}
});
canvas{
background:red;
width:800px;
height:600px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.1/vue.min.js"></script>
<div id="app">
<canvas id="canvas" width="800" height="600"></canvas>
<input type="text" v-model="exampleContent" />
<span>{{ exampleContent }}</span>
</div>
前面的 SO 代码片段是从 OP 的分叉版本创建的 CodePen
这里有一个使用 Vuejs 2 的简单方法:
将 canvas 添加到具有引用属性的模板:
ref="myCanvas"
然后您可以使用
在组件内的任何位置访问它var canvas = this.$refs.myCanvas
这个问题已经被看过几次了,自从我第一次问这个问题以来,我已经使用 canvases 和 Vue 数千次了。这是我在实践中找到的最佳选择。
给canvas一个ref
,有几个人提到过:
<div id="app">
<canvas width="800" height="600" ref="nameOfCanvas"></canvas>
</div>
在挂载函数中设置canvas的context
:
mounted(){
this.canvas = this.$refs.nameOfCanvas;
this.ctx = this.canvas.getContext("2d");
this.render();
}
不需要把ctx放在data
对象里,除非你想看
就是这样。从那里,可以创建一个 render
方法并在您的组件中引用数据...
render(){
this.ctx.clearRect(0,0,this.canvas.width, this.canvas.height);
this.ctx.fillRect(0, 0, 20, 20);
}
您还可以在此方法中设置一个 requestAnimationFrame
循环,如下所示:
render(){
this.ctx.clearRect(0,0,this.canvas.width, this.canvas.height);
this.ctx.fillRect(0, 0, 20, 20);
requestAnimationFrame(this.render);
}