快速用JavaScript实现划词取词,可复制百度文库文字(获取鼠标选中区域文字)

完整代码可在最后代码块查看呦!!!
※本贴代码,可用用于油猴脚本,支持浏览器F12Console控制台直接运行
有一段时间呢在百度文库查询资料时被限制了复制,说什么复制次数已达上限,那个
难受鸭!!于是我打开了传说中的F12,意外的发现了一个功能
在这里插入图片描述
就是很意外的发现我所选中的文字会在我的Console视图中显示于是我去看了一下他是那个JS段中打印出来的
在这里插入图片描述
97行Emmmm,好像和百度文库没有什么关系,地址好像是我浏览器的插件,然后我将这个插件装入了其他浏览器,发现会报错,应该是兼容问题,之前也想过获取鼠标选中的文字,一直也没有找到代码意思明确的文章,于是趁此时机
在这里插入图片描述
首先分析一下划词取词的过程

  1. 用户左击鼠标             → 鼠标按下事件onmousedown
  2. 鼠标滑过文字             → 文字本身样式改变
  3. 转中后抬起鼠标左键  → 鼠标抬起事件onmouseup,同时返回那些文字有变化

那么首先进行简单的代码主体:

 document.onmousedown = function(event) {//监听当前页面鼠标按下事件
	var event = event || window.event;//此处考虑兼容问题
	if (event.button == "0" || event.button == "1") {//判断按下的按键(0)
	   document.onmouseup = function(event) {//监听页面中鼠标抬起事件
	      var txt = "";
	      if(window.getSelection){//兼容性判断,各浏览器获取有变化处的文字函数不同
	         txt = window.getSelection();//谷歌等内核浏览器获取方式
	      }else{
	         txt = document.selection.createRange().text;//IE普通内核
	      }
	      console.log(txt);//控制台打印浏览
	   }  
   }
}

可以在页面中添加P标签随便写一些文字,或者放入任意网页console控制台均可,然后鼠标随便选中文字,观察控制台会出现如下内容

在这里插入图片描述

恭喜你成功第一步了,那出现了这个当初说好的文字呢???OK其实这个就是文字只是它以一种不同的方式展现了出来,那我们如何得到呢

		txt = txt+"";

将变量txt经过这步处理会变为字符串的形式了,这个时候就可以在控制台看到你所选中的文字了,你以为这就完了???不完善一下舒服嘛???冲鸭!!!
继续分析,如果用户点一个按钮,或者选中的是空格怎么办

 	txt = txt.replace(/^\s+|\s+$/g, "");
    if (txt != "") {
        console.log(txt);
    }

OK,首先一个正则判断,将两端空格去除(带着前面一堆空格获取到的字符串很带劲,试试?滑稽.jpg),之后判断如果为空就不获取,普绕飞科特

划词部分到此结束
接下来需要在选中文字后追加一个div方便用户复制百度文库文字,那么我们可以将其封成一个方法,只要将上面那一步获取到的字符串传入即可

function creatDiv(str) {
    var arr = mousePosition();//这是个获取鼠标当前位置的一个方法
    var newDiv = document.createElement('div'); //创建一个div元素;
    var newContent = document.createTextNode(str);//创建文本内容
    newDiv.appendChild(newContent);//将内容放入新创建的div
    newDiv.id = "bblock";//添加一个ID方便之后的操作
    //可以用下操作设置自己想要的CSS属性
    newDiv.style.width = "200px";//设置div宽(视自己需求而定)
    newDiv.style.background = "red";//设置背景颜色
    newDiv.style.zIndex = "1000";//设置层级保证在最上方
    newDiv.style.position = "absolute";//给div添加绝对定位*必有
    //此处要加px否则不生效,+20原因  根据自己需要调整
    newDiv.style.left = arr[0] + 20 + "px";//距左侧距离
    newDiv.style.top = arr[1] + 0 + "px";//具右侧距离
    var bo = document.body; //获取body对象.
    bo.insertBefore(newDiv, bo.lastChild); //动态插入到body中
}
function mousePosition(evt) { //当前鼠标位于页面位置
	evt = evt || window.event;//兼容性判断,满足一个即可有值
	//兼容写法,获取当前鼠标横坐标
    var xPos = evt.pageX || evt.clientX || evt.offsetX || evt.x;
    //兼容写法,获取当前鼠标纵坐标
    var yPos = evt.pageY || evt.clientY || evt.offsetY || evt.y;
    return [xPos, yPos];//返回数组为当前鼠标横纵坐标
}

你以为这就完了,OK 调GUG阶段
分析:

  1. 用户每次划词后都要生成一个新的,那么旧的怎么关闭?
  2. 如果用户在生成的div中进行划词操作,是否也要生成新的div?
  3. 如果才能判断什么情况下要进行销毁旧的div呢?

解决:

  1. 最好的关闭体验为:单击其他不是新追加的div区域进行关闭
  2. 否,新div的目的就是让用户可以在这里进行选中复制的,要加判断
  3. 根据第一条,得到销毁条件

由此可以得到我们还需要两个判断(判断div关闭,判断div中划词),和一个方法(鼠标是否离开div)

设置两个全局变量

var workType = false; //用户当前是否进行了划词
var workTool = false; //用户划词后是否正在取词

根据之前给的ID监听鼠标是否离开窗口,如果在则设置workTool为ture

function bingDiv() {
    document.getElementById("bblock").onmouseover = function() {
        workTool = true;
    }//鼠标移入事件
    document.getElementById("bblock").onmouseout = function() {
        workTool = false;
    }//鼠标移除事件
}

在划词开始添加判断

 if (workTool) { //如果用户在取词则不进行二次划词操作
	return 0;
 }
 //如果div存在且不是在取词操作 根据ID销毁该div
 if (document.getElementById("bblock") && !workTool) {
     document.body.removeChild(document.getElementById("bblock"));
 }
 //如果在不是取词操作代码会执行到这里,那么将划词工作状态设为true
 workType = true;

添加判断只有在划词操作下,鼠标抬起才会进行获取文字,追加div的操作,而此时鼠标抬起后,划词工作状态结束

 document.onmouseup = function(event) {
     if (workType) {//是划词状态才进行如下操作
         workType = false;//划词状态结束
         var txt = "";
	     if(window.getSelection){
	        txt = window.getSelection();
	     }else{
	        txt = document.selection.createRange().text;
	     }
        txt = txt + "";
        txt = txt.replace(/^\s+|\s+$/g, "");
        if (txt != "") {
            creatDiv(txt);//传入生成div的函数
        }
    }
}

这里有一个坑,为什么要把判断鼠标是否在新追加的div中封成一个方法呢?
这个大多数新手会遇到的问题,因为网页是动态渲染的,如果你直接写到划词的方法中进行判断,js是获取不到这个节点的,所以需要在每次创建节点后再去判断,防止获取不到

 function creatDiv(str) {
    var arr = mousePosition();
   		   	  ·
  			  ·
  			  ·
     bo.insertBefore(newDiv, bo.lastChild); //动态插入到body中
     bingDiv();//追加完毕后进行判断
 }

到这里效果就完全实现了

以下为全部完整代码(可直接打开需要的百度文库,粘贴到console控制台即可使用):

let workType = false; //当前划词状态
let workTool = false; //当前取词状态
document.onmousedown = function(event) {             
  var event = event || window.event;
  if ((event.button == "0" || event.button == "1") && !workTool) {
    if (workTool) { //如果用户在取词则不进行二次划词操作
        return 0;
    }
    if (document.getElementById("bblock") && !workTool) {
        document.body.removeChild(document.getElementById("bblock"));
    }
    workType = true;
    document.onmouseup = function(event) {
      if (workType) {
        workType = false;
        var txt = window.getSelection ? window.getSelection() : document.selection.createRange().text;
        txt = txt + "";
        txt = txt.replace(/^\s+|\s+$/g, "");
        if (txt != "") {
           creatDiv(txt);
        }
      }
    }
  }
}

function mousePosition(evt) { //当前鼠标位于页面位置
    evt = evt || window.event;
    var xPos = evt.pageX || evt.clientX || evt.offsetX || evt.x;
    var yPos = evt.pageY || evt.clientY || evt.offsetY || evt.y;
    return [xPos, yPos];
}

function creatDiv(str) {
    var arr = mousePosition();
    var newDiv = document.createElement('div'); //创建一个div元素;
    var newContent = document.createTextNode(str);
    newDiv.appendChild(newContent);
    newDiv.id = "bblock";
    newDiv.style.width = "200px";
    newDiv.style.background = "red";
    newDiv.style.position = "absolute";
    newDiv.style.left = arr[0] + 20 + "px";
    newDiv.style.top = arr[1]+ 0  + "px";
    newDiv.style.zIndex = "1000";
    var bo = document.body; //获取body对象
    bo.insertBefore(newDiv, bo.lastChild); //动态插入到body中
    bingDiv();
}

function bingDiv() {
    document.getElementById("bblock").onmouseover = function() {
        workTool = true;
    }
    document.getElementById("bblock").onmouseout = function() {
        workTool = false;
    }
}

效果:
在这里插入图片描述

取词区域的样式可以根据自己需求更改,我就懒一下啦~~~

猜你喜欢

转载自blog.csdn.net/flaystar/article/details/84142024