Greasy Fork

Greasy Fork is available in English.

密码可见性切换

在密码输入框旁添加可见性切换按钮

当前为 2025-07-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         密码可见性切换
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  在密码输入框旁添加可见性切换按钮
// @author       dangwa
// @match        *://*/*
// @grant        none
// @run-at       document-idle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 创建样式
    const style = document.createElement('style');
    style.textContent = `
        .tampermonkey-password-toggle {
            position: absolute;
            right: 8px;
            top: 50%;
            transform: translateY(-50%);
            cursor: pointer;
            color: #6B7280;
            z-index: 100;
            border: none;
            background: none;
        }
        .tampermonkey-password-toggle:hover {
            color: #4F46E5;
        }
        .password-input-wrapper {
            position: relative;
        }
    `;
    document.head.appendChild(style);

    // 为主密码输入框添加切换按钮
    function addToggleToPasswordInputs() {
        // 查找所有密码输入框
        const passwordInputs = document.querySelectorAll('input[type="password"]');

        passwordInputs.forEach(input => {
            // 检查是否已经添加了切换按钮
            if (input.parentElement.classList.contains('password-input-wrapper')) {
                return;
            }

            // 创建父容器
            const wrapper = document.createElement('div');
            wrapper.className = 'password-input-wrapper';

            // 将输入框放入容器
            input.parentNode.insertBefore(wrapper, input);
            wrapper.appendChild(input);

            // 创建切换按钮
            const toggleBtn = document.createElement('button');
            toggleBtn.type = 'button';
            toggleBtn.className = 'tampermonkey-password-toggle';
            toggleBtn.innerHTML = '<i class="fa fa-eye-slash"></i>';
            toggleBtn.setAttribute('aria-label', '切换密码可见性');

            // 添加 Font Awesome
            if (!document.querySelector('link[href*="font-awesome"]')) {
                const faLink = document.createElement('link');
                faLink.href = 'https://cdn.jsdelivr.net/npm/[email protected]/css/font-awesome.min.css';
                faLink.rel = 'stylesheet';
                document.head.appendChild(faLink);
            }

            // 添加按钮到容器
            wrapper.appendChild(toggleBtn);

            // 添加点击事件
            toggleBtn.addEventListener('click', function() {
                const type = input.getAttribute('type') === 'password' ? 'text' : 'password';
                input.setAttribute('type', type);

                // 切换图标
                const icon = toggleBtn.querySelector('i');
                if (type === 'text') {
                    icon.classList.remove('fa-eye-slash');
                    icon.classList.add('fa-eye');
                } else {
                    icon.classList.remove('fa-eye');
                    icon.classList.add('fa-eye-slash');
                }
            });
        });
    }

    // 初始添加切换按钮
    addToggleToPasswordInputs();

    // 监听DOM变化,处理动态加载的密码输入框
    const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                // 检查新增节点中是否有密码输入框
                for (let i = 0; i < mutation.addedNodes.length; i++) {
                    const node = mutation.addedNodes[i];
                    if (node.nodeType === 1) { // 元素节点
                        if (node.tagName === 'INPUT' && node.type === 'password') {
                            addToggleToPasswordInputs();
                            break;
                        } else {
                            // 检查子节点
                            const passwordInputs = node.querySelectorAll('input[type="password"]');
                            if (passwordInputs.length > 0) {
                                addToggleToPasswordInputs();
                                break;
                            }
                        }
                    }
                }
            }
        });
    });

    // 开始观察DOM变化
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });

    // 添加键盘快捷键支持(Ctrl+Shift+P 切换焦点密码框可见性)
    document.addEventListener('keydown', function(e) {
        if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 'p') {
            e.preventDefault();
            const activeElement = document.activeElement;
            if (activeElement && activeElement.tagName === 'INPUT' && activeElement.type === 'password') {
                // 找到对应的切换按钮并点击
                const wrapper = activeElement.parentElement;
                if (wrapper.classList.contains('password-input-wrapper')) {
                    const toggleBtn = wrapper.querySelector('.tampermonkey-password-toggle');
                    if (toggleBtn) {
                        toggleBtn.click();
                    }
                }
            }
        }
    });
})();