引言
常用的鼠标事件
首先咱们还是先回顾一下鼠标的常用事件:
- click(点击)
- dblclick(双击)
- mouseover(鼠标移入)
- mouseout(鼠标移出)
- mouseenter(鼠标移入)
- mouseleave(鼠标移出)
- mouseup(鼠标抬起)
- mousedown(鼠标按下)
- mousemove(鼠标移动)
以上就是咱们常用的鼠标事件,我们发现其中的mouseover
和mouseenter
还有mouseout
和mouseleave
好像是一样的事件,但凭我们的经验虽然看似一样,其实肯定不一样,或者说有区别。
那么他们有什么区别呢?
mouseover
和mouseenter
都是鼠标移入时触发,但区别是mouseover
支持事件冒泡,而mouseenter
不支持事件冒泡。简单说就是 mouseover
事件在鼠标指针移入被选元素或者是被选元素的任何子元素,都会触发,而mouseenter
事件只有在鼠标指针移入被选元素时,才会触发,移入被选元素的子元素不会触发。
mouseout
和mouseleave
都是鼠标移入时触发,但区别是mouseout
支持事件冒泡,而mouseleave
不支持事件冒泡。简单说就是 mouseout
事件在鼠标指针离开被选元素或者是被选元素的任何子元素,都会触发,而mouseleave
事件只有在鼠标指针离开被选元素时,才会触发,离开被选元素的子元素不会触发。
键盘事件
- keydown(键盘按下)
- keyup(键盘抬起)
- keypress(紧接着
keydown
事件触发(只有按下字符键时触发))
如果用户按下了一个字符键不放,就会重复触发keydown
和keypress
事件,直到用户松开该键为止,如果用户按下了一个非字符键不放,就会重复触发keydown
事件
keypress
事件返回的是输入的字符的ASCII码(which属性),而keydown
事件返回的是键盘码(keyCode属性)。
ps:keypress
支持的系统功能键 :
**Firefox
**:Esc、Enter、Backspace、Pause Break、Insert、 Delete、Home、End、Page Up、Page Down、F1 through F12、The Arrow Keys
、上下左右键
Chrome / Oprea / Safari
:Enter
**IE
**:Esc、Entery
除了 Firefox
,其他chrome、oprea、safari、IE
上下左右键不会触发keypress
事件的添加和移除
给Canvas中的元素添加事件我们用的是:addEventListener()
方法,移除事件用的是removeEventListener()
方法
参数值
event 必须。字符串,指定事件名。
注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。
function 必须。指定要事件触发时执行的函数。
当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。
useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。
首先看一下添加鼠标事件
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
canvas.addEventListener("mousemove", mouseMoving, false); function mouseMoving(e) { console.log(`当前鼠标在Canvas中的位置: x: ${e.clientX} y: ${e.clientY}`); }
|
Canvas支持所有的鼠标事件,但是并不支持键盘事件,那么想要让Canvas支持键盘事件我们就需要自己处理,这边有两种方法可以实现键盘事件。
方法一:让Canvas自动获取焦点,从而支持键盘事件。
<body> <canvas id="canvas" width="550" height="500" tabindex="0"//使其可聚焦 style="box-shadow: 0px 0px 5px #ccc; border-radius: 8px;"> 当前浏览器不支持canvas元素,请升级或更换浏览器! </canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); canvas.addEventListener("keydown", doKeydown, false); canvas.focus(); function doKeydown(e) { switch(e.keyCode) { case 37: console.log(`按下左键`) break; case 38: console.log(`按下上键`) break; case 39: console.log(`按下右键`) break; case 40: console.log(`按下下键`) break; } } </script> </body>
|
需要注意,当鼠标点击别的元素的时候,canvas
元素会失去焦点,从而失去键盘事件
方法二:通过为windows
对象添加键盘事件,从而控制canvas
元素(更常用)
<body> <canvas id="canvas" width="500" height="500" tabindex="0" style="box-shadow: 0px 0px 5px #ccc; border-radius: 8px;"> 当前浏览器不支持canvas元素,请升级或更换浏览器! </canvas> <script> const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); ctx.fillStyle="orange"; let x = canvas.width / 2 - 50; let y = canvas.height / 2 - 50;
ctx.fillRect(x, y, 100, 50); window.addEventListener("keydown", doKeydown, false); function doKeydown(e) { ctx.clearRect(0, 0, 500, 500) let keyID = e.keyCode ? e.keyCode :e.which; switch(keyID) { case 37: console.log(`按下左键`) x = x - 10; ctx.fillRect(x, y, 100, 50); break; case 38: console.log(`按下上键`) y = y - 10; ctx.fillRect(x, y, 100, 50); break; case 39: console.log(`按下右键`) x = x + 10; ctx.fillRect(x, y, 100, 50); break; case 40: console.log(`按下下键`) y = y + 10; ctx.fillRect(x, y, 100, 50); break; } } </script> </body>
|
内部元素添加事件
上面的所有事件其实都是添加到canvas
元素上的,但往往在平常的需求中我们需要针对canvas
元素内部的子元素做单独的事件交互,那么我们就需要考虑如何给canvas
元素的内部元素添加事件。
canvas
元素本身并没有提供给内部元素添加事件的Api,所以我们直接使用原生的方式和canvas
元素的内部元素进行交互
这里就以拖拽为例,假如canvas
元素内部有多个子元素,那么想拖拽其中一个子元素,我们首先得知道,在鼠标按下的时候是否按在canvas
元素的子元素上,只有按在canvas
元素的子元素上我们才能对它进行拖拽。
1.准备工作
<script> const canvas = document.getElementById('canvas'); const width = canvas.width; const height = canvas.height; const ctx = canvas.getContext('2d'); const images = [ { name: "白月魁", url: "../images/bailaoban.jpg" }, { name: "鸣人", url: "../images/mingren.jpg", }, { name: "路飞", url: "../images/lufei.jpg", }, { name: "哪吒", url: "../images/nazha.jpg", }, { name: "千寻", url: "../images/qianxun.jpg", }, ]; images.forEach((item)=>{ const image = new Image() image.src = item.url; const name = item.name; image.onload = () => { const w = 200; const h = 200 / image.width * image.height; const x = Math.random() * (width - w) ; const y = Math.random() * (height - h); const imageObj = { image, name, x, y, w, h } draw(imageObj) } })
function draw(imageObj) { ctx.drawImage(imageObj.image, imageObj.x, imageObj.y, imageObj.w, imageObj.h); } </script>
|
2.添加事件
canvas.addEventListener("mousedown", mousedownFn, false)
function mousedownFn(e) { canvas.addEventListener("mousemove", mousemoveFn, false) canvas.addEventListener("mouseup", mouseupFn, false) }
function mousemoveFn() {}
function mouseupFn() {}
|
3.判断选中元素
定义完事件以后,我们就需要判断每次点击的元素是其中的哪一个,这样我们才能针对这个元素做交互。
通过计算,如上面布局的代码,每个图片绘制的x、y、width和height我们都是知道的,那么当我们每次点击下去的时候就可以遍历图片的数据,看我们是否点击到元素上。
const canvas = document.getElementById('canvas'); const width = canvas.width; const height = canvas.height; const ctx = canvas.getContext('2d'); const images = [ { name: "白月魁", url: "../images/bailaoban.jpg" }, { name: "鸣人", url: "../images/mingren.jpg", }, { name: "路飞", url: "../images/lufei.jpg", }, { name: "哪吒", url: "../images/nazha.jpg", }, { name: "千寻", url: "../images/qianxun.jpg", }, ];
let imagesData = [] let clickCoordinate = { x: 0, y: 0 } let target;
images.forEach((item)=>{ const image = new Image() image.src = item.url; const name = item.name; image.onload = () => { const w = 200; const h = 200 / image.width * image.height; const x = Math.random() * (width - w) ; const y = Math.random() * (height - h); const imageObj = { image, name, x, y, w, h } imagesData.push(imageObj) draw(imageObj) } })
function draw(imageObj) { ctx.drawImage(imageObj.image, imageObj.x, imageObj.y, imageObj.w, imageObj.h); }
canvas.addEventListener("mousedown", mousedownFn, false) function mousedownFn(e) { clickCoordinate.x = e.pageX - canvas.offsetLeft; clickCoordinate.y = e.pageY - canvas.offsetTop; checkElement() canvas.addEventListener("mousemove", mousemoveFn, false) canvas.addEventListener("mouseup", mouseupFn, false) } function mousemoveFn() {}
function mouseupFn() {}
function checkElement() { imagesData.forEach((item, index)=>{ const minX = item.x const maxX = item.x + item.w const minY = item.y const maxY = item.y + item.h if(minX <= clickCoordinate.x && clickCoordinate.x <= maxX && minY <= clickCoordinate.y && clickCoordinate.y <= maxY) { target = index console.log("点击的元素是:", item.name) } }) }
|
4.移动
知道选中的元素以后,我们就需要在移动的时候把移动的坐标赋值给选中的元素,让选中的元素跟着鼠标移动。
function mousemoveFn(e) { const moveX = e.pageX const moveY = e.pageY console.log(moveX,moveY) imagesData[target].x = imagesData[target].x + ( moveX - clickCoordinate.x ); imagesData[target].y = imagesData[target].y + ( moveY - clickCoordinate.y ); ctx.clearRect(0, 0, width, height); imagesData.forEach((i) => draw(i)) clickCoordinate.x = moveX; clickCoordinate.y = moveY; }
function mouseupFn() { canvas.removeEventListener("mousemove", mousemoveFn, false) canvas.removeEventListener("mouseup", mouseupFn, false) target = undefined }
|