[英]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:到目前为止我尝试过的:
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);
?>
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.尝试使用
touch
或longpress
事件。
<!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>
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);
});
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
,元素永远不会成为鼠标事件的目标。
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 上运行。
(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;'> </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));
$(document).ready(function(){
$(".words").blockCopy({
blockPasteClass : "noPasting"
});
});
<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.
谢谢。
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.