查看 Chrome 控制台是否打开

发布于 2024-12-10 10:21:00 字数 638 浏览 0 评论 0原文

我正在使用这个小脚本来查明 Firebug 是否打开:

if (window.console && window.console.firebug) {
    //is open
};

并且它运行良好。现在我搜索了半个小时,想找到一种方法来检测Google Chrome内置的Web开发者控制台是否打开,但我找不到任何提示。

这:

if (window.console && window.console.chrome) {
    //is open
};

不起作用。

编辑:

看来无法检测Chrome控制台是否打开。但是有一个“黑客”有效,但有一些缺点:

  • 当控制台未对接时将不起作用
  • 当控制台在页面加载时打开时将不起作用

所以,我现在要选择 Unsigned 的答案,但如果有人提出了一个绝妙的主意,欢迎他仍然回答,我改变选定的答案!谢谢!

I am using this little script to find out whether Firebug is open:

if (window.console && window.console.firebug) {
    //is open
};

And it works well. Now I was searching for half an hour to find a way to detect whether Google Chrome's built-in web developer console is open, but I couldn't find any hint.

This:

if (window.console && window.console.chrome) {
    //is open
};

doesn't work.

EDIT:

So it seems that it is not possible to detect whether the Chrome console is open. But there is a "hack" that works, with some drawbacks:

  • will not work when console is undocked
  • will not work when console is open on page load

So, I am gonna choose Unsigned´s answer for now, but if some1 comes up with a brilliant idea, he is welcome to still answer and I change the selected answer! Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(25

旧话新听 2024-12-17 10:21:00

将之前的答案留在下面以了解历史背景。

调试器(2022)

虽然不是万无一失,但另一个答案中的这种基于调试器的方法似乎仍然有效。

requestAnimationFrame(2019 年末)

目前 Muhammad Umer 的方法适用于 Chrome 78,并具有检测关闭和打开事件的附加优势。

function toString (2019)

归功于 Overcl9ck 对此答案的评论。用空函数对象替换正则表达式 /./ 仍然有效。

var devtools = function() {};
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

regex toString (2017-2018)

由于最初的询问者似乎不再存在,并且这仍然是公认的答案,因此添加此解决方案以提高可见性。功劳归于 Antonin Hildebrand评论 zswang答案 。该解决方案利用了这样一个事实:除非控制台打开,否则不会对记录的对象调用 toString()

var devtools = /./;
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

console.profiles (2013)

更新: console.profiles 已从 Chrome 中删除。该解决方案不再有效。

感谢 Paul Irish使用探查器发现 DevTools

function isInspectOpen() {
  console.profile();
  console.profileEnd();
  if (console.clear) {
    console.clear();
  }
  return console.profiles.length > 0;
}
function showIfInspectIsOpen() {
  alert(isInspectOpen());
}
<button onClick="showIfInspectIsOpen()">Is it open?</button>

window.innerHeight (2011)

这个其他选项可以检测页面加载后打开的停靠检查器,但无法检测未停靠的检查器,或者检查器是否在页面加载时已打开。也存在一些误报的可能性。

window.onresize = function() {
  if ((window.outerHeight - window.innerHeight) > 100) {
    alert('Docked inspector was opened');
  }
}

Leaving previous answers below for historical context.

Debugger (2022)

While not fool-proof, this debugger-based approach in another answer does appear to still work.

requestAnimationFrame (Late 2019)

Currently Muhammad Umer's approach works on Chrome 78, with the added advantage of detecting both close and open events.

function toString (2019)

Credit to Overcl9ck's comment on this answer. Replacing the regex /./ with an empty function object still works.

var devtools = function() {};
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

regex toString (2017-2018)

Since the original asker doesn't seem to be around anymore and this is still the accepted answer, adding this solution for visibility. Credit goes to Antonin Hildebrand's comment on zswang's answer. This solution takes advantage of the fact that toString() is not called on logged objects unless the console is open.

var devtools = /./;
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

console.profiles (2013)

Update: console.profiles has been removed from Chrome. This solution no longer works.

Thanks to Paul Irish for pointing out this solution from Discover DevTools, using the profiler:

function isInspectOpen() {
  console.profile();
  console.profileEnd();
  if (console.clear) {
    console.clear();
  }
  return console.profiles.length > 0;
}
function showIfInspectIsOpen() {
  alert(isInspectOpen());
}
<button onClick="showIfInspectIsOpen()">Is it open?</button>

window.innerHeight (2011)

This other option can detect the docked inspector being opened, after the page loads, but will not be able to detect an undocked inspector, or if the inspector was already open on page load. There is also some potential for false positives.

window.onresize = function() {
  if ((window.outerHeight - window.innerHeight) > 100) {
    alert('Docked inspector was opened');
  }
}

征棹 2024-12-17 10:21:00

Chrome 65+ (2018)

    r = /./
    r.toString = function () {
        document.title = '1'
    }
    console.log('%c', r);

演示:https://jsbin.com/cecuzeb/edit?output(2018年3月更新-16)

package: https://github.com/zswang/jdetects


当打印“Element” Chrome开发者时工具将得到它的 ID

    var checkStatus;
    
    var element = document.createElement('any');
    element.__defineGetter__('id', function() {
        checkStatus = 'on';
    });
    
    setInterval(function() {
        checkStatus = 'off';
        console.log(element);
        console.clear();
    }, 1000);

另一个版本(来自评论)

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function () {
    /* TODO */
    alert('囧');
  }
});
console.log('%cHello', element);

打印一个常规变量:

    var r = /./;
    r.toString = function() {
      document.title = 'on';
    };
    console.log(r);

Chrome 65+ (2018)

    r = /./
    r.toString = function () {
        document.title = '1'
    }
    console.log('%c', r);

demo: https://jsbin.com/cecuzeb/edit?output (Update at 2018-03-16)

package: https://github.com/zswang/jdetects


When printing “Element” Chrome developer tools will get its id

    var checkStatus;
    
    var element = document.createElement('any');
    element.__defineGetter__('id', function() {
        checkStatus = 'on';
    });
    
    setInterval(function() {
        checkStatus = 'off';
        console.log(element);
        console.clear();
    }, 1000);

Another version (from comments)

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function () {
    /* TODO */
    alert('囧');
  }
});
console.log('%cHello', element);

Print a regular variable:

    var r = /./;
    r.toString = function() {
      document.title = 'on';
    };
    console.log(r);

稍尽春風 2024-12-17 10:21:00

非常可靠的黑客

基本上在属性上设置一个吸气剂并将其记录在控制台中。显然,只有当控制台打开时才能访问该东西。

https://jsfiddle.net/gcdfs3oo/44/

var checkStatus;
var indicator = document.querySelector('#devtool-status');

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function() {
    checkStatus='on';
    throw new Error("Dev tools checker");
  }
});

requestAnimationFrame(function check() {
  checkStatus = 'off';
  console.dir(element);
  indicator.className  = checkStatus;
  requestAnimationFrame(check);
});
.on{
  color:limegreen;
}

.off{
  color:red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" />

<p>
  <ul>
    <li>
      dev toolbar open: icon is <span class="on">green</span>
    </li>
    <li>
      dev toolbar closed: icon is <span class="off">red</span>
    </li>
  </ul>
</p>
<div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div>
<br/>
<p><b>Now press F12 to see if this works for your browser!</b></p>

Very Reliable hack

Basically set a getter on property and log it in console. Apparently the thing gets accessed only when console is open.

https://jsfiddle.net/gcdfs3oo/44/

var checkStatus;
var indicator = document.querySelector('#devtool-status');

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function() {
    checkStatus='on';
    throw new Error("Dev tools checker");
  }
});

requestAnimationFrame(function check() {
  checkStatus = 'off';
  console.dir(element);
  indicator.className  = checkStatus;
  requestAnimationFrame(check);
});
.on{
  color:limegreen;
}

.off{
  color:red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" />

<p>
  <ul>
    <li>
      dev toolbar open: icon is <span class="on">green</span>
    </li>
    <li>
      dev toolbar closed: icon is <span class="off">red</span>
    </li>
  </ul>
</p>
<div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div>
<br/>
<p><b>Now press F12 to see if this works for your browser!</b></p>

那请放手 2024-12-17 10:21:00

我创建了 devtools-detect 来检测 DevTools 何时打开:

console.log('is DevTools open?', window.devtools.open);

您还可以监听一个事件:

window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
});

它在以下情况下不起作用: DevTools 已取消对接。但是,可以与 Chrome/Safari/Firefox DevTools 和 Firebug 配合使用。

I created devtools-detect which detects when DevTools is open:

console.log('is DevTools open?', window.devtools.open);

You can also listen to an event:

window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
});

It doesn't work when DevTools is undocked. However, works with the Chrome/Safari/Firefox DevTools and Firebug.

流年里的时光 2024-12-17 10:21:00
console.log(Object.defineProperties(new Error, {
  message: {get() {alert('Chrome/Firefox')}},
  toString: {value() {(new Error).stack.includes('toString@')&&alert('Safari')}}
}));

演示:https://jsbin.com/cateqeyono/edit?html,output

console.log(Object.defineProperties(new Error, {
  message: {get() {alert('Chrome/Firefox')}},
  toString: {value() {(new Error).stack.includes('toString@')&&alert('Safari')}}
}));

Demo: https://jsbin.com/cateqeyono/edit?html,output

樱娆 2024-12-17 10:21:00

-----更新:------

这是一个老问题,有许多很好的答案,并且在一段时间内发挥了作用。截至2022 年 9 月 5 日的当前最佳答案是 @starball https://stackoverflow.com/a/ 68494829/275333

顺便说一句,自从我发布它以来,我的答案仍然有效,只是让它始终准确有点困难。在关闭/打开控制台的情况下,单击我的演示中的“手动基准测试”链接,看看我的意思 - 总是有很大的差异。

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

我找到了一种方法来判断 Chrome 控制台是否打开。
它仍然是一个黑客,但它更加准确,并且无论控制台是否脱离底座都可以工作。

基本上,在控制台关闭的情况下运行此代码大约需要约 100 微秒,而在控制台打开时,则需要大约两倍的时间约 200 微秒。

console.log(1);
console.clear();

(1 毫秒 = 1000 微秒)

我已经写了更多关于它的内容 这里

演示位于此处


------ Update: ------

This is an old question with many great answers that worked for a while. The current best answer as of September 5th 2022 is by @starball https://stackoverflow.com/a/68494829/275333

Btw, my answer is still working the same since I've posted it, it's just a bit difficult to make it always accurate. Click on the "Manual Benchmark" link in my demo with the console closed/opened to see what I mean - there is always a big difference.

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

I found a way to tell if the Chrome Console is opened or not.
It’s still a hack but it’s way more accurate and will work whether the console is undocked or not.

Basically running this code with the console closed takes about ~100 microseconds and while the console is opened it takes about twice as much ~200 microseconds.

console.log(1);
console.clear();

(1 millisecond = 1000 microsecond)

I’ve written more about it here.

Demo is here.

套路撩心 2024-12-17 10:21:00

似乎有一些常见的解决方案类别:

  • 依靠在开发工具出现时检测屏幕大小的调整(当开发工具/控制台作为单独的窗口打开时,这不起作用)
  • 拦截某些可以调出开发工具的用户操作/console,例如右键菜单、F12、Ctrl+Shift+C 等。这不能涵盖页面无法检测到的浏览器镶边中的 UI 机制。
  • 将某些内容记录到控制台并依赖浏览器特定的行为来进行懒惰、精美的打印。从历史上看,这些似乎不太可靠,但它们很好而且简单。如果您希望它们在同一浏览会话中重复工作,您可能必须接受某种程度的控制台垃圾邮件。当用户在其开发工具控制台中禁用所有级别的日志记录然后刷新时,这不起作用,并且对于第一方执行上下文,这可以通过在用户脚本中重新定义控制台功能来阻止(对于第三方脚本执行上下文,我还没有弄清楚如何使用用户脚本来做到这一点)。
  • 将计时启发法与debugger 语句结合使用。棘手的部分是找到一种方法,使计时器不会被 事件循环队列,以及调试器语句暂停其运行的线程的执行这一事实。还有一个挑战是用户可以根据具体情况或禁用全部来禁用常规调试器语句。

以下是我使用调试器方法对特定问题的解决方案。 IE。当主线程在启发式计时器之间运行长任务时,避免误报,避免调试器语句阻塞主线程,并防止禁用调试器语句。注意:我认为没有办法阻止用户禁用所有调试器断点,这可能是最好的。

工作原理

当开发工具打开并且线程遇到调试语句时,Chrome 浏览器就会进入调试状态。

  1. 主线程向 webworker 线程发送消息。
  2. 工作线程以打开的心跳进行回复。
  3. 主线程通过启动计时器来响应关闭心跳。
  4. 工作线程的消息处理程序遇到调试器语句(可以选择包含在 eval 语句中以防止用户禁用它)。
  5. 如果 devtools 关闭,worker 将立即向主线程发送确认,主线程将得出 devtools 已关闭的结论。
  6. 如果打开 devtools,worker 将进入调试会话,主线程会注意到 Worker 没有足够快地响应,从而得出调试器必须打开的结论。主线程不会被工作线程的调试会话阻塞,但其超时响应将被事件队列中主线程中任何繁重的处理所阻塞。

我已经在 GitHub 上发布了一个参考实现(由我编写)这里< /a>、和一个演示在这里

优点

  • 与屏幕尺寸变化检测方法不同,当控制台位于单独的窗口中时,此方法有效。
  • 与用户操作拦截方法不同,无论用户操作如何打开控制台,这种方法都有效。
  • console.log 方法不同,这可以适用于控制台的多次打开-关闭,而不会向控制台发送大量消息。
  • 与基本的计时器调试器方法不同,检测不应因繁忙的线程(主线程或其他工作线程)而触发误报,调试器语句位于工作线程而不是主线程中,因此主线程不会被阻塞, eval-debugger 语句可防止禁用该特定调试器语句。

缺点

  • 用户可以禁用所有断点,这将禁用这种检测方法。
  • eval 包装的调试器语句在通过内容安全策略禁用 eval 的站点上不起作用,在这种情况下只能使用常规调试器语句。

There seem to be a few common classes of solutions:

  • Rely on detecting resizing of the screen when the devtools appear (this doesn't work when the devtools/console are opened as a separate window)
  • Intercept certain user actions that can bring up the devtools/console such as right click menu, F12, Ctrl+Shift+C, etc. This can't cover UI mechanisms that are in the browser chrome that aren't detectable by the page.
  • Log something to the console and rely on browser-specific behaviour for lazy, fancy printing. Historically, these seem to not be highly reliable, but they're nice and simple. If you want them to work repeatedly in the same browsing session, you'll probably have to accept some degree of console spam. This doesn't work when the user disables all levels of logging in their devtools console and then refreshes, and for first-party execution contexts, this can be thwarted by redefining the console functions in a userscript (for third-party script execution contexts, I haven't figured out how to do that with a userscript yet).
  • Use timing heuristics with the debugger statement. The tricky part is to find a way so that the timers can't get messed up by long running tasks in the event loop queue, and the fact that the debugger statement pauses execution of the thread it runs on. There's also the challenge that regular debugger statements can be disabled by the user on a case-by-case or disable-all basis.

What follows is my solution to the specific problems with the debugger approach. Ie. Avoid false positives when the main thread runs a long task between a heuristic timer, avoid the debugger statement from blocking the main thread, and prevent disabling the debugger statement. Note: I don't think there is a way to prevent a user from disabling all debugger breakpoints, and that is probably for the best.

How It Works

The Chrome browser enters debugging when devtools are open and a thread encounters a debugging statement.

  1. Main thread sends a message to a webworker thread.
  2. Worker thread replies with an opening heartbeat.
  3. Main thread reacts by starting a timer to expect the closing heartbeat.
  4. Worker thread's message handler encounters a debugger statement (optionally wrapped in an eval statement to prevent the user from disabling it).
  5. If devtools are closed, the worker will immediately send an acknowledgement to the main thread, and the main thread will conclude that devtools are closed.
  6. If devtools are opened, the worker will enter a debugging session, and the main thread will notice that the Worker has not responded sufficiently quickly, concluding that the debugger must be open. The main thread will not be blocked by the worker's debugging session, but it's timeout response will be blocked by any heavy processing in the main thread ahead of it in the event queue.

I've published a reference implementation (authored by me) here on GitHub, and a demo here.

Pros

  • Unlike screen-size-change-detection approaches, this works when the console is in a separate window.
  • Unlike user-action-interception approaches, this works regardless of what user action brings up the console.
  • Unlike console.log approaches, this can work for multiple open-closes of the console without spamming the console with messages.
  • Unlike basic timer-debugger approaches, the detection should never trigger false positives due to busy threads (main thread, or other workers), the debugger statement is in the worker instead of the main thread, so the main thread won't get blocked, and the eval-debugger statement prevents disabling that specific debugger statement.

Cons

  • The user can disable all breakpoints, which will disable this method of detection.
  • The eval-wrapped debugger statement won't work on sites which disable eval via their Content Security Policy, in which case only a regular debugger statement can be used.
被你宠の有点坏 2024-12-17 10:21:00

我发现新方法在 Chrome 89 上工作,

使用 console.profile、setInterval 和函数 toString

    var devtools = function() {};
    devtools.toString = function() {
        alert('NOPE!!')
        return '-'
    }

    setInterval(()=>{
        console.profile(devtools)
        console.profileEnd(devtools)
    }, 1000)

在 safari 中,它不起作用。

在 chrome 89 以下,我无法检查它是否有效。

I found new methods work at Chrome 89

Using console.profile, setInterval and function toString

    var devtools = function() {};
    devtools.toString = function() {
        alert('NOPE!!')
        return '-'
    }

    setInterval(()=>{
        console.profile(devtools)
        console.profileEnd(devtools)
    }, 1000)

In safari, it doesn't works.

Below chrome 89, i can't check whether it works.

枯寂 2024-12-17 10:21:00

Chrome 开发者工具实际上只是 WebKit 的 WebCore 库的一部分。所以这个问题适用于 Safari、Chrome 和任何其他 WebCore 消费者。

如果存在解决方案,它将基于 WebKit Web 检查器打开和关闭时 DOM 中的差异。不幸的是,这是一种先有鸡还是先有蛋的问题,因为当检查器关闭时我们无法使用检查器来观察 DOM。

您可以做的就是编写一些 JavaScript 来转储整个 DOM 树。然后在检查器打开时运行一次,在检查器关闭时运行一次。 DOM 中的任何差异都可能是 Web 检查器的副作用,我们可以使用它来测试用户是否正在检查。

这个链接对于 DOM 转储脚本来说是一个好的开始,但是您需要转储整个 DOMWindow 对象,而不仅仅是 document

更新:

看起来现在有办法做到这一点。查看 Chrome 检查器检测器

The Chrome developer tools is really just a part of WebKit's WebCore library. So this question applies to Safari, Chrome, and any other WebCore consumers.

If a solution exists, it'll be based off a difference in the DOM when the WebKit web inspector is open and when it's closed. Unfortunately, this is a kind of a chicken and egg problem because we can't use the inspector to observe the DOM when the inspector is closed.

What you may be able to do is write a bit of JavaScript to dump the entire DOM tree. Then run it once when the inspector is open, and once when the inspector is closed. Any difference in the DOM is probably a side-effect of the web inspector, and we may be able to use it to test if the user is inspecting or not.

This link is a good start for a DOM dumping script , but you'll want to dump the entire DOMWindow object, not just document.

Update:

Looks like there's a way to do this now. Check out Chrome Inspector Detector

吻风 2024-12-17 10:21:00

我写了一篇关于此的博客文章: http://nepjua.org/check -if-browser-console-is-open/

可以检测是否停靠或取消停靠

function isConsoleOpen() {  
  var startTime = new Date();
  debugger;
  var endTime = new Date();

  return endTime - startTime > 100;
}

$(function() {
  $(window).resize(function() {
    if(isConsoleOpen()) {
        alert("You're one sneaky dude, aren't you ?")
    }
  });
});

I wrote a blog post about this: http://nepjua.org/check-if-browser-console-is-open/

It can detect whether it's docked or undocked

function isConsoleOpen() {  
  var startTime = new Date();
  debugger;
  var endTime = new Date();

  return endTime - startTime > 100;
}

$(function() {
  $(window).resize(function() {
    if(isConsoleOpen()) {
        alert("You're one sneaky dude, aren't you ?")
    }
  });
});
层林尽染 2024-12-17 10:21:00

有一种棘手的方法可以检查它是否具有“选项卡”权限的扩展:

chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){
    if (tabs.length > 0){
        //devtools is open
    }
});

您也可以检查它是否为您的页面打开:

chrome.tabs.query({
    url: 'chrome-devtools://*/*',
    title: '*example.com/your/page*'
}, function(tabs){ ... })

There is a tricky way to check it for extensions with 'tabs' permission:

chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){
    if (tabs.length > 0){
        //devtools is open
    }
});

Also you can check if it open for your page:

chrome.tabs.query({
    url: 'chrome-devtools://*/*',
    title: '*example.com/your/page*'
}, function(tabs){ ... })
对不⑦ 2024-12-17 10:21:00

Muhammad Umer 的方法对我有用,而且我正在使用 React,所以我决定制作一个 hooks 解决方案:

const useConsoleOpen = () => {
  const [consoleOpen, setConsoleOpen] = useState(true)

  useEffect(() => {
    var checkStatus;

    var element = new Image();
    Object.defineProperty(element, "id", {
      get: function () {
        checkStatus = true;
        throw new Error("Dev tools checker");
      },
    });

    requestAnimationFrame(function check() {
      checkStatus = false;
      console.dir(element); //Don't delete this line!
      setConsoleOpen(checkStatus)
      requestAnimationFrame(check);
    });
  }, []);

  return consoleOpen
}

注意:当我搞乱了它,很长一段时间都不起作用,我不明白为什么。我已经删除了 console.dir(element); 这对于它的工作原理至关重要。我删除了大多数非描述性控制台操作,因为它们只是占用空间并且通常对于该功能来说不是必需的,所以这就是为什么它对我不起作用。

使用它:

import React from 'react'

const App = () => {
  const consoleOpen = useConsoleOpen()

  return (
    <div className="App">
      <h1>{"Console is " + (consoleOpen ? "Open" : "Closed")}</h1>
    </div>
  );
}

我希望这可以帮助任何使用 React 的人。如果有人想对此进行扩展,我希望能够在某个时刻停止无限循环(因为我没有在每个组件中使用它)并找到一种保持控制台干净的方法。

Muhammad Umer's approach worked for me, and I'm using React, so I decided to make a hooks solution:

const useConsoleOpen = () => {
  const [consoleOpen, setConsoleOpen] = useState(true)

  useEffect(() => {
    var checkStatus;

    var element = new Image();
    Object.defineProperty(element, "id", {
      get: function () {
        checkStatus = true;
        throw new Error("Dev tools checker");
      },
    });

    requestAnimationFrame(function check() {
      checkStatus = false;
      console.dir(element); //Don't delete this line!
      setConsoleOpen(checkStatus)
      requestAnimationFrame(check);
    });
  }, []);

  return consoleOpen
}

NOTE: When I was messing with it, it didn't work for the longest time and I couldn't figure out why. I had deleted console.dir(element); which is critical to how it works. I delete most non-descriptive console actions since they just take up space and aren't usually necessary to the function, so that was why it wasn't working for me.

To use it:

import React from 'react'

const App = () => {
  const consoleOpen = useConsoleOpen()

  return (
    <div className="App">
      <h1>{"Console is " + (consoleOpen ? "Open" : "Closed")}</h1>
    </div>
  );
}

I hope this helps anyone using React. If anyone wants to expand on this, I would like to be able stop the infinite loop at some point (since I don't use this in every component) and to find a way to keep the console clean.

锦上情书 2024-12-17 10:21:00
var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
    document.title = 'xxxxxx'
}});

setTimeout(()=>console.log(div),3000)

var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
    document.title = 'xxxxxx'
}});

setTimeout(()=>console.log(div),3000)

冷︶言冷语的世界 2024-12-17 10:21:00

Javascript 检测开发者工具控制台打开

从 2022 年 2 月 2 日起

  • Chrome 版本 97 开始工作(开发者工具已脱离/已停靠/键盘快捷键< /strong>)
  • Edge 版本 97(开发者工具脱离/停靠/键盘快捷键
  • FireFox 版本 96.0.03(开发者工具未固定/固定/键盘快捷键
  • Safari
  • FireBug检测(开发者工具)
// Prevent Right Click (Optional)
document.addEventListener('contextmenu', function(event) {
    event.preventDefault();
}, true); 

// DevTools Opened Script
function DevToolsOpened() {
    alert("Developer Tools Opened");
}

// Detect DevTools (Chrome/Edge)
// https://stackoverflow.com/a/67148898/9498503 (SeongJun)
var devtools = function() {};
devtools.toString = function() {
    DevToolsOpened();
    return '-';
}

setInterval(()=>{
    console.profile(devtools);
    console.profileEnd(devtools);
    if (console.clear) {
        console.clear();
    }
}, 1000);

// Detect DevTools (FireFox)
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
    // Detect Resize (Chrome/Firefox/Edge Works) but (Triggers on Zoom In Chrome and Zoom Out FireFox)
    window.onresize = function() {
        if ((window.outerHeight - window.innerHeight) > 100 || (window.outerWidth - window.innerWidth) > 100) {
            DevToolsOpened();
        }
    }
}

// Detect Fire Bug
if (window.console && window.console.firebug || console.assert(1) === '_firebugIgnore') {
    DevToolsOpened();
};

// Detect Key Shortcuts
// https://stackoverflow.com/a/65135979/9498503 (hlorand)
window.addEventListener('keydown', function(e) {
    if (
        // CMD + Alt + I (Chrome, Firefox, Safari)
        e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
        // CMD + Alt + J (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
        // CMD + Alt + C (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
        // CMD + Shift + C (Chrome)
        e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
        // Ctrl + Shift + J (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
        // Ctrl + Shift + C (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // F12 (Chome, Firefox, Edge)
        e.keyCode == 123 ||
        // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
        e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
        e.ctrlKey == true && e.keyCode == 85
    ) {
        DevToolsOpened();
    }
});

Javascript Detect Developer Tools Console Opening

Working from 2/2/2022

  • Chrome Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts)
  • Edge Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts)
  • FireFox Version 96.0.03 (Developer Tools Undocked/Docked/Keyboard shortcuts)
  • Safari ?
  • FireBug Detection (Developer Tools)

// Prevent Right Click (Optional)
document.addEventListener('contextmenu', function(event) {
    event.preventDefault();
}, true); 

// DevTools Opened Script
function DevToolsOpened() {
    alert("Developer Tools Opened");
}

// Detect DevTools (Chrome/Edge)
// https://stackoverflow.com/a/67148898/9498503 (SeongJun)
var devtools = function() {};
devtools.toString = function() {
    DevToolsOpened();
    return '-';
}

setInterval(()=>{
    console.profile(devtools);
    console.profileEnd(devtools);
    if (console.clear) {
        console.clear();
    }
}, 1000);

// Detect DevTools (FireFox)
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
    // Detect Resize (Chrome/Firefox/Edge Works) but (Triggers on Zoom In Chrome and Zoom Out FireFox)
    window.onresize = function() {
        if ((window.outerHeight - window.innerHeight) > 100 || (window.outerWidth - window.innerWidth) > 100) {
            DevToolsOpened();
        }
    }
}

// Detect Fire Bug
if (window.console && window.console.firebug || console.assert(1) === '_firebugIgnore') {
    DevToolsOpened();
};

// Detect Key Shortcuts
// https://stackoverflow.com/a/65135979/9498503 (hlorand)
window.addEventListener('keydown', function(e) {
    if (
        // CMD + Alt + I (Chrome, Firefox, Safari)
        e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
        // CMD + Alt + J (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
        // CMD + Alt + C (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
        // CMD + Shift + C (Chrome)
        e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
        // Ctrl + Shift + J (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
        // Ctrl + Shift + C (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // F12 (Chome, Firefox, Edge)
        e.keyCode == 123 ||
        // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
        e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
        e.ctrlKey == true && e.keyCode == 85
    ) {
        DevToolsOpened();
    }
});

淡水深流 2024-12-17 10:21:00

当浏览器的 DevTools 打开时,断点标记为“debugger;”只要您不停用断点,就会附加。

这是检查调试器是否启用的代码:

let workerUrl = 'data:application/javascript;base64,' + btoa(`
self.addEventListener('message', (e) => {
  if(e.data==='hello'){
    self.postMessage('hello');
  }
  debugger;
  self.postMessage('');
});
`);
function checkIfDebuggerEnabled() {
  return new Promise((resolve) => {
    let fulfilled = false;
    let worker = new Worker(workerUrl);
    worker.onmessage = (e) => {
      let data = e.data;
      if (data === 'hello') {
        setTimeout(() => {
          if (!fulfilled) {
            resolve(true);
            worker.terminate();
          }
        }, 1);
      } else {
        fulfilled = true;
        resolve(false);
        worker.terminate();
      }
    };
    worker.postMessage('hello');
  });
}

checkIfDebuggerEnabled().then((result) => {
  if (result) {
    alert('browser DevTools is open');
  }else{
    alert('browser DevTools is not open, unless you have deactivated breakpoints');
  }
});

注意:如果使用 CSP,则您需要将 worker-src 'unsafe-inline' 添加到 CSP 策略,或者将上面的工作线程源代码移动到 CSP 允许的资源并更改 workerUrl< /code> 到该资源。

When a browser's DevTools is open, breakpoints marked by 'debugger;' will be attached as long as you don't deactivate breakpoints.

So here is the code to check if debugger is enabled:

let workerUrl = 'data:application/javascript;base64,' + btoa(`
self.addEventListener('message', (e) => {
  if(e.data==='hello'){
    self.postMessage('hello');
  }
  debugger;
  self.postMessage('');
});
`);
function checkIfDebuggerEnabled() {
  return new Promise((resolve) => {
    let fulfilled = false;
    let worker = new Worker(workerUrl);
    worker.onmessage = (e) => {
      let data = e.data;
      if (data === 'hello') {
        setTimeout(() => {
          if (!fulfilled) {
            resolve(true);
            worker.terminate();
          }
        }, 1);
      } else {
        fulfilled = true;
        resolve(false);
        worker.terminate();
      }
    };
    worker.postMessage('hello');
  });
}

checkIfDebuggerEnabled().then((result) => {
  if (result) {
    alert('browser DevTools is open');
  }else{
    alert('browser DevTools is not open, unless you have deactivated breakpoints');
  }
});

Note: if CSP is used then you need either to add worker-src 'unsafe-inline' to CSP policy or to move worker source code above to a CSP-allowed resource and change workerUrl to that resource.

沉默的熊 2024-12-17 10:21:00

您也可以尝试以下操作: https://github.com/sindresorhus/devtools-detect

// check if it's open
console.log('is DevTools open?', window.devtools.open);
// check it's orientation, null if not open
console.log('and DevTools orientation?', window.devtools.orientation);

// get notified when it's opened/closed or orientation changes
window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
    console.log('and DevTools orientation?', e.detail.orientation);
});

Also you can try this: https://github.com/sindresorhus/devtools-detect

// check if it's open
console.log('is DevTools open?', window.devtools.open);
// check it's orientation, null if not open
console.log('and DevTools orientation?', window.devtools.orientation);

// get notified when it's opened/closed or orientation changes
window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
    console.log('and DevTools orientation?', e.detail.orientation);
});
蓝海 2024-12-17 10:21:00

如果您是在开发过程中做事情的开发人员。看看这个 Chrome 扩展程序。它可以帮助您检测 Chrome Devtoos 何时打开或关闭。

https://chrome.google.com/webstore/detail/devtools-status-Detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1

此扩展程序可帮助 Javascript 开发人员检测 Chrome Devtools 在当前情况下打开或关闭的情况页。
当 Chrome Devtools 关闭/打开时,扩展程序将在 window.document 元素上引发名为“devtoolsStatusChanged”的事件。

这是示例代码:

 function addEventListener(el, eventName, handler) {
    if (el.addEventListener) {
        el.addEventListener(eventName, handler);
    } else {
        el.attachEvent('on' + eventName,
            function() {
                handler.call(el);
            });
    }
}


// Add an event listener.
addEventListener(document, 'devtoolsStatusChanged', function(e) {
    if (e.detail === 'OPENED') {
        // Your code when Devtools opens
    } else {
        // Your code when Devtools Closed
    }
});

If you are developers who are doing stuff during development. Check out this Chrome extension. It helps you detect when Chrome Devtoos is opened or closed.

https://chrome.google.com/webstore/detail/devtools-status-detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1

This extension helps Javascript developers detect when Chrome Devtools is open or closed on current page.
When Chrome Devtools closes/opens, the extension will raise a event named 'devtoolsStatusChanged' on window.document element.

This is example code:

 function addEventListener(el, eventName, handler) {
    if (el.addEventListener) {
        el.addEventListener(eventName, handler);
    } else {
        el.attachEvent('on' + eventName,
            function() {
                handler.call(el);
            });
    }
}


// Add an event listener.
addEventListener(document, 'devtoolsStatusChanged', function(e) {
    if (e.detail === 'OPENED') {
        // Your code when Devtools opens
    } else {
        // Your code when Devtools Closed
    }
});
蓦然回首 2024-12-17 10:21:00

这里的一些答案将在 Chrome 65 中停止工作。这是一种定时攻击替代方案,在 Chrome 中运行得非常可靠,并且比 toString() 方法更难缓解。不幸的是,它在 Firefox 中并不那么可靠。

addEventListener("load", () => {

var baseline_measurements = [];
var measurements = 20;
var warmup_runs = 3;

const status = document.documentElement.appendChild(document.createTextNode("DevTools are closed"));
const junk = document.documentElement.insertBefore(document.createElement("div"), document.body);
junk.style.display = "none";
const junk_filler = new Array(1000).join("junk");
const fill_junk = () => {
  var i = 10000;
  while (i--) {
    junk.appendChild(document.createTextNode(junk_filler));
  }
};
const measure = () => {
    if (measurements) {
    const baseline_start = performance.now();
    fill_junk();
    baseline_measurements.push(performance.now() - baseline_start);
    junk.textContent = "";
    measurements--;
    setTimeout(measure, 0);
  } else {
    baseline_measurements = baseline_measurements.slice(warmup_runs); // exclude unoptimized runs
    const baseline = baseline_measurements.reduce((sum, el) => sum + el, 0) / baseline_measurements.length;

    setInterval(() => {
      const start = performance.now();
      fill_junk();
      const time = performance.now() - start;
      // in actual usage you would also check document.hasFocus()
      // as background tabs are throttled and get false positives
      status.data = "DevTools are " + (time > 1.77 * baseline ? "open" : "closed");
      junk.textContent = "";
    }, 1000);
  }
};

setTimeout(measure, 300);

});

Some answers here will stop working in Chrome 65. Here's a timing attack alternative that works pretty reliably in Chrome, and is much harder to mitigate than the toString() method. Unfortunately it's not that reliable in Firefox.

addEventListener("load", () => {

var baseline_measurements = [];
var measurements = 20;
var warmup_runs = 3;

const status = document.documentElement.appendChild(document.createTextNode("DevTools are closed"));
const junk = document.documentElement.insertBefore(document.createElement("div"), document.body);
junk.style.display = "none";
const junk_filler = new Array(1000).join("junk");
const fill_junk = () => {
  var i = 10000;
  while (i--) {
    junk.appendChild(document.createTextNode(junk_filler));
  }
};
const measure = () => {
    if (measurements) {
    const baseline_start = performance.now();
    fill_junk();
    baseline_measurements.push(performance.now() - baseline_start);
    junk.textContent = "";
    measurements--;
    setTimeout(measure, 0);
  } else {
    baseline_measurements = baseline_measurements.slice(warmup_runs); // exclude unoptimized runs
    const baseline = baseline_measurements.reduce((sum, el) => sum + el, 0) / baseline_measurements.length;

    setInterval(() => {
      const start = performance.now();
      fill_junk();
      const time = performance.now() - start;
      // in actual usage you would also check document.hasFocus()
      // as background tabs are throttled and get false positives
      status.data = "DevTools are " + (time > 1.77 * baseline ? "open" : "closed");
      junk.textContent = "";
    }, 1000);
  }
};

setTimeout(measure, 300);

});
与酒说心事 2024-12-17 10:21:00

至于 Chrome/77.0.3865.752019 版本不起作用。 toString 立即调用,无需打开 Inspector。

const resultEl = document.getElementById('result')
const detector = function () {}

detector.toString = function () {
	resultEl.innerText = 'Triggered'
}

console.log('%c', detector)
<div id="result">Not detected</div>

As for Chrome/77.0.3865.75 a version of 2019 not works. toString invokes immediately without Inspector opening.

const resultEl = document.getElementById('result')
const detector = function () {}

detector.toString = function () {
	resultEl.innerText = 'Triggered'
}

console.log('%c', detector)
<div id="result">Not detected</div>

终遇你 2024-12-17 10:21:00

使用包 dev-tools 中的这个包 isDevToolsOpened() 函数- 监控
除 Firefox 外,它在所有浏览器中都能按预期工作。

use this package isDevToolsOpened() function from the package dev-tools-monitor
which works as expected in all browsers except for firefox.

通知家属抬走 2024-12-17 10:21:00

您可以捕捉打开开发的事件。通过将事件侦听器添加到打开该工具的键盘快捷键来使用该工具。这不是“黑客”,而且 100% 的时间都有效。

它不会捕获的唯一情况是当用户用鼠标手动打开它时。所以这是一个“部分解决方案”,也许对某人有用。

<script>
function devToolsOpened(e){
    alert("devtools opened");
    // uncomment to prevent opening dev.tools:
    // e.preventDefault();
}
window.addEventListener('keydown', function(e) {

    if (
        // CMD + Alt + I (Chrome, Firefox, Safari)
        e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
        // CMD + Alt + J (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
        // CMD + Alt + C (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
        // CMD + Shift + C (Chrome)
        e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
        // Ctrl + Shift + J (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
        // Ctrl + Shift + C (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // F12 (Chome, Firefox, Edge)
        e.keyCode == 123 ||
        // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
        e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
        e.ctrlKey == true && e.keyCode == 85
        ){
            devToolsOpened(e);
    }
});
</script>

打开开发者工具的键盘快捷键:

You can catch the event of opening the dev. tools by adding event listeners to the keyboard shortcuts with which it opens. This is not a "hack" and it works 100% of the time.

The only case it won't catch is when the user opens it manually with mouse. So it is a "partial solution" perhaps it is useful for somebody.

<script>
function devToolsOpened(e){
    alert("devtools opened");
    // uncomment to prevent opening dev.tools:
    // e.preventDefault();
}
window.addEventListener('keydown', function(e) {

    if (
        // CMD + Alt + I (Chrome, Firefox, Safari)
        e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
        // CMD + Alt + J (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
        // CMD + Alt + C (Chrome)
        e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
        // CMD + Shift + C (Chrome)
        e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
        // Ctrl + Shift + J (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
        // Ctrl + Shift + C (Chrome, Edge)
        e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
        // F12 (Chome, Firefox, Edge)
        e.keyCode == 123 ||
        // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
        e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
        e.ctrlKey == true && e.keyCode == 85
        ){
            devToolsOpened(e);
    }
});
</script>

Keyboard shortcuts to open Developer Tools:

请别遗忘我 2024-12-17 10:21:00

计时解决方案(适用于对接和未对接)

它有点侵入性,但不如调试器陷阱那么多

var opened = false;
var lastTime = Date.now();
const interval = 50;
const threshold = 30;
setInterval(() => {

    let delta = Date.now() - lastTime;

    if (delta > interval + threshold) {
        document.title = "P3nis";
        opened = true;
    }

    lastTime = Date.now();

    if (!opened) {
        debugger;
    }

}, interval)

Timing solution (works for docked and undocked)

It is a bit intrusive but not as much as the debugger trap

var opened = false;
var lastTime = Date.now();
const interval = 50;
const threshold = 30;
setInterval(() => {

    let delta = Date.now() - lastTime;

    if (delta > interval + threshold) {
        document.title = "P3nis";
        opened = true;
    }

    lastTime = Date.now();

    if (!opened) {
        debugger;
    }

}, interval)

弥繁 2024-12-17 10:21:00

在 2024 年,如果 devtools 控制台打开,您始终可以检查显示哪些窗口属性。

目前这些是

['dir', 'dirxml', 'profile', 'profileEnd', 'table', 'keys', 'values', 'debug', 'undebug', 'monitor', 'unmonitor', 'inspect', 'copy', 'queryObjects', '$_', '$0', '$1', '$2', '$3', '$4', 'getEventListeners', 'getAccessibleName', 'getAccessibleRole', 'monitorEvents', 'unmonitorEvents', '

所以脚本是这样的:

if (window.profile) {
    console.log("devtools open!");
}

要验证它只需将其放入 setTimeout 并关闭控制台,然后再打开它并查看它打印的内容。

, '$', '$x']

所以脚本是这样的:

要验证它只需将其放入 setTimeout 并关闭控制台,然后再打开它并查看它打印的内容。

In 2024 you can always just check which window properties appear if devtools console is open.

Currently those are

['dir', 'dirxml', 'profile', 'profileEnd', 'table', 'keys', 'values', 'debug', 'undebug', 'monitor', 'unmonitor', 'inspect', 'copy', 'queryObjects', '$_', '$0', '$1', '$2', '$3', '$4', 'getEventListeners', 'getAccessibleName', 'getAccessibleRole', 'monitorEvents', 'unmonitorEvents', '

So the script is something like:

if (window.profile) {
    console.log("devtools open!");
}

To verify it just put it in setTimeout and close console and then open it back and see what it printed.

, '$', '$x']

So the script is something like:

To verify it just put it in setTimeout and close console and then open it back and see what it printed.

如痴如狂 2024-12-17 10:21:00

我意识到这不是一个通用的解决方案,但可能会对遇到类似情况的人有所帮助:

我在开发工具打开时遇到了 JavaScript 测试失败的问题。测试的代码监听 focusin 事件,并且这些事件仅在文档具有显式焦点时触发。

我的解决方法是在 !document.hasFocus() 时使规范失败并给出解释。

I realize this is not a general solution, but might help someone with a similiar case:

I had a problem with a JavaScript test failing while the DevTools are open. The tested code listened to focusin events, and those only fire if the document has explicit focus.

My workaround was to fail the spec with an explanation when !document.hasFocus().

若相惜即相离 2024-12-17 10:21:00

启用调试模式开/关功能的最佳方法是默认在 localStorage 中设置一个标志 'debugMode'='off' -

localStorage.setItem('debugMode', 'off');

然后,在 Local Storage 中更改它开发时手动打开浏览器 -

在此处输入图像描述

然后在代码中使用以下条件在“打开”时执行不同的操作 -

if(localStorage.getItem('debugMode') === 'on'){
   //do something 1
}else {
   //do something 2
}

Best way to have Debug-Mode on/off feature is to set a flag 'debugMode'='off' in localStorage by default -

localStorage.setItem('debugMode', 'off');

Then, change it in Local Storage of browser manually to 'on' while development -

enter image description here

Then use below condition in code to do differrent action if it's 'on' -

if(localStorage.getItem('debugMode') === 'on'){
   //do something 1
}else {
   //do something 2
}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文