您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
完全解除复制/粘贴限制,保留 Ctrl+Z 撤销,并兼容大部分浏览器环境
// ==UserScript== // @name 完全解除任意网站复制粘贴限制 & 原生复制粘贴使用体验 // @namespace http://tampermonkey.net/ // @version 1.1 // @description 完全解除复制/粘贴限制,保留 Ctrl+Z 撤销,并兼容大部分浏览器环境 // @author AMT // @match *://*/* // @grant none // @run-at document-end // @license MIT // ==/UserScript== (function () { 'use strict'; /************** 0. 解除常规禁用选中 / 右键 / 拖拽 / 长按 **************/ const blocked = [ 'selectstart', 'mousedown', 'mouseup', 'mousemove', 'contextmenu', 'dragstart' ]; blocked.forEach(ev => document.addEventListener(ev, e => e.stopImmediatePropagation(), true) ); if (document.body) document.body.onselectstart = null; // 强制允许选中 const css = document.createElement('style'); css.textContent = ` *{user-select:text!important;-webkit-user-select:text!important;} `; document.head.appendChild(css); /************** 1. 统一处理 Ctrl/⌘+V **************/ const isMac = /Mac/i.test(navigator.platform); /** 监听主文档的粘贴快捷键 */ document.addEventListener('keydown', onKeyPaste, true); /** 监听所有同源 iframe(学习通很多编辑器在 iframe 内) */ observeIframes(node => node.addEventListener('keydown', onKeyPaste, true)); async function onKeyPaste(e) { const isPasteKey = (isMac ? e.metaKey : e.ctrlKey) && e.key.toLowerCase() === 'v'; if (!isPasteKey) return; const target = document.activeElement; if (!isEditable(target)) return; e.stopImmediatePropagation(); e.preventDefault(); // 读剪贴板 let text = await readClipboard(); if (!text) return; // 1) 先尝试最标准的 insertText —— 成功率最高,支持撤销 if (tryExecCommand(text, target)) return; /* ----------------------------------------------------------- 2) fallback:逐段“模拟键盘输入”,绕过 paste 封锁 --------------------------------------------------------- */ simulateTyping(text, target); } /************** 2. 辅助函数 **************/ /** 判断可编辑元素(input / textarea / contenteditable) */ function isEditable(el) { if (!el) return false; if (el.isContentEditable) return true; const tag = (el.tagName || '').toLowerCase(); if (tag === 'textarea') return true; if (tag === 'input') { // 只处理常见文本类型 return /^(?:text|search|email|url|tel|password)$/i.test(el.type || ''); } return false; } /** 读取剪贴板文字(多浏览器兜底) */ async function readClipboard() { // 新 API if (navigator.clipboard?.readText) { try { const t = await navigator.clipboard.readText(); if (t) return t; } catch { } } // 旧 API const legacy = (document.clipboardData || window.clipboardData); return legacy ? legacy.getData('text') : ''; } /** execCommand 插入文本,成功返回 true */ function tryExecCommand(text, el) { try { el.focus(); /* 对部分富文本框,只有先选中光标位置再 execCommand 才能奏效 */ if (document.execCommand('insertText', false, text)) { dispatchInput(el, text); return true; } } catch { /* fall through */ } return false; } /** fallback:把文本像键盘一样“敲”进去(一次性插入,效率 > 单字符) */ function simulateTyping(text, el) { if (!el) return; const isInput = !el.isContentEditable; /* 保存光标 & 原内容 */ let start = 0, end = 0, original = ''; if (isInput) { start = el.selectionStart; end = el.selectionEnd; original = el.value; } else { /* contentEditable 统计纯文本光标偏移——简单场景足够 */ const sel = el.ownerDocument.getSelection(); if (!sel.rangeCount) return; const range = sel.getRangeAt(0); start = range.startOffset; end = range.endOffset; original = el.textContent; } /* 计算插入后内容 */ const newValue = original.slice(0, start) + text + original.slice(end); /* 写入内容(对 React/Vue 等框架,用原生 setter 触发监听) */ if (isInput) { const setter = Object.getOwnPropertyDescriptor( el.tagName === 'INPUT' ? HTMLInputElement.prototype : HTMLTextAreaElement.prototype, 'value' ).set; setter.call(el, newValue); } else { el.textContent = newValue; } /* 恢复光标到粘贴尾部 */ if (isInput && el.setSelectionRange) { el.setSelectionRange(start + text.length, start + text.length); } else if (el.isContentEditable) { const sel = el.ownerDocument.getSelection(); sel.removeAllRanges(); const range = el.ownerDocument.createRange(); range.setStart(el.firstChild || el, start + text.length); range.collapse(true); sel.addRange(range); } dispatchInput(el, text); } /** 统一派发 beforeinput/input/change,保证框架同步 v-model/双向绑定 */ function dispatchInput(el, data) { /* beforeinput(某些编辑器会用) */ el.dispatchEvent(new InputEvent('beforeinput', { data, inputType: 'insertFromPaste', bubbles: true, cancelable: true })); /* input */ el.dispatchEvent(new InputEvent('input', { data, inputType: 'insertFromPaste', bubbles: true })); /* change(有需要就派,不影响正常撤销) */ el.dispatchEvent(new Event('change', { bubbles: true })); } /** 监听/递归注入同源 iframe(学习通作业答题区常见) */ function observeIframes(cb) { const handled = new WeakSet(); const tryHook = frame => { if (handled.has(frame)) return; handled.add(frame); try { cb(frame.contentDocument); } catch { /* 跨域 iframe 无权限 */ } }; /* 当前已存在的 iframe */ document.querySelectorAll('iframe').forEach(tryHook); /* 后续动态插入的 iframe */ new MutationObserver(muts => { muts.forEach(m => { m.addedNodes.forEach(node => { if (node.tagName === 'IFRAME') tryHook(node); }); }); }).observe(document.documentElement, { childList: true, subtree: true }); } })();