鞋在前面:Java中的Selection和Range对象,对于没有开发过文本编辑器或者没有接触过文本选择项目的同学,熟悉而陌生,熟悉是大致知道是干嘛的,陌生就是从来没用过,具体查手册也不是很明白。本文以有道词典chrome翻译插件的屏幕拾词为例,来详细讲解一下这两个对象的具体使用
什么是屏幕拾词?就是按住ctrl键,鼠标移动到对应单词上,有道词典chrome插件就会获取到这个单词并帮你翻译
至于为什么会用到有道词典chrome翻译插件[下文中都简称有道插件]?那当然是为了方便查阅www.w3.org ( https://www.w3.org/)上面的文档啦...,当老板过来找你的时候发现你在看英文文档,你懂的??…
不知道插件怎么用?看这里: https://chrome.google.com/webstore/detail/%E6%9C%89%E9%81%93%E8%AF%8D%E5%85%B8chrome%E5%88%92%E8%AF%8D%E6%8F%92%E4%BB%B6/eopjamdnofihpioajgfdikhhbobonhbb?hl=zh-CN。自带梯子,GFW,这个大家也都懂的…
chrome浏览器安装好有道翻译插件的效果图如下
上图中大家会看到有道插件的工作方式有2种,本文着重介绍第二种方式的实现思路,也就是按住Ctrl键自动拾取英文单词进行翻译
划词翻译
指此即译模式(按下Ctrl键指词)
再上一张有道插件的屏幕拾词翻译效果图:
正式开始前,先了解下有道插件的工作原理和步骤
获取到目标单词
将单词文本通过ajax请求发送给有道服务器获取翻译结果
将翻译结果展示到页面上
这么一来,划词翻译就很好理解了。按住鼠标左键拖动选中目标单词,发起ajax请求服务器获得翻译结果,将翻译结果展示到页面上
大家可能会问了,鼠标拖动选中的部分是怎么被java获取的?这就得聊聊今天的两位主角Selection对象和Range对象了
正文
简单来说:按住鼠标左键拖动选择目标区域后,浏览器会自动创建一个选区,也就是Selection对象,这个选区里连续的文本区域就是一个Range对象,直接上代码
那么这两个对象是有了,可是跟获取选中的文本貌似没有太大关系?还是上代码
就是这样简单,只需要三行js代码就可以获取到用户选中的目标文本,so easy…
OK,可以抬头看黑板了,现在开始说重点:有道插件是如何做到按住ctrl键来自动拾取页面中的英文单词的?一步一步,follow me…
第一步:监听鼠标移动事件,获取鼠标当前悬停的坐标
上代码
监听mousemove事件,可以通过event.ctrlKey来判断ctrl键是否被按下了,event.clientX和event.clientY可以获取当前鼠标对应的坐标,到目前为止,准备工作就绪
第二步:获取鼠标所在坐标的英文单词
回想一下有道插件翻译的效果图,按住ctrl键,鼠标移动到某个单词上方的时候,这个单词底部变成了选中的蓝色,就像是有人拖动鼠标选中了一样?
没错,实现逻辑就是:当鼠标移动到任意位置的时候,获取到当前鼠标坐标,然后查找该坐标附近的唯一英文单词,找到该单词后,创建选区(Selection)以及拖蓝(Range),就出现了单词被选中的效果,然后再通过Range.toString()获取目标单词
这里有个新概念-拖蓝:Selection对象所对应的是用户所选择的 ranges (区域),俗称拖蓝
另外,细心的同学会问,到底是如何查找的呢?接下来就是… 先介绍几个基本概念,欲速则不达,先弄明白一些基本问题,比如说
如何根据一个坐标来创建一块拖蓝?有哪些方法可以创建拖蓝?
创建拖蓝(也就是Range对象),有以下4种方法
var range = document.createRange() 通过document对象的createRange()方法创建空的Range对象
var selection = document.getSelection();var range = selection.getRangeAt(0)
通过Selection对象的getRangeAt()方法获取Range对象
var range = document.caretRangeAtPoint()
通过document对象的caretRangeAtPoint(x,y)来创建Range对象
var range = new Range() 通过构造函数创建Range对象
这几种方法有什么异同?请继续滚动鼠标…
方法1,document.createRange(),直接上代码
效果图如下
这里有几个重要概念Range.setStart(node, offset),Range.setEnd(node, offset)。Range对象的这两个函数分别可以调整Range对象文本的起始位置和结束位置。
创建好了Range对象并设置了起始位置和结束位置之后,浏览器里面并不会出现选中效果[拖蓝],那是因为该Range对象只存在于Java脚本里,并没有在浏览器页面里长出来,那怎么让这个Range对象成长为拖蓝呢?就是下面三行代码干的好事
创建选区Selection对象s,并把创建的Range对象oRange添加到Selection对象s,大功告成,拖蓝长出来了。
细心的朋友又会问了,那Selection对象和Range对象到底是什么关系呢?
简单来说:Selection对象称为选区,它可以包含多个Range对象,也就是同一时刻,浏览器只能有一个选区(Selection),而该选区可以包含多个拖蓝区域(Range)
经测试,firefox按住ctrl键的时候,可以手动选择多个拖蓝[脚本相同],chrome目前是禁用了ctrl选择多个拖蓝的功能,IE 也不支持,如下是firefox的效果截图
如果尝试用java脚本在chrome下创建多个range则会报错如下截图[直译就是:不连续的selection是不被支持的]:
方法2:var selection = document.getSelection();var range = selection.getRangeAt(0)
document.getSelection()获取到选区对象selection,并使用Selection对象的getRangeAt()方法获取Range对象。这个方法也同时说明了Selection对象和Range对象的关系
方法3:没错,它就是本文要用到的核心方法之一,通过坐标创建Range对象 var r = document.caretRangeFromPoint(event.clientX, event.clientY);,那这个Range对象如何和它周围的文本节点关联呢?答案就是下面的4个属性
Range.startContainer:Range对象起始位置所在节点
Range.startContainer.data:Range对象起始位置所在节点的文本字符串
Range.endContainer:Range对象结束位置所在节点
Range.endContainer.data:Range对象结束位置所在节点的文本字符串
通过坐标创建的Range对象起始位置和结束位置是相同的,循环往前移动起始位置,直到遇到非英文字符停止;循环往后移动结束位置,直到遇到非英文字符停止(通过Range.setStart()和Range.setEnd()来移动起始/结束位置),最终创建的Range对象就会拾取到目标单词
方法4 构造函数创建Range对象类似方法1 var range = new Range();
如何创建Selection对象,有哪几种方法?
获取Selection对象有2种方法,其作用是等同的
var selection = window.getSelection()
var selection = document.getSelection()
OK,讲完了基本知识,直接上代码
下面源码为精简后的核心代码,不能直接运行,完整demo已放github上( https://github.com/yukap6/demo/blob/master/youdaoDictDemo/demo.html)
效果图如下
后记
测试代码的时候,有一个坑就是mousemove或者mouseup事件执行如上代码都是OK的,但是mousedown事件则不会产生拖蓝(选中效果)。这个是因为鼠标按下事件发生时,通过脚本创建了拖蓝,但是会紧接着执行mouseup事件,这个时候,浏览器会自动创建新的选区,从而清除掉已经创建好的拖蓝区域
这里讲的api都是标准api,IE8-等浏览器有自己特殊的类似api
有道插件展示翻译结果的时候,涉及到元素定位,这个可以单独开一篇文章来讲了,这里不再赘述
chrome插件开发其实很简单,就是根据chrome官方规则,把html,js,css文件打包成.crx文件后,上传到chrome商店,就变成了插件,所以作为前端同学,开发chrome插件是很容易的,如何开发一个chrome插件 ( https://developer.chrome.com/extensions)
chrome浏览器如下两行代码的执行结果是一致的,这个也很好理解,因为chrome限制了一个Selection对象只能对应一个Range对象
console.log(Selection.toString());
console.log(Range.toString());
修改拖蓝的颜色样式,示例代码如下
另外,有道chrome官方插件有2个小小的不足
鼠标移动较快的时候,偶尔会出现鼠标在单词A上,但是展示的翻译结果是单词B的
浏览器页面在缩放状态,翻译结果展示的时候,定位会不准确。[发现这个是因为笔者经常会将英文站点放大看,会比较清晰舒服]
经过笔者的修改,已经解决了这2个问题。针对问题1,使用函数节流来解决;针对问题2,监听页面缩放状态,对缩放状态的页面定位换不同的方式,具体可以看修改后的源码 ( https://github.com/yukap6/youdaodictforchrome)
2、本站永久网址:https://www.yuanmacun.com
3、本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行删除处理。
4、本站一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
5、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
6、本站资源大多存储在云盘,如发现链接失效,请联系我们我们会第一时间更新。
源码村资源网 » 包含html按钮设置鼠标事件监听事件的词条
1 评论