浏览器页面功能限制与反限制的斗争

开博两年多,只自己重新以高优先级的样式弄了博客的展示界面(兼容IE6···),之后没有任何博文产出,因为后来才开始知道有响应式布局这个东西,想弄完再写(哈哈哈哈,我是屁事特多的类型),也有点不好意思了。这篇文章基本上是对网上已有的文章做了下整理而已,写的也是大家用的主流方法,所以也没啥新内容,也没有多少技术水平,是本人用以当作技术类文章的Helloworld的练笔测试。好啦,开撸,小弟语文不好,有错误请帮忙订正一下(*@ο@*) 哇~

大伙在看网页时,或多或少都会遇到一些禁止右键、选择、复制、黏贴之类的网站,或者在写一些要限制用户操作的页面时应该也有实现过类似的需求。

首先说说可以实现对应禁止功能的,可以达到目的的事件咯。So Easy~ 

  1. 禁止右键菜单方法只有一个: 'contextmenu'
  2. 禁止选择 'selectstart','select'
  3. 禁止拖动 'dragstart', 
  4. 禁止复制 有这种 'beforecopy', 'copy' ,'selectstart','select','keydown','mouseup'(不然你选择不让你玩鼠标和键盘也是个思路对不?)
  5. 哈哈哈哈,俺只是个打杂的,不是什么专业的前端开发工程师,估计还会有遗漏,就先留个来凑凑数哈···

简单,这种需求网上一搜到处都是,网上实现的最简单方法无非也就是在body标签里面,禁止掉对应的事件。

如禁止右键菜单:

<body oncontextmenu="return false">    
</body>

所谓你省心大家也省心,破解方法也是So Easy:对body,玩个事件一次过解绑就好了。

(function () {
    ['contextmenu', 'dragstart', 'mouseup', 'copy', 'beforecopy', 'selectstart', 'select', 'keydown']
        .forEach(function (evt) {
            document.body['on'+evt]=null;
        });
})();

当然,有些会用事件绑定,这里只讨论一些常规的方案哈。但jQuery这东东,实在是太好用了,不给大家讲shenmegui的基础知识,就是告诉大家,bind绑定的都可以用unbind解绑。不要问我为啥不说$.fn.on什么的,on出现的版本太后了,我还真看过现在还有 1.3.2的jq。

思路还是同上,不过,用jquery的网站大部分绑定在 document那里。这次以禁止右键和禁止选择为栗子

(function () {
$(document).on('contextmenu selectstart', function () {
return false;
});
})();

附上解决方法的话:

(function ($) {
    ['contextmenu', 'dragstart', 'mouseup', 'copy', 'beforecopy', 'selectstart', 'select', 'keydown']
        .forEach(function (evt) {
            $(document).unbind(evt);
        });
})(jQuery);

哈哈哈,像我这么写这两段代码太恶劣了,太偷懒了,然后就可以合体出兼容性更好的方案

(function ($) {
    ['contextmenu', 'dragstart', 'mouseup', 'copy', 'beforecopy', 'selectstart', 'select', 'keydown']
        .forEach(function (evt) {
            document.body['on' + evt] = null;
            if ($)
                $(document).unbind(evt);
        });
})(window.jQuery);

当然,绑定的话,不一定是绑定在body或者document元素。可能是绑在某个div那里,就不恶意卖萌加段代码了。这个时候,我们就要对整个页面元素 document.all 都解绑一次,然后你会发现漏掉了 window 和document 这两个也是可以绑定的,所以必须补上。

灯灯灯灯,大家久等的代码:

(function (window) {
    var eventArr = ['contextmenu', 'dragstart', 'mouseup', 'copy', 'beforecopy', 'selectstart', 'select', 'keydown'];

    function runScript(window) {
        var document = window["document"],
            $ = window["jQuery"],
            unbind = function (ele) {
                eventArr.forEach(function (evt) {
                    ele['on' + evt] = null;
                    if ($) {
                        $(ele).unbind(evt);
                    }
                });
            };
        [window, document].forEach(unbind);
        for (var i = 0, all = document.all, len = all.length; i < len; i++) {
            var ele = all[i];
            if (ele && ele.nodeType === 1) {
                unbind(ele);
            }
        }
    }
    runScript(window);
})(window);

另外,跑到这里的时候,你会发现在路由器管理页面的右键禁止你是无法解决。 因为用了frameset 和iframe。 所以,在遍历元素的时候,要对frame和iframe 进行操作。同时要反防止跨域的js权限问题,导致后面的元素没跑,也把try catch加上。

 1 (function (window) {
 2     var eventArr = ['contextmenu', 'dragstart', 'mouseup', 'copy', 'beforecopy', 'selectstart', 'select', 'keydown'];
 3 
 4     function runScript(window) {
 5         var document = window["document"],
 6             $ = window["jQuery"],
 7             unbind = function (ele) {
 8                 eventArr.forEach(function (evt) {
 9                     ele['on' + evt] = null;
10                     if ($) {
11                         $(ele).unbind(evt);
12                     }
13                     try {
14                         if (/frame/i.test(ele.tagName)) {
15                             runScript(ele.contentWindow);
16                         }
17                     } catch (err) {
18                     }
19                 });
20             };
21         [window, document].forEach(unbind);
22         for (var i = 0, all = document.all, len = all.length; i < len; i++) {
23             var ele = all[i];
24             if (ele && ele.nodeType === 1) {
25                 unbind(ele);
26             }
27         }
28     }
29 
30     runScript(window);
31 })(window);

然后,有史以来兼容性最强的解决页面功能被禁用的方案终于出炉了。

利用谷歌那啥 js压缩编译器来着,压一下的话共398个字符(唉,我数得可辛苦了/(ㄒoㄒ)/~~)···对应是书签代码也出来了。把这个加到书签里面有事点一点···

javascript:(function(c){function e(a){var b=a.document,f=a.jQuery,g=function(a){h.forEach(function(b){a["on"+b]=null;f&&f(a).unbind(b);try{/frame/i.test(a.tagName)&&e(a.contentWindow)}catch(c){}})};[a,b].forEach(g);a=0;for(var b=b.all,c=b.length;a<c;a++){var d=b[a];d&&1===d.nodeType&&g(d)}}var h="contextmenu dragstart mouseup copy beforecopy selectstart select keydown".split(" ");e(c)})(window);

  所以说,禁止页面功能不能用简单方法来实现。如果让我写的话,至少也会实现成这样,看你丫的怎么解绑我原生匿名函数···

(function (window) {
    function bindEvent(elem, event, handler, useCapture) {
        event = event.replace(/^on/ig, "").toLowerCase();
        if (elem.addEventListener) {
            elem.addEventListener(event, handler, useCapture);
            return true;
        }
        else if (elem.attachEvent) {
            return elem.attachEvent('on' + event, handler);
        }
        elem['on' + event] = handler;
    }


    ['contextmenu', 'dragstart', 'beforecopy', 'copy', 'cut', 'paste', 'selectstart', 'select']
        .forEach(function (evt) {

            bindEvent(window, evt, function () {
                cancBub(evt);

                return prtDtV(evt);

                function cancBub(evt) {
                    var e = window.event || evt;
                    e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true
                }

                function prtDtV(evt) {
                    var e = window.event || evt;
                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
                    return false;
                }
            })
        });

})(window);

最后,我看了他这代码一眼,默默选择在那个页面关掉了浏览器的javascript功能···

 

-------------------------------

以下内容于 2021年11月13日 添加

一般来说,做到前面的已经解决掉大部分问题了。但如果 自己考虑 别人也会用代码 来解除掉页面的事件绑定。 所以 还得加上 防止 别人 跑 禁止的代码。最简单的吧办法就是不断地保证自己的禁用代码要一直重复绑定。使用 setTimeout/setInterval 例如:

 

function CopyrightProtect() {
   xxx.onclick=function(evt){
    evt.preventDefault();
   return false;
  }
  ...
})
setInterval(CopyrightProtect,500);

 

然后禁止别人选择的时候也可以使用 样式 user-select 来控制: 

1 .none-userselect{
2   -webkit-touch-callout: none;
3   -webkit-user-select: none;
4   -khtml-user-select: none;
5   -moz-user-select: none;
6   -ms-user-select: none;
7   user-select: none;
8 }

 

 所以做禁止别人禁止选择时需要对这部分样式也进行重写,对于任意的样式来说,就是重写这部分:  

if (ele.style) {
    if (ele.style.setProperty) {
        ele.style.setProperty("user-select", "unset", "important")
    } else {
        ele.style.userSelect = "unset"
    }
}

 

所以最终的 超级脚本是:

(function (window) {
    var eventArr = ["contextmenu", "dragstart", "mouseup", "copy", "beforecopy", "selectstart", "select", "keydown"];
    function runScript(window) {

        try {
            var toItem = window.setTimeout(function () {
                do { window.clearTimeout(toItem) } while (toItem--)
            }, 0) + 1;
            var inItem = window.clearInterval(function () {
                do { window.clearInterval(inItem) } while (inItem--)
            }, 0) + 1;
        } catch (error) {
        }
        
        var document = window["document"], $ = window["jQuery"], unbind = function (ele) {
            eventArr.forEach(function (evt) {

                ele["on" + evt] = null; if ($) { $(ele).unbind(evt) }

                if (ele.style) {
                    if (ele.style.setProperty) {
                        ele.style.setProperty("user-select", "unset", "important")
                    } else {
                        ele.style.userSelect = "unset"
                    }
                }
                try {
                    if (/frame/i.test(ele.tagName)) { runScript(ele.contentWindow) }
                } catch (err) { }
            })
        };

        document.querySelectorAll("video").forEach(function (x) {
            x.remove()
        });

        [window, document].forEach(unbind);

        for (var i = 0, all = document.all, len = all.length; i < len; i++) {
            var ele = all[i];
            if (ele && ele.nodeType === 1) {
                unbind(ele)
            }
        }
    }

    runScript(window)

})(window);

 

最终结果:

javascript:(function(n){function f(b){try{var g=b.setTimeout(function(){do b.clearTimeout(g);while(g--)},0)+1,h=b.clearInterval(function(){do b.clearInterval(h);while(h--)},0)+1}catch(a){}var c=b.document,k=b.jQuery,m=function(a){p.forEach(function(l){a["on"+l]=null;k&&k(a).unbind(l);a.style&&(a.style.setProperty?a.style.setProperty("user-select","unset","important"):a.style.userSelect="unset");try{/frame/i.test(a.tagName)&&f(a.contentWindow)}catch(r){}})};c.querySelectorAll("video").forEach(function(a){a.remove()});
[b,c].forEach(m);var d=0;c=c.all;for(var q=c.length;d<q;d++){var e=c[d];e&&1===e.nodeType&&m(e)}}var p="contextmenu dragstart mouseup copy beforecopy selectstart select keydown".split(" ");f(n)})(window);

 

posted @ 2015-04-25 05:04  Nieg  阅读(488)  评论(0编辑  收藏  举报