星号密码框显示明文密码

// ==UserScript==

目前為 2025-05-20 提交的版本,檢視 最新版本

// ==UserScript==
// @name        星号密码框显示明文密码
// @namespace   Violentmonkey Scripts
// @match       *://*/*
// @grant       none
// @version     1.1
// @license     MIT
// @author      -
// @description // ==UserScript==
// @name        星号密码框显示明文密码
// @namespace   Violentmonkey Scripts
// @match       *://*/*
// @grant       none
// @license     MIT
// @author      -
// @description # 密码可视交互功能说明
// 
// 本功能旨在提升用户在**输入或查看密码**时的交互体验。通过简单的 **鼠标悬停操作**,用户可临时查看密码框中的明文内容,从而增强使用的便捷性与准确性。
// 
// ---
// 
// ## ✨ 功能亮点
// 
// ### 🔍 密码可见性切换
// - 用户将鼠标悬停在密码输入框上时,系统**自动切换为明文显示模式**;
// - 鼠标移出后,自动恢复为密文状态;
// - 无需点击额外按钮,显著提升交互效率。
// 
// ### 🔄 兼容动态页面与懒加载场景
// - 支持异步加载或动态渲染的页面(如 AJAX 请求加载、React/Vue 等前端框架组件);
// - 确保在各类复杂前端架构中功能稳定运行。
// 
// ### ⚡ 轻量高效实现
// - 基于原生 JavaScript 实现,**不依赖任何第三方库**;
// - 占用资源少,性能优异;
// - 兼容主流浏览器:Chrome、Firefox、Edge 等。
// 
// ### 🔐 安全性保障
// - 显示密码仅限于客户端视觉呈现;
// - 数据传输与存储仍保持加密状态;
// - 不影响原有安全机制,保障用户信息安全。
// 
// ---
// 
// ## 🛠️ 技术实现简述
// 
// ### 基础结构
// - 使用 HTML 中 `<input type="password">` 作为基础输入元素。
// 
// ### 核心逻辑
// - 监听 `mouseover` 和 `mouseout` 事件;
// - 动态修改 `input.type` 属性,在 `"text"` 与 `"password"` 之间切换。
// 
// ### 动态兼容处理
// - 对于动态加载的内容:
//   - 可采用 **事件委托** 或 **MutationObserver** 检测 DOM 变化;
//   - 确保新加入的密码框也能正确绑定交互事件。
// 
// ---
// 
// 该功能设计简洁实用,兼顾用户体验与安全性,适用于多种 Web 应用场景。
// ==/UserScript==

(function() {
    'use strict';

    function bindPasswordEvents(input) {
        input.addEventListener('mouseenter', () => input.type = 'text');
        input.addEventListener('mouseleave', () => input.type = 'password');
    }

    function handleMutations(mutations) {
        debugger
        mutations.flatMap(e => [...e.addedNodes]).filter(node => node.nodeType === Node.ELEMENT_NODE).forEach(node => {
            if (node.tagName === 'INPUT' && node.type === 'password') {
                bindPasswordEvents(node);
            } else {
                // 检查其子节点
                node.querySelectorAll('input[type="password"]').forEach(bindPasswordEvents);
            }
        });
        // mutations.forEach(mutation => {
        //     mutation.addedNodes.forEach(node => {
        //         if (node.nodeType !== Node.ELEMENT_NODE) {
        //             return;
        //         }
        //         if (node.tagName === 'INPUT' && node.type === 'password') {
        //             bindPasswordEvents(node);
        //         } else {
        //             // 检查其子节点
        //             node.querySelectorAll('input[type="password"]').forEach(bindPasswordEvents);
        //         }
        //     });
        // });
    }

    const observer = new MutationObserver(handleMutations);
    const config = { childList: true, subtree: true };
    observer.observe(document, config);

    // 初始化现有密码输入框的事件绑定
    document.querySelectorAll('input[type="password"]').forEach(bindPasswordEvents);

})();
// ==/UserScript==

(function() {
    'use strict';

    function bindPasswordEvents(input) {
        input.addEventListener('mouseenter', () => input.type = 'text');
        input.addEventListener('mouseleave', () => input.type = 'password');
    }

    const observer = new MutationObserver((mutations)=>{
      mutations.flatMap(e => [...e.addedNodes]).filter(node => node.nodeType === Node.ELEMENT_NODE).forEach(node => {
            if (node.tagName === 'INPUT' && node.type === 'password') {
                bindPasswordEvents(node);
            } else {
                node.querySelectorAll('input[type="password"]').forEach(bindPasswordEvents);
            }
        });
    });
    observer.observe(document, { childList: true, subtree: true });

    // 初始化现有密码输入框的事件绑定
    document.querySelectorAll('input[type="password"]').forEach(bindPasswordEvents);

})();