深入探讨JavaScript、JQuery屏蔽网页鼠标右键菜单及禁止选择复制


Posted in Javascript onJune 10, 2014

我记得在刚开始接触动态HTML及JavaScript时就接触过关于鼠标右键屏蔽的脚本代码,当时这些代码很多会用在防止浏览者未经允许的复制网页上的文字或者其他内容,后来的实际应用证明这种做法是不符合用户体验的,而且破解的方法也有很多,比如我曾经写过一篇文章讲解如何解除网页禁止复制的办法。

由此可见,限制右键及复制是不明智的做法,但是今天我仍然要谈谈关于禁止网页复制、右键菜单的事儿,因为随着网页APP技术的发展,网页应用和桌面应用之间的界限越来越模糊,有一些桌面程序实际上是由网页配合JavaScript实现的,另外一些手机应用也可以是由HTML5+JavaScript实现的,在这种情形下,限制右键就是有必要的了,因为作为APP来说,网页的右键选择文字及弹出菜单在大多数情况下显得没有必要了。

接下来介绍的可能只包含某一方面的代码,但是我相信大家一定能够举一反三:-)

一、粗暴版的限制选择复制或者禁止鼠标右键

我们先谈谈如何粗暴的限制或者禁止浏览者复制网页上的文字,正常的防止浏览者复制文字,我们肯定是想到禁用用户的某些特定的操作,比如鼠标右键,选择,复制等等,而这些操作对应了相应的脚本事件,只要给这些事件加上一个方法,让其返回false就可以“吃”掉这个操作了,一般粗暴的禁止复制的脚本代码如下:

window.onload = function() {
    with(document.body) {
      oncontextmenu=function(){return false}
      ondragstart=function(){return false}
      onselectstart=function(){return false}
      onbeforecopy=function(){return false}
      onselect=function(){document.selection.empty()}
      oncopy=function(){document.selection.empty()}
    }
}

为什么称这个方法为粗暴版的呢?因为使用这个方法禁止鼠标右键后你会发现网页上任何控件都无法右击或者选择了,网页似乎成了死板的图片,也许你会觉得无所谓,但是对于input、textarea文本框这类字符输入控件就有很大的关系了,这些地方不能限制用户的右键及选择复制操作。

二、合理判断要限制的HTML标签元素

如何判断当前处理的层所在的元素标签呢,也就是说得到鼠标当前所在的HTML Tag,这里我们以oncontextmenu为例,其实在document.body.oncontextmenu传入的函数有一个参数我们略去了,完整的写法应该是document.body.oncontextmenu=function(e){}这里的e是JavaScript中的Event事件对象,在IE中可能是通过window.event获取的。通过这个事件对象可以获取触发事件时鼠标所在的HTML Tag,我们可以判断是不是我们要忽略处理元素标签,这里我提供一个函数如下:

var isTagName = function(e, whitelists) {
      e = e || window.event;
      var target = e.target || e.srcElement;
      Array.prototype.contains = function(elem)
        {
           for (var i in this)
           {
               if (this[i].toString().toUpperCase() == elem.toString().toUpperCase()) return true;
           }
           return false;
        }
      if (whitelists && !whitelists.contains(target.tagName)) {
        return false;
      }
      return true;
};

这里的e是事件对象event,target是事件对象所引用的元素对象,当然这里两个变量都采取了兼容IE的写法,具体可以参考《How can I make event.srcElement work in Firefox and what does it mean?》;这里的whitelists是白名单HTML元素标签Tag名,比如['INPUT', 'TEXTAREA'],表示将输入文本框input和textarea加入判断,如果当前事件元素是的话就返回true,这样我们通过下面的代码可以选择性的屏蔽鼠标右键了:

document.body.oncontextmenu=function(e){
     return isTagName(e, ['A', 'TEXTAREA']);
}

三、JQuery版的选择性屏蔽禁止文本选择

同样的对于其他的操作也可以选择性的屏蔽,在JQuery支持的环境中我在StackOverflow找到了这么一篇文章《How to disable text selection using jQuery?》,虽然是讲解的禁止选择的,不过可以借鉴一下,具体代码如下:

(function($){  $.fn.ctrlCmd = function(key) {
    var allowDefault = true;
    if (!$.isArray(key)) {
       key = [key];
    }
    return this.keydown(function(e) {
        for (var i = 0, l = key.length; i < l; i++) {
            if(e.keyCode === key[i].toUpperCase().charCodeAt(0) && e.metaKey) {
                allowDefault = false;
            }
        };
        return allowDefault;
    });
};
 
$.fn.disableSelection = function() {
    this.ctrlCmd(['a', 'c']);
    return this.attr('unselectable', 'on')
               .css({'-moz-user-select':'-moz-none',
                     '-moz-user-select':'none',
                     '-o-user-select':'none',
                     '-khtml-user-select':'none',
                     '-webkit-user-select':'none',
                     '-ms-user-select':'none',
                     'user-select':'none'})
               .bind('selectstart', false);
};
})(jQuery);

在使用上采取下面的代码:
$(':not(input,select,textarea)').disableSelection();

这样就可以除去input、select、textarea外禁止选择了,这段代码的技巧是除了采取selectstart外还给相关元素添加了某些特殊浏览器支持的CSS特性,这样基本可以实现大多数浏览器的兼容,同时这段代码还屏蔽了键盘按键选择Ctrl+A和Ctrl+C,不得不佩服作者周到的考虑。

四、进一步完善:屏蔽鼠标点击操作

我在测试这段代码时遇到一个问题就是点击除input、select、textarea外的元素时会全部选择页面,原文作者给出一个简单的方法就是在使用代码上附加.on('mousedown', false),这样就屏蔽了鼠标的单击,使用代码变成如下:

$(':not(input,select,textarea)').disableSelection().on('mousedown', false);

但是问题又来了,我发现采取上述代码后,input,select,textarea也开始变得不正常起来,看样子屏蔽mousedown的特性应用到所有元素上了。现在转换一下思路,结合刚才我提出的方案,判断event对象来实现选择性屏蔽,我将代码修正如下:
$(':not(input,select,textarea)').disableSelection().on('mousedown', function(e) {
    var event = $.event.fix(e);
    var elem = event.target || e.srcElement;
    if (elem.tagName.toUpperCase() != 'TEXTAREA' && elem.tagName.toUpperCase() != 'INPUT') {
        e.preventDefault();
        return false;
    }
    return true;
});

这样textarea和input就不会限制mousedown了,我们将这段代码抽出为函数:
function jQuery_isTagName(e, whitelists) {
      e = $.event.fix(e);
      var target = e.target || e.srcElement;
      if (whitelists && $.inArray(target.tagName.toString().toUpperCase(), whitelists) == -1) {
        return false;
      }
      return true;
}$(':not(input,select,textarea)').disableSelection().on('mousedown', function(e) {
    if (!jQuery_isTagName(e, ['INPUT', 'TEXTAREA'])) {
        e.preventDefault();
        return false;
    }
    return true;
});

五、JQuery版的选择性屏蔽禁止鼠标右键

对于右键菜单,我们可以这样处理:

$(document).bind("contextmenu",function(e){
    if (!jQuery_isTagName(e, ['INPUT', 'TEXTAREA'])) {
        e.preventDefault();
        return false;
    }
    return true;
});
Javascript 相关文章推荐
jQuery 加上最后自己的验证
Nov 04 Javascript
Js 中debug方式
Feb 07 Javascript
jquery 获取自定义属性(attr和prop)的实现代码
Jun 27 Javascript
JavaScript实现点击自动选择TextArea文本的方法
Jul 02 Javascript
jQuery实现响应鼠标滚动的动感菜单效果
Sep 21 Javascript
Angular 页面跳转时传参问题
Aug 01 Javascript
jQuery实现可编辑表格并生成json结果(实例代码)
Jul 19 jQuery
浅谈webpack 构建性能优化策略小结
Jun 13 Javascript
在vue-cli的组件模板里使用font-awesome的两种方法
Sep 28 Javascript
vue中组件的3种使用方式详解
Mar 23 Javascript
微信小程序实现动态列表项的顺序加载动画
Jul 25 Javascript
在layui中layer弹出层点击事件无效的解决方法
Sep 05 Javascript
js换图片效果可进行定时操作
Jun 09 #Javascript
jQuery如何将选中的对象转化为原始的DOM对象
Jun 09 #Javascript
javascript 处理null及null值示例
Jun 09 #Javascript
网页实时显示服务器时间和javscript自运行时钟
Jun 09 #Javascript
jQuery setTimeout传递字符串参数报错的解决方法
Jun 09 #Javascript
js去除输入框中所有的空格和禁止输入空格的方法
Jun 09 #Javascript
Node.js(安装,启动,测试)
Jun 09 #Javascript
You might like
给ECShop添加最新评论
2015/01/07 PHP
php从给定url获取文件扩展名的方法
2015/03/14 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
Codeigniter控制器controller继承问题实例分析
2016/01/19 PHP
新浪微博字数统计 textarea字数统计实现代码
2011/08/28 Javascript
js判断背景图片是否加载成功使用img的width实现
2013/05/29 Javascript
使用jQuery解决IE与FireFox下createElement方法的差异
2013/11/14 Javascript
jQuery实现“扫码阅读”功能
2015/01/21 Javascript
基于Bootstrap实现下拉菜单项和表单导航条(两个菜单项,一个下拉菜单和登录表单导航条)
2016/07/22 Javascript
jQuery中的insertBefore(),insertAfter(),after(),before()区别介绍
2016/09/01 Javascript
纯js实现html转pdf的简单实例(推荐)
2017/02/16 Javascript
Vue.js常用指令之循环使用v-for指令教程
2017/06/27 Javascript
vue中实现methods一个方法调用另外一个方法
2018/02/08 Javascript
js、jquery实现列表模糊搜索功能过程解析
2020/03/27 jQuery
详解vue中使用transition和animation的实例代码
2020/12/12 Vue.js
[05:28]刀塔密之一:团结则存
2014/07/03 DOTA
[03:51]吞吞映像 每周精彩击杀top10第二弹
2014/06/25 DOTA
Python批量转换文件编码格式
2015/05/17 Python
Python中装饰器兼容加括号和不加括号的写法详解
2017/07/05 Python
python3 flask实现文件上传功能
2020/03/20 Python
python re正则匹配网页中图片url地址的方法
2018/12/20 Python
Python pexpect模块及shell脚本except原理解析
2020/08/03 Python
详解Python openpyxl库的基本应用
2021/02/26 Python
秘鲁购物网站:Linio秘鲁
2017/04/07 全球购物
学前教育毕业生自荐信范文
2013/12/24 职场文书
社会治安综合治理管理责任书
2014/04/16 职场文书
公司委托书怎么写
2014/08/02 职场文书
2014年世界艾滋病日演讲稿
2014/11/28 职场文书
2014年车间主任工作总结
2014/12/10 职场文书
安全保证书怎么写
2015/02/28 职场文书
大学生社会服务心得体会
2016/01/22 职场文书
深度好文:50条没人告诉你的人生经验,句句精辟
2019/08/22 职场文书
Golang 实现超大文件读取的两种方法
2021/04/27 Golang
pytorch model.cuda()花费时间很长的解决
2021/06/01 Python
Android开发 使用文件储存的方式保存QQ密码
2022/04/24 Java/Android
Python实现简单得递归下降Parser
2022/05/02 Python