熟悉vue-electron项目
创建一个vue使用electron桌面应用:
-
首先使用vue-cli创建一个vue的项目,创建命令:
vue create vue-electron:选择自我配置:
选择项目中要使用到的技术点:
选择vue的版本(2.0):
是否选择history模式作为路由模式(否):
选择css预处理器:
如babel、ESlint等插件是否要独立创建一个文件(是):
是否要将此保存为未来项目的预设(否):
等待安装完成:
-
进入vue-electron为vue项目安装electron插件:
安装命令:
vue add electron-builder:选择electron版本:
使用
cd vue-electron命令 进入 vue-electron使用npm run electron:serve / yarn electron:serve启动项目: -
启动项目的时候会很慢,出现这个问题的主要原因是项目在下载
electron-devtools-installer这个插件,但是又由于这个插件是国外的,国内访问非常慢,有可能还会有下载失败的情况出现下载失败:
解决办法:我们打开项目中的background.js文件,找到
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'这一行,将它注释掉,这样每次启动项目的时候,就不会在下载这个插件了,也就避免了这个问题:运行效果:
项目一:拖拽、平移、缩放、截选等
项目需求:使用svg.js初始化一个svg画布,给画布初始化一个图片;在页面上渲染四个按钮,分别是:绘制,拖拽、删除、所、绘制十字线。默认情况下,可以在鼠标按下时拖拽图片移动,鼠标滑轮滚动时可以实现图片的缩放;当选择绘制时候,停止图片的平移、缩放功能,可以绘制一个矩形,用来选择一个某个局部细节,当绘制完成时,恢复图片的平移、缩放功能;当按下拖拽按钮时,可以将绘制的所有的矩形选中,进行拖拽放大缩小;当按下删除按钮时,可以将选中的矩形删除掉;当按下绘制十字线按钮时,在鼠标点击的时候绘制一个十字线。
-
首先我们将vue项目中的不用的vue组件删掉,如HelloWorld.vue和AboutView.vue组件,在
views/HomeView.vue组件中,进行项目开发:-
安装svg.js插件,安装命令:
npm install @svgdotjs/svg.js / yarn add @svgdotjs/svg.js: -
初始化一个svg画布,给svg初始化一个图片,实现图片的缩放平移:
在script中通过
import { SVG } from '@svgdotjs/svg.js'引入 svg.js;在template模板中定义一个存放svg元素的父元素:
<template> <div class="home"> <!-- 存放svg的父元素 --> <div class="svgMain"></div> </div> </template>在script中的data中初始化一个svg,在methods中定义初始化svg的方法initSvg(), 并在mounted()调用:
<script> import { SVG } from '@svgdotjs/svg.js' export default { name: 'HomeView', data() { return { svg: SVG() } }, methods: { // 初始化SVG initSvg () { this.svg.addTo('.svgMain').size("100%", "100%"); } }, mounted() { this.initSvg() } } </script>此时我们可以在控制台看到我们插件的svg元素:
初始化图片:在methods中定义initImg()方法用来初始化图片,并在initSvg方法中调用:
<script> import { SVG } from '@svgdotjs/svg.js' export default { name: 'HomeView', data() { return { svg: SVG(), //定义一个svg方法 imgMsg: { //用来存放图片的宽高 w: 0, h: 0 } } }, methods: { // 初始化SVG initSvg () { this.svg.addTo('.svgMain').size("100%", "100%"); this.initImg() }, // 初始化图片 initImg() { this.svg.image(require("@/assets/xibao.jpg"), (e) => { this.imgMsg.w = e.target.naturalWidth; //获取图片宽度 this.imgMsg.h = e.target.naturalHeight; //获取图片高度 // 初始化viewbox,它的起点时(0, 0),宽高和图片的快高一样 this.svg.viewbox(0, 0, this.imgMsg.w, this.imgMsg.h) }) } }, mounted() { this.initSvg() } } </script>此时我们再启动项目,会看见我们初始化的图片,而且图片是因窗口而自适应大小的:
-
实现让鼠标控制svg元素平移、缩放:在methods方法中,定义svgConfig方法,并在initImg方法中调用:
因为控制svg元素平移缩放,需要使用 panzoom.js ,通过
npm install @svgdotjs/svg.js @svgdotjs/svg.panzoom.js进行安装:安装完成之后,我们在script中引入svg.panzoom.js:
import '@svgdotjs/svg.panzoom.js'此时,我们使用svg.panzoom方法,控制svg元素的缩放平移:
initImg() { this.svg.image(require("@/assets/xibao.jpg"), (e) => { this.imgMsg.w = e.target.naturalWidth; //获取图片宽度 this.imgMsg.h = e.target.naturalHeight; //获取图片高度 // 初始化viewbox,它的起点时(0, 0),宽高和图片的快高一样 this.svg.viewbox(0, 0, this.imgMsg.w, this.imgMsg.h) // 调用svgConfig方法,让svg原始可以缩放平移 this.svgConfig(true) }) }, // 让鼠标控制svg元素平移缩放 svgConfig(flag) { this.svg.panZoom({ zoomMin: 0.2, //最小缩放级别 zoomMax: 20, //最大缩放级别 zoomFactor: 0.15, // 鼠标滚轮放大缩小倍数 wheelZoom: flag //启用滚轮缩放 }) } -
我们绘制四个控制按钮,这里使用的element-ui的按钮,可以自己书写:
<template> <div class="home"> <!-- 定义四个按钮,用来控制svg操作 --> <div class="control-btn"> <div @click="drawARectangle($event)">绘制矩形</div> <div @click="dragTheRectangle($event)">拖拽矩形</div> <div @click="removeTheRectangle($event)">删除矩形</div> <div @click="drawACross($event)">绘制十字</div> </div> <!-- 存放svg的父元素 --> <div class="svgMain"></div> </div> </template>
-
-
绘制矩形:点击绘制矩形之后,取消svg因素的平移和缩放。用户可以在图片上绘制矩形。绘制矩形需要导入svg.draw.js。
-
导入svg.draw.js:
import "@/js/svg.draw.js"; -
在点击后,取消svg因素的平移和缩放,在鼠标按下时候,开始绘制:
// 绘制矩形 drawARectangle() { // 取消svg元素的平移和缩放 this.svgConfig(false); // 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { this.rect = this.svg .rect() //绘制矩形 .attr({ // 设置矩形的属性 fill: "transparent", // 绘制背景色 stroke: "red", // 绘制边框颜色 "stroke-width": 3, // 绘制边框宽度 }); this.rect.draw(e); // 开始绘制 }); }, -
鼠标抬起的时候,停止绘制,恢复svg元素的缩放平移:
// 绘制矩形 drawARectangle() { // 取消svg元素的平移和缩放 this.svgConfig(false); // 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { this.rect = this.svg .rect() //绘制矩形 .attr({ // 设置矩形的属性 fill: "transparent", // 绘制背景色 stroke: "red", // 绘制边框颜色 "stroke-width": 3, // 绘制边框宽度 }); this.rect.draw(e); // 开始绘制 }); // 鼠标抬起时,矩形绘制完成,恢复svg元素的平移和缩放 this.svg.on("mouseup", (e) => { // 使矩形完成绘制 this.rect.draw(e); // 恢复svg元素的平移和缩放 this.svgConfig(true); }); },问题1:当我们单击按钮以后,按钮被选中,但是此时我们又不想绘制矩形,我们会再次单击按钮,会发现此时按钮的选中效果并没有失效,并且还可以继续进行绘制矩形。解决办法,每次单击之后,都进行一次判断,判断按钮是否被选中,如果选中,我们就移除选中事件;如果没有选中,我们就添加选中事件。这里我们是用jQuery的hasClass方法,判断此时按钮是否处于选中状态。
安装jQuery命令:
npm install jquery;在
HomeView.vue组件的script中导入jQuery:// 绘制矩形 drawARectangle(e) { // 获取单击按钮 let el = $(e.target); if (!el.hasClass("current")) { // 如果没有选中,我们添加选中事件 el.addClass("current"); ···· // 鼠标抬起时,矩形绘制完成,恢复svg元素的平移和缩放 this.svg.on("mouseup", (e) => { // 使矩形完成绘制 this.rect.draw(e); // 移除选中样式 el.removeClass('current') // 恢复svg元素的平移和缩放 this.svgConfig(true); }); } else { // 如果被选中,我们移除选中事件 el.removeClass("current"); this.svgConfig(true); } },问题2:我们每次都有鼠标按下和抬起事件,都有绑定,却没有解绑,这就可能会导致,绘制完成后,我们在拖拽图片的时候,又进行一次绘制。解决版本,我们可以声明一个方法initOnOff,用来解绑这些事件:
// 绘制矩形 drawARectangle(e) { // 在每次操作前,进行初始化,解绑之前可能没有解绑的事件 this.initOnOff() // 获取单击按钮 let el = $(e.target); if (!el.hasClass("current")) { // 如果没有选中,我们添加选中事件 el.addClass("current"); // 取消svg元素的平移和缩放 this.svgConfig(false); // 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { this.rect = this.svg .rect() //绘制矩形 .attr({ // 设置矩形的属性 fill: "transparent", // 绘制背景色 stroke: "red", // 绘制边框颜色 "stroke-width": 3, // 绘制边框宽度 }); this.rect.draw(e); // 开始绘制 }); // 鼠标抬起时,矩形绘制完成,恢复svg元素的平移和缩放 this.svg.on("mouseup", (e) => { // 使矩形完成绘制 this.rect.draw(e); // 解绑mousedown和mouseup事件 this.initOnOff() // 恢复svg元素的平移和缩放 this.svgConfig(true); }); } else { // 调用initOnOff方法,移除选中事件 this.initOnOff() // 恢复平移缩放 this.svgConfig(true); } }, // 解绑操作 initOnOff() { // 解绑mousedown和mouseup方法 this.svg.off('mousedown') this.svg.off('mouseup') $(".control-btn>div").removeClass("current"); //移除所有按钮的选中事件 },问题3:当我们鼠标移除视口/屏幕外时,会失去对dom的监听,示例:
解决办法:
将鼠标抬起事件修改为:
// 当我们鼠标移除视口/屏幕外时,会失去对dom的监听 document.addEventListener("mouseup", this.stopDraw, true); // 绘制完成 stopDraw(e) { // 使矩形完成绘制 this.rect.draw(e); // 解绑mousedown和mouseup事件 this.initOnOff(); // 恢复svg元素的平移和缩放 this.svgConfig(true); }, -
优化绘制矩形过程1(超出图片裁剪回来):
我们应该让用户在截选细节时,矩形框不应该超出图片。但是此时我们可以在图片外面绘制,这显然是不正确的,错误示范:
解决办法:
右下角:根据下图分析可知,我们需要获取 实际画框的W就是用图片的宽度-画框的宽;实际画框的H就是图片的高度-画框的y;
// 将用户画的超出图片位置裁剪掉 rectCalculation(e) { // 右下角操作 // 我们需要获取 实际画框的W就是用图片的宽度-画框的宽;实际画框的H就是图片的高度-画框的y; let x = e.attr("x"); // 用户画的画框的起始点横坐标 let y = e.attr("y"); // 用户画的画框的起始点纵坐标 let rightX = x + e.attr("width"); // 用户画的画框的终点横坐标 let rightY = y + e.attr("height"); // 用户画的画框的终点纵坐标 // 设置画框的宽高 if(rightX > this.imgMsg.w) { e.attr('width', this.imgMsg.w - x) } if (rightY > this.imgMsg.h) { e.attr('height', this.imgMsg.h - y) } // 左上角操作 },左上角:根据下图分析可知,我们要获取画框的实际W就是用画框的宽-画框的横坐标的绝对值,获取画框实际的高就是用画框的高-画框的纵坐标的绝对值。
// 将用户画的超出图片位置裁剪掉 rectCalculation(e) { // 右下角操作 ···· // 左上角操作 if (x < 0) { e.attr("width", e.attr("width") - Math.abs(x)); } if (y < 0) { e.attr("height", e.attr("height") - Math.abs(y)); } },坑:如果我们直接设置如向上设置画框的宽高的话,我们就会出现:画框的宽高裁剪为我们想要的宽高,但是它依然没有在指定位置上,是因为我们画框的起始坐标在上面,所以此时,我们将画框的起始坐标设置为(0,0)就可以解决这个问题。
// 左上角操作 if (x < 0) { e.attr({x: 0,"width": e.attr("width") - Math.abs(x)}); } if (y < 0) { e.attr({y:0, "height": e.attr("height") - Math.abs(y)}); }-
优化绘制矩形过程1(不能让用户画矩形时,超出图片):
// 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { ··· // 判断用户在绘制矩形的过程中,如果超出图片,则进行限制 this.rect.on("drawupdate", () => { this.rectCalculation(this.rect); }); }); -
优化绘制矩形过程1(当用户在图片外开始绘制时,取消绘制):
// 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { ··· // 当用户在图片外开始绘制时,取消绘制 if ( this.rect.attr("x") < 0 || this.rect.attr("y") < 0 || this.rect.attr("x") > this.imgMsg.w || this.rect.attr("y") > this.imgMsg.h ) { this.rect.remove(); } }); -
绘制完成,可以重新启动项目,查看运行效果:
-
-
拖拽矩形: 点击拖拽矩形按钮后,可以将绘制的矩形框进行拖拽、放大缩小。但拖拽范围不能超出图片。
-
当用户点击拖拽矩形按钮后,进行判断,当前是否处于选中状态,如果处于选中状态,则取消选中事件,恢复svg元素可以平移和缩放功能;如果处于非选中状态,则添加选中事件,取消svg元素的平移和缩放功能,给绘制的所有矩形添加选中事件。当用户选中某个矩形后,可以对矩形进行拖拽放大放小。
为了获取绘制的矩形,我们可以在绘制矩形()的时候,添加一个class为lable的属性。
// 鼠标按下时,开始绘制,鼠标抬起时候,结束绘制 this.svg.on("mousedown", (e) => { this.rect = this.svg .rect() //绘制矩形 .attr({ // 设置矩形的属性 fill: "transparent", // 绘制背景色 stroke: "red", // 绘制边框颜色 "stroke-width": 3, // 绘制边框宽度 }).addClass('lable'); this.rect.draw(e); // 开始绘制 // 判断用户在绘制矩形的过程中,如果超出图片,则进行限制 ··· // 当用户在图片外开始绘制时,取消绘制 ··· });
-