简体   繁体   English

防止用户在移动浏览器上复制文本

[英]Prevent user from copying text on mobile browsers

I'm trying to develop a typing speed competition using JavaScript.我正在尝试使用 JavaScript 开发打字速度竞赛。 People should write all the words they see from a div to a textarea.人们应该将他们从 div 看到的所有单词写到 textarea 中。

To prevent cheating (like copying the words from div) one way is check the written words only when a keyboard key is down, but I was wondering if there is a way to prevent the user from copying the text in a browser?为了防止作弊(如从 div 复制单词),一种方法是仅在按下键盘键时检查写入的单词,但我想知道是否有办法防止用户在浏览器中复制文本?

What I have tried so far:到目前为止我尝试过的:

  1. Disable right click (didn't work on mobile browsers)禁用右键单击(不适用于移动浏览器)
  2. Show an alert using the onmousedown event in all the page (it didn't work either)在所有页面中使用 onmousedown 事件显示警报(它也不起作用)

Using any libraries is OK.使用任何库都可以。

You can simply make the text into an image.您可以简单地将文本转换为图像。

<style type="text/css">
div.image {
    width: 100px;
    height: 100px;
    background-image: url-to-your-image;
}
</style>

To generate the images you can use a server side script as in the aswers of this question要生成图像,您可以使用服务器端脚本,如本问题的答案

or something like this:或类似的东西:

<?php
header("Content-type: image/png");
$im = @imagecreate(210, 30)
or die("Cannot Initialize new GD image stream");
$background_color = imagecolorallocate($im, 255, 255, 255);
$text_color = imagecolorallocate($im, 0, 0, 0);
imagestring($im, 4, 5, 5,  "This is a test", $text_color);
imagepng($im);
imagedestroy($im);
?> 

Test here在这里测试

You can prevent the user from actually selecting the text so it can not be copied - however I'd still combine this with paste detection as others recommended您可以阻止用户实际选择文本,因此无法复制它 - 但是我仍然会像其他人推荐的那样将其与粘贴检测结合起来

 .noselect { -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; }
 <p>this can be selected</p> <p class="noselect">this can NOT be selected</p>

But the user can still open the page source and copy it from there.但是用户仍然可以打开页面源并从那里复制它。

One crazy way of doing this is, laying out another absolutely positioned element on top of this.一种疯狂的方法是,在此之上放置另一个绝对定位的元素。 But this will disallow clicking of links too!但这也将禁止点击链接! May be you can do it with position: relative and a higher z-index .也许你可以用position: relative和更高的z-index来做到这一点。

 .content {position: relative;} .content .mask {position: absolute; z-index: 1; width: 100%; height: 100%;} .content a {position: relative; z-index: 3;}
 <div class="content"> <div class="mask"></div> <p>Pages that you view in incognito tabs won't stick around in your browser's history, cookie store or search history after you've closed <strong>all</strong> of your incognito tabs. Any files that you download or bookmarks that you create will be kept. <a href="https://support.google.com/chrome/?p=incognito">Learn more about incognito browsing</a></p> </div>

Try using the touch or longpress events.尝试使用touchlongpress事件。

<!DOCTYPE html>
<html>
<head>
  <script>
    function absorbEvent_(event) {
      var e = event || window.event;
      e.preventDefault && e.preventDefault();
      e.stopPropagation && e.stopPropagation();
      e.cancelBubble = true;
      e.returnValue = false;
      return false;
    }

    function preventLongPressMenu(node) {
      node.ontouchstart = absorbEvent_;
      node.ontouchmove = absorbEvent_;
      node.ontouchend = absorbEvent_;
      node.ontouchcancel = absorbEvent_;
    }

    function init() {
      preventLongPressMenu(document.getElementById('theimage'));
    }
  </script>
</head>
<body onload="init()">
  <img id="theimage" src="http://www.google.com/logos/arthurboyd2010-hp.jpg" width="400">
</body>
</html>

Source来源

Try putting a transparent div over the text.尝试在文本上放置一个透明的 div。 I have used jQuery here.我在这里使用了 jQuery。 That should work.那应该工作。

var position = $('#textInHere').position();
$('#noClickThroughThis').css({
    height: ($('#textInHere').height()),
    width:  ($('#textInHere').width()),
    position: 'absolute',
    top: position.top,
    left: position.left,
    'z-index': 100
});

Here is a fiddle http://jsfiddle.net/lacrioque/tc4bwejn/这是一个小提琴http://jsfiddle.net/lacrioque/tc4bwejn/

It's easy to disable the paste feature by using jQuery.使用 jQuery 很容易禁用粘贴功能。 For example, if you have an edit field like this one:例如,如果您有一个这样的编辑字段:

<p id='someInput' contenteditable='true'>Here is the text</p>

Then, this piece of jQuery code will disable the pasting feature on it:然后,这段 jQuery 代码将禁用其上的粘贴功能:

$('#someInput').on('paste', function(e) {
  return false;
});

A good way to work out if a user is cheating is to compare the current input length to the last input length.判断用户是否作弊的一个好方法是将当前输入长度与最后输入长度进行比较。 You can use a data attribute to store the previous value (or length):您可以使用数据属性来存储先前的值(或长度):

<textarea class="typing-only" data-temp=""></textarea>

jQuery: jQuery:

$(document).on('input', '.typing-only', function(){
    if((this.value.length - 1) > $(this).data('temp').length){
        alert('Cheat!');
    }
    $(this).data('temp', this.value);
});

JSFiddle demo JSFiddle 演示

pointer-events: none

CSS pointer-events allows you to control the interaction between an element and the mouse. CSS pointer-events允许您控制元素和鼠标之间的交互。 When set to none , the element is never the target of mouse events.当设置为none ,元素永远不会成为鼠标事件的目标。

MDN definition page MDN定义页面

You can try using :after tag and styling it with content: "Text";您可以尝试使用:after标签并使用content: "Text"; in css, AFAIK you cannot select :before and :after's content.在 css 中,AFAIK 你不能选择 :before 和 :after 的内容。

Thanks for your amazing solutions.感谢您提供的惊人解决方案。 I tested all of them, and in short some of them worked only on a PC, some only on Chrome and Firefox and some only on Safari , but unfortunately none of them worked 100%.我测试了所有这些,简而言之,其中一些仅在 PC 上运行,一些仅在 Chrome 和 Firefox 上运行,一些仅在Safari 上运行,但不幸的是,它们都没有 100% 运行。

Although @Max answer might be safest, I didn't tag with PHP in the question because if I use this solution dealing with answers, it will be hard because I don't have access to words on the client side!尽管@Max 答案可能是最安全的,但我没有在问题中使用 PHP 进行标记,因为如果我使用此解决方案来处理答案,将会很困难,因为我无法在客户端访问单词!

So the ultimate solution I came with was combining all of the provided answers plus some new methods (like clearing the clipboard every second) into a jQuery plugin.因此,我提出的最终解决方案是将所有提供的答案以及一些新方法(例如每秒清除剪贴板)组合到一个 jQuery 插件中。 Now it works on multiple elements too and worked 100% on PC browsers, Firefox, Chrome, and Safari.现在它也适用于多个元素,并且 100% 可以在 PC 浏览器、Firefox、Chrome 和 Safari 上运行。


What this plugin does这个插件的作用

  1. Prevent pasting (optional)防止粘贴(可选)
  2. Clearing clipboard (looks like it doesn't work well)清除剪贴板(看起来效果不佳)
  3. Absorbs all touch events吸收所有触摸事件
  4. Disable right click禁用右键单击
  5. Disable user selections禁用用户选择
  6. Disable pointer events禁用指针事件
  7. Add a mask with a z-index inside any selected DOM在任何选定的 DOM 中添加带有 z-index 的掩码
  8. Add a transparent div on any selected DOM在任何选定的 DOM 上添加一个透明的 div

A jsFiddle :一个 jsFiddle

(function($) {

    $.fn.blockCopy = function(options) {

        var settings = $.extend({
            blockPasteClass    : null
        }, options);

        if(settings.blockPasteClass){
            $("." + settings.blockPasteClass ).bind('copy paste cut drag drop', function (e) {
                e.preventDefault();
                return false;
            });
        }

        function style_appender(rule){
            $('html > head').append($('<style>'+rule+'</style>'));
        }

        function html_appender(html){
            $("body").append(html);
        }

        function clearClipboard() {
            var $temp = $("#bypasser");
            $temp.val("You can't cheat !").select();
            document.execCommand("copy");
        }

        function add_absolute_div(id) {
            html_appender("<div id='noClick"+id+"' onclick='return false;' oncontextmenu='return false;'>&nbsp;</div>");
        }

        function absorbEvent_(event) {
            var e = event || window.event;
            e.preventDefault && e.preventDefault();
            e.stopPropagation && e.stopPropagation();
            e.cancelBubble = true;
            e.returnValue = false;
            return false;
        }

        function preventLongPressMenu(node) {
            node.ontouchstart = absorbEvent_;
            node.ontouchmove = absorbEvent_;
            node.ontouchend = absorbEvent_;
            node.ontouchcancel = absorbEvent_;
        }

        function set_absolute_div(element,id){
            var position = element.position();
            var noclick = "#noClick" + id;

            $(noclick).css({
                height: (element.height()),
                width:    (element.width()),
                position: 'absolute',
                top: position.top,
                left: position.left,
                'z-index': 100
            })
        }


        $("body").bind("contextmenu", function(e) {
            e.preventDefault();
        });

        //Append needed rules to CSS
        style_appender(
            "* {-moz-user-select: none !important; -khtml-user-select: none !important;   -webkit-user-select: none !important; -ms-user-select: none !important;   user-select: none !important; }"+
            ".content {position: relative !important; }" +
            ".content .mask {position: absolute !important ; z-index: 1 !important; width: 100% !important; height: 100%!important;}" +
            ".content a {position: relative !important; z-index: 3 !important;}"+
            ".content, .content .mask{ pointer-events: none;}"
        );


        //Append an input to clear the clipboard
        html_appender("<input id='bypasser' value='nothing' type='hidden'>");

        //Clearing clipboard Intervali
        setInterval(clearClipboard,1000);

        var id = 1;

        return this.each( function() {

            //Preventing using touch events
            preventLongPressMenu($(this));

            //Add CSS preventer rules to selected DOM & append mask to class
            $(this).addClass("content").append("<div class='mask'></div>");

            //Append an absolute div to body
            add_absolute_div(id);

            //Set position of the div to selected DOM
            set_absolute_div($(this),id);

            id++;
        });
    }
}(jQuery));

Usage用法

$(document).ready(function(){

    $(".words").blockCopy({
        blockPasteClass : "noPasting"
    });

});

HTML for demo:用于演示的 HTML:

<div class="words">Test1: Can you copy me or not?</div><br>
<div class="words">Test2: Can you <br> copy me or not?</div><br>
<textarea class="words">Test3: Can you <br>copy me or not?</textarea><br>


<textarea  class="noPasting"   placeholder="Test1: Paste content if you can"   ></textarea><br>

<textarea  class="noPasting"   placeholder="Test2: Paste content if you can"   ></textarea>

Let me know your opinions.让我知道你的意见。 Thanks.谢谢。

Sources来源

A simpler solution than the accepted one would be to simply use a canvas element with filltext比公认的更简单的解决方案是简单地使用带有填充文本的画布元素

 var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); ctx.fillText("Can't copy this", 5, 30);
 <canvas id="myCanvas"></canvas>

JSFiddle example JSFiddle 示例

You can return false on jQuery's cut copy paste events.您可以在 jQuery 的cut copy paste事件上return false

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script> $(document).on("cut copy paste", function(event){ return false; }); </script> <textarea>Try to copy my text</textarea>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM