深入探讨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 相关文章推荐
JavaScript的eval JSON object问题
Nov 15 Javascript
javascript实现简单的可随机变色网页计算器示例
Dec 30 Javascript
JavaScript实现定时页面跳转功能示例
Feb 14 Javascript
浅谈jquery拼接字符串效率比较高的方法
Feb 22 Javascript
jQuery插件zTree实现的多选树效果示例
Mar 08 Javascript
浅谈js-FCC算法Friendly Date Ranges(详解)
Apr 10 Javascript
原生js实现公告滚动效果
Jan 10 Javascript
详解jQuery中的getAll()和cleanData()
Apr 15 jQuery
微信小程序实现搜索指定景点周边美食、酒店
May 18 Javascript
Element-UI中关于table表格的那些骚操作(小结)
Aug 15 Javascript
Vue插件之滑动验证码用法详解
Apr 05 Javascript
ant-design-vue中的select选择器,对输入值的进行筛选操作
Oct 24 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
php下intval()和(int)转换使用与区别
2008/07/18 PHP
单一index.php实现PHP任意层级文件夹遍历(Zjmainstay原创)
2012/07/31 PHP
PHP批量检测并去除文件BOM头代码实例
2014/05/08 PHP
Yii2选项卡的简单使用
2017/05/26 PHP
php生出随机字符串
2017/07/06 PHP
PHP设计模式之单例模式原理与实现方法分析
2018/04/25 PHP
js window对象属性和方法相关资料整理
2015/11/11 Javascript
js判断图片加载完成后获取图片实际宽高的方法
2016/02/25 Javascript
一些实用性较高的js方法
2016/04/19 Javascript
H5移动端图片压缩上传开发流程
2016/11/09 Javascript
vue动态添加路由addRoutes之不能将动态路由存入缓存的解决
2019/02/19 Javascript
vue内置组件keep-alive事件动态缓存实例
2020/10/30 Javascript
vantUI 获得piker选中值的自定义ID操作
2020/11/04 Javascript
Python实现的检测web服务器健康状况的小程序
2014/09/17 Python
详解Python中的多线程编程
2015/04/09 Python
使用Python的判断语句模拟三目运算
2015/04/24 Python
python 如何快速找出两个电子表中数据的差异
2017/05/26 Python
Python使用sklearn库实现的各种分类算法简单应用小结
2019/07/04 Python
基于python的selenium两种文件上传操作实现详解
2019/09/19 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
HTML5 window/iframe跨域传递消息 API介绍
2013/08/26 HTML / CSS
英国豪华文具和皮具配件经典老品牌:Smythson(斯迈森)
2018/04/19 全球购物
苹果音乐订阅:Apple Music
2018/08/02 全球购物
英国最大的在线快递公司之一:ParcelHero
2019/11/04 全球购物
澳大利亚最大的护发和护肤品购物网站:RY
2019/12/26 全球购物
《乡下孩子》教学反思
2014/04/17 职场文书
秦兵马俑导游词
2015/02/02 职场文书
本科毕业论文致谢怎么写
2015/05/14 职场文书
大国崛起日本观后感
2015/06/02 职场文书
家属联谊会致辞
2015/07/31 职场文书
课程设计感想范文
2015/08/11 职场文书
美德少年主要事迹材料
2015/11/04 职场文书
小学六一儿童节活动开幕词
2016/03/04 职场文书
如何制定销售人员薪酬制度?
2019/07/09 职场文书
Redis 彻底禁用RDB持久化操作
2021/07/09 Redis
疑《守望先锋2》A测截图泄露 或将推出新模式、新界面
2022/04/03 其他游戏