CSS+JavaScript 禁用浏览器复制功能的几种方法

🛡️ 禁用浏览器复制功能完整指南

网页中禁用用户的复制功能,包括 CSS 方法、JavaScript 方法、综合解决方案以及实际应用场景。适用于需要保护内容版权、防止恶意爬取或提升用户体验的场景。

📋 目录

🚀 快速开始

如果您想快速实现基本的复制保护,可以直接使用以下代码:

复制代码
<!DOCTYPE html>
<html>
  <head>
    <style>
      /* 基础保护样式 */
      .protected {
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        -webkit-touch-callout: none;
      }
    </style>
  </head>
  <body class="protected">
    <script>
      // 基础保护脚本
      document.addEventListener("contextmenu", (e) => e.preventDefault());
      document.addEventListener("keydown", (e) => {
        if (e.ctrlKey && (e.keyCode === 67 || e.keyCode === 65)) {
          e.preventDefault();
        }
      });
    </script>

    <h1>受保护的内容</h1>
    <p>这里的内容无法被轻易复制</p>
  </body>
</html>

🎨 CSS 方法

CSS 方法是最基础且高效的保护方式,通过样式属性来禁用用户的选择和交互行为。

1. 禁用文本选择

基础语法
复制代码
/* 禁用所有文本选择 - 基础版本 */
.no-select {
  -webkit-user-select: none; /* Safari */
  -moz-user-select: none; /* Firefox */
  -ms-user-select: none; /* Internet Explorer/Edge */
  user-select: none; /* 标准语法 */
}

/* 应用到整个页面 */
body {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
高级配置
复制代码
/* 完整的文本选择保护 */
.protected-content {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;

  /* 移动端优化 */
  -webkit-touch-callout: none; /* 禁用iOS Safari的长按菜单 */
  -webkit-tap-highlight-color: transparent; /* 禁用点击高亮 */
  -webkit-appearance: none; /* 移除默认样式 */

  /* 禁用文本选择手柄 */
  -webkit-text-size-adjust: none;
}

/* 选择性允许文本选择 */
.selectable {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

/* 只允许选择文本内容,不允许选择元素 */
.text-only {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

/* 允许全部选择 */
.select-all {
  -webkit-user-select: all;
  -moz-user-select: all;
  -ms-user-select: all;
  user-select: all;
}
实际使用示例
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <style>
      /* 保护主要内容 */
      .article-content {
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none;
        padding: 20px;
        border: 1px solid #ddd;
        background: #f9f9f9;
      }

      /* 允许输入框正常使用 */
      .user-input {
        -webkit-user-select: text;
        -moz-user-select: text;
        -ms-user-select: text;
        user-select: text;
        padding: 10px;
        border: 1px solid #ccc;
        width: 100%;
        margin: 10px 0;
      }

      /* 代码块可以选择 */
      .code-block {
        -webkit-user-select: all;
        -moz-user-select: all;
        -ms-user-select: all;
        user-select: all;
        background: #f4f4f4;
        padding: 10px;
        font-family: monospace;
      }
    </style>
  </head>
  <body>
    <div class="article-content">
      <h2>受保护的文章标题</h2>
      <p>这段内容无法被选择和复制</p>
      <img src="protected-image.jpg" alt="受保护的图片" />
    </div>

    <input
      type="text"
      class="user-input"
      placeholder="这里可以正常输入和选择文本"
    />

    <div class="code-block">console.log('这段代码可以被选择复制');</div>
  </body>
</html>

2. 禁用拖拽功能

复制代码
/* 禁用图片和媒体元素的拖拽 */
img,
video,
audio,
canvas,
svg {
  -webkit-user-drag: none;
  -khtml-user-drag: none;
  -moz-user-drag: none;
  -o-user-drag: none;
  user-drag: none;
  pointer-events: none; /* 完全禁用鼠标事件 */
}

/* 禁用所有元素的拖拽 */
* {
  -webkit-user-drag: none;
  -khtml-user-drag: none;
  -moz-user-drag: none;
  -o-user-drag: none;
  user-drag: none;
}

/* 恢复必要的交互元素 */
.interactive,
button,
input,
textarea,
select,
a {
  pointer-events: auto;
  -webkit-user-drag: auto;
  -khtml-user-drag: auto;
  -moz-user-drag: auto;
  -o-user-drag: auto;
  user-drag: auto;
}

/* 特殊处理:可拖拽的元素 */
.draggable {
  -webkit-user-drag: element;
  -khtml-user-drag: element;
  -moz-user-drag: element;
  -o-user-drag: element;
  user-drag: element;
}

3. 移动端特殊优化

复制代码
/* 移动端复制保护 */
.mobile-protected {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;

  /* iOS Safari 特殊处理 */
  -webkit-touch-callout: none; /* 禁用长按菜单 */
  -webkit-tap-highlight-color: transparent; /* 禁用点击高亮 */

  /* Android 特殊处理 */
  -webkit-text-size-adjust: none; /* 禁用文本大小调整 */

  /* 禁用双击缩放 */
  touch-action: manipulation;

  /* 禁用选择手柄 */
  -webkit-appearance: none;
}

/* 禁用文本选择高亮 */
.mobile-protected::selection {
  background: transparent;
}

.mobile-protected::-moz-selection {
  background: transparent;
}

/* 禁用iOS Safari的选择工具栏 */
.mobile-protected::-webkit-selection {
  background: transparent;
}

⚡ JavaScript 方法

JavaScript 方法提供了更灵活和强大的保护功能,可以动态控制用户行为并提供反馈。

1. 禁用右键菜单

基础实现
复制代码
// 方法1: 全局禁用右键菜单
document.addEventListener("contextmenu", function (e) {
  e.preventDefault();
  return false;
});

// 方法2: 针对特定元素
document
  .getElementById("protected-content")
  .addEventListener("contextmenu", function (e) {
    e.preventDefault();
    alert("右键功能已被禁用");
    return false;
  });

// 方法3: 使用事件委托
document.addEventListener("contextmenu", function (e) {
  if (e.target.classList.contains("protected")) {
    e.preventDefault();
    console.log("尝试右键点击受保护内容");
    return false;
  }
});
高级实现
复制代码
// 智能右键菜单禁用
class ContextMenuProtection {
  constructor(options = {}) {
    this.options = {
      showWarning: true,
      warningMessage: "此内容受到保护,无法使用右键菜单",
      allowedElements: ["input", "textarea"],
      ...options,
    };
    this.init();
  }

  init() {
    document.addEventListener("contextmenu", (e) => this.handleContextMenu(e));
  }

  handleContextMenu(e) {
    const tagName = e.target.tagName.toLowerCase();

    // 允许特定元素使用右键菜单
    if (this.options.allowedElements.includes(tagName)) {
      return true;
    }

    // 检查是否有特殊标记
    if (e.target.dataset.allowContextMenu === "true") {
      return true;
    }

    e.preventDefault();

    if (this.options.showWarning) {
      this.showWarning(this.options.warningMessage);
    }

    return false;
  }

  showWarning(message) {
    // 创建自定义提示
    const warning = document.createElement("div");
    warning.textContent = message;
    warning.style.cssText = `
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: #ff4444;
            color: white;
            padding: 10px 20px;
            border-radius: 5px;
            z-index: 10000;
            font-size: 14px;
        `;

    document.body.appendChild(warning);

    setTimeout(() => {
      document.body.removeChild(warning);
    }, 2000);
  }
}

// 使用示例
const contextProtection = new ContextMenuProtection({
  showWarning: true,
  warningMessage: "内容受保护,禁止右键操作",
  allowedElements: ["input", "textarea", "select"],
});

2. 禁用键盘快捷键

基础实现
复制代码
// 禁用常见的复制快捷键
document.addEventListener("keydown", function (e) {
  // 禁用 Ctrl+C (复制)
  if (e.ctrlKey && e.keyCode === 67) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+A (全选)
  if (e.ctrlKey && e.keyCode === 65) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+V (粘贴)
  if (e.ctrlKey && e.keyCode === 86) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+X (剪切)
  if (e.ctrlKey && e.keyCode === 88) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+S (保存)
  if (e.ctrlKey && e.keyCode === 83) {
    e.preventDefault();
    return false;
  }

  // 禁用 F12 (开发者工具)
  if (e.keyCode === 123) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+Shift+I (开发者工具)
  if (e.ctrlKey && e.shiftKey && e.keyCode === 73) {
    e.preventDefault();
    return false;
  }

  // 禁用 Ctrl+U (查看源代码)
  if (e.ctrlKey && e.keyCode === 85) {
    e.preventDefault();
    return false;
  }
});
高级键盘保护
复制代码
class KeyboardProtection {
  constructor(options = {}) {
    this.options = {
      disableCopy: true,
      disablePaste: true,
      disableSelectAll: true,
      disableSave: true,
      disableDevTools: true,
      disablePrint: true,
      allowedInputs: ["input", "textarea"],
      showWarnings: true,
      ...options,
    };

    this.forbiddenKeys = this.buildForbiddenKeys();
    this.init();
  }

  buildForbiddenKeys() {
    const keys = [];

    if (this.options.disableCopy) {
      keys.push({ ctrl: true, key: 67, name: "Ctrl+C (复制)" });
    }

    if (this.options.disablePaste) {
      keys.push({ ctrl: true, key: 86, name: "Ctrl+V (粘贴)" });
    }

    if (this.options.disableSelectAll) {
      keys.push({ ctrl: true, key: 65, name: "Ctrl+A (全选)" });
    }

    if (this.options.disableSave) {
      keys.push({ ctrl: true, key: 83, name: "Ctrl+S (保存)" });
    }

    if (this.options.disableDevTools) {
      keys.push(
        { key: 123, name: "F12 (开发者工具)" },
        { ctrl: true, shift: true, key: 73, name: "Ctrl+Shift+I (开发者工具)" },
        { ctrl: true, shift: true, key: 74, name: "Ctrl+Shift+J (控制台)" },
        { ctrl: true, key: 85, name: "Ctrl+U (查看源代码)" }
      );
    }

    if (this.options.disablePrint) {
      keys.push({ ctrl: true, key: 80, name: "Ctrl+P (打印)" });
    }

    return keys;
  }

  init() {
    document.addEventListener("keydown", (e) => this.handleKeyDown(e));
  }

  handleKeyDown(e) {
    const target = e.target;
    const tagName = target.tagName.toLowerCase();

    // 允许在输入框中使用某些快捷键
    if (this.options.allowedInputs.includes(tagName)) {
      // 在输入框中只禁用开发者工具相关快捷键
      if (this.options.disableDevTools) {
        const devToolsKeys = this.forbiddenKeys.filter(
          (key) =>
            key.name.includes("开发者工具") ||
            key.name.includes("控制台") ||
            key.name.includes("查看源代码")
        );

        for (let forbidden of devToolsKeys) {
          if (this.matchesKeyCombo(e, forbidden)) {
            e.preventDefault();
            this.showWarning(`${forbidden.name} 已被禁用`);
            return false;
          }
        }
      }
      return true;
    }

    // 检查所有禁用的快捷键
    for (let forbidden of this.forbiddenKeys) {
      if (this.matchesKeyCombo(e, forbidden)) {
        e.preventDefault();

        if (this.options.showWarnings) {
          this.showWarning(`${forbidden.name} 已被禁用`);
        }

        return false;
      }
    }
  }

  matchesKeyCombo(event, combo) {
    return (
      (!combo.ctrl || event.ctrlKey) &&
      (!combo.shift || event.shiftKey) &&
      (!combo.alt || event.altKey) &&
      event.keyCode === combo.key
    );
  }

  showWarning(message) {
    if (this.options.showWarnings) {
      console.warn(message);
      // 可以在这里添加自定义的警告显示逻辑
    }
  }
}

// 使用示例
const keyboardProtection = new KeyboardProtection({
  disableCopy: true,
  disablePaste: true,
  disableSelectAll: true,
  disableSave: true,
  disableDevTools: true,
  disablePrint: true,
  allowedInputs: ["input", "textarea"],
  showWarnings: true,
});

3. 禁用文本选择

复制代码
// 方法1: 禁用选择事件
document.addEventListener("selectstart", function (e) {
  e.preventDefault();
  return false;
});

// 方法2: 清除已选择的文本
document.addEventListener("mouseup", function () {
  if (window.getSelection) {
    window.getSelection().removeAllRanges();
  } else if (document.selection) {
    document.selection.empty();
  }
});

// 方法3: 禁用拖拽选择
document.addEventListener("dragstart", function (e) {
  e.preventDefault();
  return false;
});

// 方法4: 高级文本选择保护
class TextSelectionProtection {
  constructor(options = {}) {
    this.options = {
      clearSelectionInterval: 100, // 清除选择的间隔时间(ms)
      allowedElements: ["input", "textarea"],
      ...options,
    };
    this.init();
  }

  init() {
    // 禁用选择开始事件
    document.addEventListener("selectstart", (e) => this.handleSelectStart(e));

    // 禁用拖拽事件
    document.addEventListener("dragstart", (e) => this.handleDragStart(e));

    // 定期清除选择
    if (this.options.clearSelectionInterval > 0) {
      setInterval(
        () => this.clearSelection(),
        this.options.clearSelectionInterval
      );
    }

    // 监听鼠标事件
    document.addEventListener("mouseup", () => this.clearSelection());
    document.addEventListener("keyup", () => this.clearSelection());
  }

  handleSelectStart(e) {
    const tagName = e.target.tagName.toLowerCase();

    if (this.options.allowedElements.includes(tagName)) {
      return true;
    }

    e.preventDefault();
    return false;
  }

  handleDragStart(e) {
    const tagName = e.target.tagName.toLowerCase();

    if (this.options.allowedElements.includes(tagName)) {
      return true;
    }

    e.preventDefault();
    return false;
  }

  clearSelection() {
    try {
      if (window.getSelection) {
        const selection = window.getSelection();
        if (selection.rangeCount > 0) {
          // 检查选择是否在允许的元素中
          const range = selection.getRangeAt(0);
          const container = range.commonAncestorContainer;
          const element =
            container.nodeType === Node.TEXT_NODE
              ? container.parentElement
              : container;

          const tagName = element.tagName ? element.tagName.toLowerCase() : "";

          if (!this.options.allowedElements.includes(tagName)) {
            selection.removeAllRanges();
          }
        }
      } else if (document.selection) {
        document.selection.empty();
      }
    } catch (e) {
      // 忽略错误
    }
  }
}

// 使用示例
const textProtection = new TextSelectionProtection({
  clearSelectionInterval: 50,
  allowedElements: ["input", "textarea", "select"],
});

4. 监控开发者工具

复制代码
// 基础开发者工具检测
let devtools = {
  open: false,
  orientation: null,
};

const threshold = 160;

function detectDevTools() {
  if (
    window.outerHeight - window.innerHeight > threshold ||
    window.outerWidth - window.innerWidth > threshold
  ) {
    if (!devtools.open) {
      devtools.open = true;
      console.log("开发者工具已打开");
      // 可以在这里添加警告或重定向
      // window.location.href = 'about:blank';
    }
  } else {
    devtools.open = false;
  }
}

setInterval(detectDevTools, 500);

// 高级开发者工具检测
class DevToolsDetection {
  constructor(options = {}) {
    this.options = {
      checkInterval: 1000,
      onDetected: () => console.warn("检测到开发者工具"),
      onClosed: () => console.log("开发者工具已关闭"),
      threshold: 160,
      redirectUrl: null,
      showWarning: true,
      ...options,
    };

    this.isOpen = false;
    this.init();
  }

  init() {
    setInterval(() => this.check(), this.options.checkInterval);

    // 检测控制台输出
    this.detectConsoleOutput();

    // 检测调试器
    this.detectDebugger();
  }

  check() {
    const widthThreshold =
      window.outerWidth - window.innerWidth > this.options.threshold;
    const heightThreshold =
      window.outerHeight - window.innerHeight > this.options.threshold;

    if (widthThreshold || heightThreshold) {
      if (!this.isOpen) {
        this.isOpen = true;
        this.handleDetected();
      }
    } else {
      if (this.isOpen) {
        this.isOpen = false;
        this.handleClosed();
      }
    }
  }

  detectConsoleOutput() {
    // 重写console方法来检测控制台使用
    const originalLog = console.log;
    console.log = (...args) => {
      this.handleDetected();
      return originalLog.apply(console, args);
    };
  }

  detectDebugger() {
    // 定期检查调试器
    setInterval(() => {
      const start = performance.now();
      debugger;
      const end = performance.now();

      if (end - start > 100) {
        this.handleDetected();
      }
    }, 3000);
  }

  handleDetected() {
    this.options.onDetected();

    if (this.options.showWarning) {
      alert("检测到开发者工具,页面功能可能受限");
    }

    if (this.options.redirectUrl) {
      window.location.href = this.options.redirectUrl;
    }
  }

  handleClosed() {
    this.options.onClosed();
  }
}

// 使用示例
const devToolsDetection = new DevToolsDetection({
  checkInterval: 1000,
  onDetected: () => {
    console.warn("开发者工具被检测到");
    document.body.style.display = "none";
  },
  onClosed: () => {
    document.body.style.display = "block";
  },
  threshold: 160,
  showWarning: true,
});

🔧 综合解决方案

将 CSS 和 JavaScript 方法结合起来,创建一个完整的复制保护系统。

完整的保护类

复制代码
class CopyProtection {
  constructor(options = {}) {
    this.options = {
      // 基础保护选项
      disableRightClick: true,
      disableSelection: true,
      disableKeyboardShortcuts: true,
      disableDeveloperTools: true,
      disableDragDrop: true,
      disablePrint: true,

      // 用户体验选项
      showWarnings: true,
      allowedElements: ["input", "textarea", "select"],
      warningDuration: 2000,

      // 高级选项
      clearSelectionInterval: 100,
      devToolsCheckInterval: 1000,
      redirectOnDevTools: false,
      redirectUrl: "about:blank",

      // 自定义消息
      messages: {
        rightClick: "右键功能已被禁用",
        keyboard: "该快捷键已被禁用",
        devTools: "检测到开发者工具",
        selection: "文本选择已被禁用",
      },

      ...options,
    };

    this.isDevToolsOpen = false;
    this.init();
  }

  init() {
    // 添加CSS样式
    this.addProtectionStyles();

    // 初始化各种保护功能
    if (this.options.disableRightClick) {
      this.initRightClickProtection();
    }

    if (this.options.disableSelection) {
      this.initSelectionProtection();
    }

    if (this.options.disableKeyboardShortcuts) {
      this.initKeyboardProtection();
    }

    if (this.options.disableDeveloperTools) {
      this.initDevToolsDetection();
    }

    if (this.options.disableDragDrop) {
      this.initDragDropProtection();
    }

    if (this.options.disablePrint) {
      this.initPrintProtection();
    }

    console.log("🛡️ 复制保护系统已启动");
  }

  addProtectionStyles() {
    const style = document.createElement("style");
    style.id = "copy-protection-styles";
    style.textContent = `
            /* 基础保护样式 */
            .copy-protected {
                -webkit-user-select: none;
                -moz-user-select: none;
                -ms-user-select: none;
                user-select: none;
                -webkit-touch-callout: none;
                -webkit-tap-highlight-color: transparent;
                -webkit-user-drag: none;
                -khtml-user-drag: none;
                -moz-user-drag: none;
                -o-user-drag: none;
                user-drag: none;
            }

            /* 媒体元素保护 */
            .copy-protected img,
            .copy-protected video,
            .copy-protected audio,
            .copy-protected canvas {
                pointer-events: none;
                -webkit-user-drag: none;
                -khtml-user-drag: none;
                -moz-user-drag: none;
                -o-user-drag: none;
                user-drag: none;
            }

            /* 选择高亮禁用 */
            .copy-protected::selection {
                background: transparent;
            }

            .copy-protected::-moz-selection {
                background: transparent;
            }

            /* 警告提示样式 */
            .copy-protection-warning {
                position: fixed;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                background: linear-gradient(135deg, #ff6b6b, #ee5a24);
                color: white;
                padding: 15px 25px;
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.3);
                z-index: 999999;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                font-size: 14px;
                font-weight: 500;
                text-align: center;
                animation: copyProtectionFadeIn 0.3s ease-out;
            }

            @keyframes copyProtectionFadeIn {
                from {
                    opacity: 0;
                    transform: translate(-50%, -50%) scale(0.8);
                }
                to {
                    opacity: 1;
                    transform: translate(-50%, -50%) scale(1);
                }
            }

            /* 允许的元素恢复正常功能 */
            .copy-protected input,
            .copy-protected textarea,
            .copy-protected select {
                -webkit-user-select: text;
                -moz-user-select: text;
                -ms-user-select: text;
                user-select: text;
                pointer-events: auto;
            }
        `;

    document.head.appendChild(style);

    // 应用保护样式到body
    document.body.classList.add("copy-protected");
  }

  initRightClickProtection() {
    document.addEventListener("contextmenu", (e) => {
      const tagName = e.target.tagName.toLowerCase();

      if (this.options.allowedElements.includes(tagName)) {
        return true;
      }

      if (e.target.dataset.allowContextMenu === "true") {
        return true;
      }

      e.preventDefault();

      if (this.options.showWarnings) {
        this.showWarning(this.options.messages.rightClick);
      }

      return false;
    });
  }

  initSelectionProtection() {
    // 禁用选择开始
    document.addEventListener("selectstart", (e) => {
      const tagName = e.target.tagName.toLowerCase();

      if (this.options.allowedElements.includes(tagName)) {
        return true;
      }

      e.preventDefault();
      return false;
    });

    // 定期清除选择
    if (this.options.clearSelectionInterval > 0) {
      setInterval(() => {
        this.clearSelection();
      }, this.options.clearSelectionInterval);
    }

    // 监听鼠标和键盘事件
    document.addEventListener("mouseup", () => this.clearSelection());
    document.addEventListener("keyup", () => this.clearSelection());
  }

  clearSelection() {
    try {
      if (window.getSelection) {
        const selection = window.getSelection();
        if (selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          const container = range.commonAncestorContainer;
          const element =
            container.nodeType === Node.TEXT_NODE
              ? container.parentElement
              : container;

          const tagName = element.tagName ? element.tagName.toLowerCase() : "";

          if (!this.options.allowedElements.includes(tagName)) {
            selection.removeAllRanges();
          }
        }
      } else if (document.selection) {
        document.selection.empty();
      }
    } catch (e) {
      // 忽略错误
    }
  }

  initKeyboardProtection() {
    const forbiddenKeys = [
      { ctrl: true, key: 67, name: "Ctrl+C (复制)" },
      { ctrl: true, key: 86, name: "Ctrl+V (粘贴)" },
      { ctrl: true, key: 65, name: "Ctrl+A (全选)" },
      { ctrl: true, key: 88, name: "Ctrl+X (剪切)" },
      { ctrl: true, key: 83, name: "Ctrl+S (保存)" },
      { ctrl: true, key: 80, name: "Ctrl+P (打印)" },
      { key: 123, name: "F12 (开发者工具)" },
      { ctrl: true, shift: true, key: 73, name: "Ctrl+Shift+I (开发者工具)" },
      { ctrl: true, shift: true, key: 74, name: "Ctrl+Shift+J (控制台)" },
      { ctrl: true, key: 85, name: "Ctrl+U (查看源代码)" },
    ];

    document.addEventListener("keydown", (e) => {
      const target = e.target;
      const tagName = target.tagName.toLowerCase();

      // 允许在输入框中使用某些快捷键
      if (this.options.allowedElements.includes(tagName)) {
        // 在输入框中只禁用开发者工具相关快捷键
        const devToolsKeys = forbiddenKeys.filter(
          (key) =>
            key.name.includes("开发者工具") ||
            key.name.includes("控制台") ||
            key.name.includes("查看源代码")
        );

        for (let forbidden of devToolsKeys) {
          if (this.matchesKeyCombo(e, forbidden)) {
            e.preventDefault();
            if (this.options.showWarnings) {
              this.showWarning(this.options.messages.keyboard);
            }
            return false;
          }
        }
        return true;
      }

      // 检查所有禁用的快捷键
      for (let forbidden of forbiddenKeys) {
        if (this.matchesKeyCombo(e, forbidden)) {
          e.preventDefault();

          if (this.options.showWarnings) {
            this.showWarning(this.options.messages.keyboard);
          }

          return false;
        }
      }
    });
  }

  matchesKeyCombo(event, combo) {
    return (
      (!combo.ctrl || event.ctrlKey) &&
      (!combo.shift || event.shiftKey) &&
      (!combo.alt || event.altKey) &&
      event.keyCode === combo.key
    );
  }

  initDragDropProtection() {
    document.addEventListener("dragstart", (e) => {
      const tagName = e.target.tagName.toLowerCase();

      if (this.options.allowedElements.includes(tagName)) {
        return true;
      }

      e.preventDefault();
      return false;
    });
  }

  initPrintProtection() {
    // 禁用打印快捷键已在键盘保护中处理
    // 这里可以添加额外的打印保护逻辑
    window.addEventListener("beforeprint", (e) => {
      if (this.options.showWarnings) {
        this.showWarning("打印功能已被禁用");
      }
      e.preventDefault();
      return false;
    });
  }

  initDevToolsDetection() {
    setInterval(() => {
      const widthThreshold = window.outerWidth - window.innerWidth > 160;
      const heightThreshold = window.outerHeight - window.innerHeight > 160;

      if (widthThreshold || heightThreshold) {
        if (!this.isDevToolsOpen) {
          this.isDevToolsOpen = true;
          this.handleDevToolsDetected();
        }
      } else {
        this.isDevToolsOpen = false;
      }
    }, this.options.devToolsCheckInterval);
  }

  handleDevToolsDetected() {
    if (this.options.showWarnings) {
      this.showWarning(this.options.messages.devTools);
    }

    if (this.options.redirectOnDevTools) {
      setTimeout(() => {
        window.location.href = this.options.redirectUrl;
      }, 1000);
    }
  }

  showWarning(message) {
    // 移除已存在的警告
    const existingWarning = document.querySelector(".copy-protection-warning");
    if (existingWarning) {
      existingWarning.remove();
    }

    // 创建新的警告
    const warning = document.createElement("div");
    warning.className = "copy-protection-warning";
    warning.textContent = message;

    document.body.appendChild(warning);

    // 自动移除警告
    setTimeout(() => {
      if (warning.parentNode) {
        warning.parentNode.removeChild(warning);
      }
    }, this.options.warningDuration);
  }

  // 公共方法:启用保护
  enable() {
    document.body.classList.add("copy-protected");
    console.log("🛡️ 复制保护已启用");
  }

  // 公共方法:禁用保护
  disable() {
    document.body.classList.remove("copy-protected");
    console.log("🔓 复制保护已禁用");
  }

  // 公共方法:销毁保护
  destroy() {
    // 移除样式
    const style = document.getElementById("copy-protection-styles");
    if (style) {
      style.remove();
    }

    // 移除类名
    document.body.classList.remove("copy-protected");

    // 移除警告
    const warnings = document.querySelectorAll(".copy-protection-warning");
    warnings.forEach((warning) => warning.remove());

    console.log("🗑️ 复制保护已销毁");
  }
}

// 使用示例
const protection = new CopyProtection({
  // 基础保护选项
  disableRightClick: true,
  disableSelection: true,
  disableKeyboardShortcuts: true,
  disableDeveloperTools: true,
  disableDragDrop: true,
  disablePrint: false,

  // 用户体验选项
  showWarnings: true,
  allowedElements: ["input", "textarea", "select"],
  warningDuration: 3000,

  // 高级选项
  clearSelectionInterval: 50,
  devToolsCheckInterval: 1000,
  redirectOnDevTools: false,

  // 自定义消息
  messages: {
    rightClick: "🚫 右键功能已被禁用",
    keyboard: "⌨️ 该快捷键已被禁用",
    devTools: "🔧 检测到开发者工具",
    selection: "📝 文本选择已被禁用",
  },
});

🎯 高级技巧

1. 动态内容保护

复制代码
// 动态添加保护到新内容
function protectNewContent() {
  const observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
      mutation.addedNodes.forEach((node) => {
        if (node.nodeType === Node.ELEMENT_NODE) {
          node.classList.add("copy-protected");
        }
      });
    });
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true,
  });
}

2. 图片水印保护

复制代码
// 为图片添加水印
function addWatermarkToImages() {
  document.querySelectorAll("img").forEach((img) => {
    img.addEventListener("load", function () {
      const canvas = document.createElement("canvas");
      const ctx = canvas.getContext("2d");

      canvas.width = this.naturalWidth;
      canvas.height = this.naturalHeight;

      // 绘制原图
      ctx.drawImage(this, 0, 0);

      // 添加水印
      ctx.font = "20px Arial";
      ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
      ctx.fillText("© 版权所有", 10, 30);

      // 替换原图
      this.src = canvas.toDataURL();
    });
  });
}

3. 内容加密显示

复制代码
// 简单的内容混淆
function obfuscateContent() {
  const textNodes = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_TEXT,
    null,
    false
  );

  const nodes = [];
  let node;
  while ((node = textNodes.nextNode())) {
    if (node.textContent.trim()) {
      nodes.push(node);
    }
  }

  nodes.forEach((node) => {
    const original = node.textContent;
    const obfuscated = btoa(original); // Base64编码

    node.textContent = obfuscated;

    // 鼠标悬停时显示原文
    node.parentElement.addEventListener("mouseenter", () => {
      node.textContent = original;
    });

    node.parentElement.addEventListener("mouseleave", () => {
      node.textContent = obfuscated;
    });
  });
}

🌐 浏览器兼容性

功能 Chrome Firefox Safari Edge IE11
user-select
contextmenu 事件
selectstart 事件
dragstart 事件
keydown 事件
touch-callout
tap-highlight-color

❓ 常见问题解答

Q1: 这些方法能 100%防止复制吗?

A: 不能。这些方法只能防止普通用户的意外复制,技术熟练的用户仍然可以通过多种方式绕过这些限制。

Q2: 会影响 SEO 吗?

A : 适当使用不会影响 SEO。搜索引擎爬虫通常不会执行 JavaScript,所以 CSS 的user-select: none不会影响内容索引。

Q3: 如何在保护内容的同时保持可访问性?

A:

  • 确保输入框和表单元素可以正常使用
  • 为屏幕阅读器用户提供替代的内容访问方式
  • 不要完全禁用键盘导航

Q4: 移动端效果如何?

A : 移动端的保护效果相对较好,特别是 iOS Safari 的-webkit-touch-callout: none可以有效禁用长按菜单。

CSS+JavaScript 禁用浏览器复制功能的几种方法 - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

相关推荐
林太白2 分钟前
Nuxt3 功能篇
前端·javascript·后端
YuJie3 分钟前
webSocket Manager
前端·javascript
Mapmost18 分钟前
Mapmost SDK for UE5 内核升级,三维场景渲染效果飙升!
前端
Mapmost21 分钟前
重磅升级丨Mapmost全面兼容3DTiles 1.1,3DGS量测精度跃升至亚米级!
前端·vue.js·three.js
wycode27 分钟前
Promise(一)极简版demo
前端·javascript
浮幻云月28 分钟前
一个自开自用的Ai提效VsCode插件
前端·javascript
DevSecOps选型指南29 分钟前
SBOM风险预警 | NPM前端框架 javaxscript 遭受投毒窃取浏览器cookie
前端·人工智能·前端框架·npm·软件供应链安全厂商·软件供应链安全工具
__lll_37 分钟前
Docker 从入门到实战:容器、镜像与 Compose 全攻略
前端·docker
木春1 小时前
react组件化思维:高复用性 UI 设计之道
前端·react.js