最近项目中用到Vue Konva框架,遇到一些问题基本搜不到,网上的文章基本都是些入门教程什么的。所以本文整理了使用过程中遇到的问题以及解决办法,希望你用到的时候有所帮助。
基本是按照我在开发中使用的顺序来写的,使用方法和错误处理没有做单独区分。如有需要可以搜索关键字。
我们的项目没有做动画的要求,所以本文也没有提及动画相关的。
2018.8.25
需求:类似美图秀秀网页版的拼图工具。但是美图秀秀用的是 Flash,我们用 canvas,所以能参考的也就只有效果了。
领导给选的是konva.js
Konva.js 一个基于 Canvas 开发的 2d JavaScript框架库, 它可以轻松的实现桌面应用和移动应用中的图形交互交互效果
我们的项目用了Vue,这个框架也有一个Vue版本的。
国际惯例,先撸文档:
Canvas
Konva官方文档(中文)
Konva API文档(英文)
Demo(英文)
Vue Konva(英文)
Vue Konva Issues(英文)
英文API还是挺全的,Vue的文档和文章比较少,主要还是对照英文的API。做这个需求的时候体会到程序员的英语水平真的很重要,因为后面有一些问题去issues提问的时候都是先中文组织好语言再用谷歌翻译下(///▽///)
下面来说说遇到的问题吧(都是在vue框架中)
- 渲染图片
-
用
<v-image/>
标签,它的image属性值是一个image对象 -
渲染的图片不需要改变
script: data () { return { // image对象 imageObj: new Image() } }, computed: { stageImage () { this.imageObj.src = this.stage.url this.imageObj.width = this.stage.width this.imageObj.height = this.stage.height return { image: this.imageObj } } } template: <v-image ref="image" :config="{ image: stageImage }"/>
-
渲染的图片是可变的
// 创建 image 对象 newImage (url) { let img = new Image() img.src = url return img }
-
报错:渲染的图片不是image对象,会报下面的错
- 旋转(例如给
<v-image/>
添加rotation属性)
-
默认旋转是围绕图片左上角(0, 0)位置的
-
如果想围绕图片中心旋转需要配置如下属性
<v-image ref="image" :config="{ x: 200, y: 150, offset: { // 让旋转点的位置从左上角移到图片中心,此时的图片坐标x,y以中心点位置计算 x: 200, y: 150, }, width: 400, height: 300, rotation: 90, image: stageImage }"/>
- 裁剪
-
正三角形
<v-group ref="group" :config="{ clipFunc: function(ctx) { // 正三角形 150是边长 ctx.beginPath(); ctx.moveTo(75, 0) ctx.lineTo(0, Math.sqrt(Math.pow(150, 2) - Math.pow(75, 2))) ctx.lineTo(150, Math.sqrt(Math.pow(150, 2) - Math.pow(75, 2))) ctx.closePath() } }"> <v-image ref="image" :config="{ image: stageImage }"/> </v-group>
-
心形
<v-group ref="group" :config="{ clipFunc: function(ctx) { // 心形 ctx.beginPath() // 起始点 ctx.moveTo(75, 40) // 左半边 ctx.bezierCurveTo(75, 37, 70, 25, 50, 25) ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5) ctx.bezierCurveTo(20, 80, 40, 102, 75, 120) // 右半边 ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5) ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25) ctx.bezierCurveTo(85, 25, 75, 37, 75, 40) //闭合路径 ctx.closePath() } }"> <v-image ref="image" :config="{ image: stageImage }"/> </v-group>
-
阻止冒泡
这个issues上有,直接贴了 -
鼠标滚轮事件
也是issues上的 -
获取鼠标位置(我是在拖拽的时候用)
// dragstart 获取鼠标位置 dragStart () { let posX = this.$refs.stage.getStage().getPointerPosition().x let posY = this.$refs.stage.getStage().getPointerPosition().y }
-
this.$refs.stage.getStage() 可以查看vue konva中舞台对象的方法,文档中没有的可以去里面找找,在_proto_属性里
-
序列化舞台,konva.js可以,vue konva没有toJSON()方法
-
生成 dataurl
this.$refs.stage.getStage().toDataURL()
-
生成 img 标签
this.$refs.stage.getStage().toImage({ callback: function(img) { console.log(img) } })
-
warning:
Konva warning: Unable to get data URL. Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
error:Uncaught (in promise) TypeError: Cannot read property '1' of null
- 开发的时候自测没有报这个错误,发到线上之后自测依然正常,但是有的同事电脑会报这个错。
- 刚开始排查的时候没有留意上面的警告,其实警告内容正是报错的原因“Konva警告:无法获取数据URL。 无法在’HTMLCanvasElement’上执行’toDataURL’:可能无法导出受污染的画布。“
这是因为stage渲染的图片跨域了,污染了画布。什么是“被污染”的 canvas? - 按照网上的方法给图片添加了
image.setAttribute('crossorigin', 'anonymous')
还是不行。 - 我们的图片是单独在一台服务器上,而且本地环境测试环境正式环境的都不同,图片量很多,所以没办法放到静态文件夹中。最后的解决办法是做了转发,在图片渲染之前匹配线上存储图片的服务器域名,替换为当前域名
document.domain
。 - 需要注意的是,在stage的配置中不管有没有渲染的图片都必须不能跨域,而且所有url必须都是有效的,否则一样会报错。
- 但是为什么我自测的时候没有这个问题呢,这是因为我的谷歌浏览器是命令起的,是开发者模式,所以不会报这个错。