您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name 记录账号和密码
// @version 0.5.5
// @description 记录网站密码信息并自动填充
// @author niweizhuan
// @match *://*/*
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// @grant GM_addStyle
// @grant unsafeWindow
// @license MIT
// @namespace https://bbs.tampermonkey.net.cn/
// ==/UserScript==
(function() {
'use strict';
// 是否自动填充密码
var autoFillEnabled = true;
// 当前显示的页面索引
var currentPageIndex = 0;
// 显示区域的 DOM 元素
var displayAreaDiv;
// 当前网站域名
var currentDomain = getCurrentDomain();
//上下页按钮
var prevPageButton;
var nextPageButton;
//----------------------------------------------
// 获取当前网站的域名
function getCurrentDomain() {
return window.location.hostname;
}
// 获取存储
function getStoredData(domain) {
var data = GM_getValue(domain);
if (!data) return { accounts: [], priority: 0 }; // 如果没有数据,返回默认值
try {
data = JSON.parse(data);
} catch (error) {
alert("记录账号和密码:数据解析错误: “", error , "”已删除该条数据");
GM_deleteValue(domain); // 删除无效的存储数据
return { accounts: [], priority: 0 }; // 如果解析失败,返回默认值
}
// 处理旧版本数据(如果 data 是一个数组,则将其包装成包含 priority 的对象)
if (Array.isArray(data)) {
data = { accounts: data, priority: 0 };
}
// 确保优先级字段存在
if (typeof data.priority === 'undefined') {
data.priority = 0;
}
// 检查 accounts 的格式是否正确
if (!Array.isArray(data.accounts)) {
alert("记录账号和密码:accounts 格式不正确,已删除无效数据");
GM_deleteValue(domain); // 删除无效的存储数据
return { accounts: [], priority: data.priority }; // 格式不正确,返回默认 accounts
}
// 验证每个账户的格式,确保有 username 和 password
data.accounts = data.accounts.filter(account => {
if (typeof account.username === 'string' && typeof account.password === 'string') {
return true; // 格式正确,保留此账户
} else {
alert("记录账号和密码:账户数据格式错误,已删除: ", account);
GM_deleteValue(domain); // 删除无效的存储数据
return false; // 格式不正确,删除此账户
}
});
return data;
}
// 设置存储
function setStoredData(domain, data) {
GM_setValue(domain, JSON.stringify(data)); // 将数据存储为 JSON 字符串
}
//----------------------------------------------
// 创建按钮
function createButton(text, clickHandler) {
var button = document.createElement("button");
button.textContent = text;
button.style.cursor = "pointer";
button.style.backgroundColor = "transparent";
button.style.border = "none";
button.style.fontSize = "inherit";
button.style.color = "#333";
button.style.margin = "0 5px";
button.style.padding = "3px 5px";
button.onclick = clickHandler; // 绑定点击事件
button.ontouchend = clickHandler; // 兼容触摸事件
return button;
}
// 创建标签
function createLabel(text) {
var label = document.createElement("p");
label.textContent = text;
label.style.margin = "0"; // 无外边距
return label;
}
// 创建文字
function createValue(text) {
var value = document.createElement("p");
value.textContent = text;
value.style.margin = "0 5px"; // 设置左右间距
return value;
}
// 创建复制按钮
function createCopyButton(text, copyText) {
var button = document.createElement("button");
button.textContent = text;
button.style.cursor = "pointer";
button.style.backgroundColor = "transparent";
button.style.border = "none";
button.style.fontSize = "inherit";
button.style.color = "#333";
button.style.marginLeft = "5px"; // 左侧间距
button.style.padding = "3px 5px";
button.onclick = function() {
copyTextToClipboard(copyText, button); // 点击时复制文本
};
button.ontouchend = button.onclick; // 兼容触摸事件
return button;
}
// 复制文本
function copyTextToClipboard(text, button) {
navigator.clipboard.writeText(text).then(function() {
var originalText = button.textContent;
button.textContent = "已复制"; // 显示已复制状态
setTimeout(function() {
button.textContent = originalText; // 恢复按钮文本
}, 2000);
}).catch(function(err) {
console.error('复制失败:', err); // 复制失败时输出错误
});
}
//----------------------------------------------
// 显示界面初始化
function createDisplayArea() {
if (displayAreaDiv) {
document.body.removeChild(displayAreaDiv); // 移除现有显示区域
}
// 创建新的显示区域
displayAreaDiv = document.createElement("div");
displayAreaDiv.setAttribute("class", "passwordDisplayArea");
displayAreaDiv.style.display = "none"; // 初始隐藏
displayAreaDiv.style.position = "fixed";
displayAreaDiv.style.bottom = "70px";
displayAreaDiv.style.right = "20px";
displayAreaDiv.style.background = "skyblue";
displayAreaDiv.style.padding = "5px";
displayAreaDiv.style.border = "1px solid #ccc";
displayAreaDiv.style.zIndex = "2147483647"; // 确保显示在最上层
displayAreaDiv.style.maxWidth = "250px";
displayAreaDiv.style.fontSize = "14px";
var topButtons = document.createElement("div");
topButtons.style.display = "flex";
topButtons.style.justifyContent = "space-between";
topButtons.style.marginBottom = "5px";
// 添加关闭按钮
topButtons.appendChild(createButton("关闭", function() {
displayAreaDiv.style.display = "none"; // 隐藏显示区域
}));
// 添加编辑按钮
topButtons.appendChild(createButton("编辑", function() {
displayAreaDiv.style.display = "none"; // 隐藏显示区域
var storedData = getStoredData(currentDomain);
var accountInfo = storedData.accounts[currentPageIndex];
showEditPage(accountInfo); // 显示编辑页面
}));
// 添加新建按钮
topButtons.appendChild(createButton("新建", function() {
displayAreaDiv.style.display = "none"; // 隐藏显示区域
showNewPage(); // 显示新建页面
}));
displayAreaDiv.appendChild(topButtons);
// 显示当前网站域名
var domainContainer = document.createElement("div");
domainContainer.style.display = "flex";
domainContainer.style.alignItems = "center";
domainContainer.appendChild(createLabel("当前网站:"));
domainContainer.appendChild(createValue(currentDomain));
displayAreaDiv.appendChild(domainContainer);
// 创建账号信息容器
var accountContainer = document.createElement("div");
accountContainer.setAttribute("class", "accountContainer");
displayAreaDiv.appendChild(accountContainer);
// 创建页面控制按钮
var pageControls = document.createElement("div");
pageControls.style.display = "flex";
pageControls.style.justifyContent = "center";
pageControls.style.marginTop = "5px";
// 上一页按钮
prevPageButton = createButton("<", function() {
if (currentPageIndex > 0) {
currentPageIndex--; // 转到上一页
updateAccountDisplay();
}
});
pageControls.appendChild(prevPageButton);
// 显示当前页数的标签
var pageLabel = document.createElement("span");
pageLabel.setAttribute("class", "pageLabel");
pageLabel.style.margin = "0 10px";
pageControls.appendChild(pageLabel);
nextPageButton = createButton(">", function() {
var storedData = getStoredData(currentDomain);
if ((currentPageIndex + 1) < storedData.accounts.length) { // 确保不要超过帐户数量
currentPageIndex++; // 转到下一页
updateAccountDisplay();
}
});
pageControls.appendChild(nextPageButton);
displayAreaDiv.appendChild(pageControls); // 将页面控制按钮添加到显示区域
document.body.appendChild(displayAreaDiv); // 将显示区域添加到页面
updateAccountDisplay(); // 更新账号信息显示
}
// 显示页面
function showNewPage() {
var newDiv = document.createElement("div");
newDiv.setAttribute("class", "passwordEditArea");
newDiv.style.position = "fixed";
newDiv.style.bottom = "70px";
newDiv.style.right = "20px";
newDiv.style.background = "white";
newDiv.style.padding = "10px";
newDiv.style.border = "1px solid #ccc";
newDiv.style.zIndex = "2147483647"; // 确保显示在最上层
newDiv.style.maxWidth = "250px";
newDiv.style.fontSize = "14px";
newDiv.innerHTML = `
<p><label>账号:<input type="text" id="newUsername" style="width: 100%;"></label></p>
<p><label>密码:<input type="password" id="newPassword" style="width: 100%;"></label></p>
<div style="display: flex; justify-content: space-between; margin-top: 10px;">
<button id="cancelNew">取消</button>
<button id="saveNew">创建</button>
</div>
`;
document.body.appendChild(newDiv);
// 取消按钮事件处理程序
document.getElementById("cancelNew").onclick = function() {
document.body.removeChild(newDiv); // 关闭新建页面
};
// 保存按钮事件处理程序
document.getElementById("saveNew").onclick = function() {
var username = document.getElementById("newUsername").value.trim(); // 获取用户名
var password = document.getElementById("newPassword").value; // 获取密码
if (!validateInput(username, password)) { // 验证输入
return;
}
var storedData = getStoredData(currentDomain); // 获取存储数据
storedData.accounts.push({ username, password }); // 添加新账号信息
setStoredData(currentDomain, storedData); // 保存数据
document.body.removeChild(newDiv); // 关闭新建页面
currentPageIndex = 0; // 重置页面索引
updateAccountDisplay(); // 更新显示
};
}
// 无账号密码单独界面
function createNoInfoText(text) {
var noInfoText = document.createElement("p");
noInfoText.textContent = text;
noInfoText.style.margin = "0"; // 无外边距
return noInfoText;
}
//--------------------------------------------------------
// 编辑页面默认填充
function populateEditFieldsWithCurrentAccount() {
var storedData = getStoredData(currentDomain);
var currentAccount = storedData.accounts[currentPageIndex];
var usernameField = document.getElementById("editUsername");
var passwordField = document.getElementById("editPassword");
usernameField.value = currentAccount.username || ""; // 填充用户名
passwordField.value = currentAccount.password || ""; // 填充密码
}
// 更新显示界面账号
function updateAccountDisplay() {
var storedData = getStoredData(currentDomain);
var accountContainer = displayAreaDiv.querySelector(".accountContainer");
accountContainer.innerHTML = ""; // 清空当前显示内容
if (storedData.accounts.length > 0) {
var accountInfo = storedData.accounts[currentPageIndex];
var accountRow = document.createElement("div");
accountRow.style.display = "flex";
accountRow.style.justifyContent = "space-between";
accountRow.appendChild(createLabel("账号:")); // 账号标签
accountRow.appendChild(createCopyButton("复制", accountInfo.username || "[无账号信息]")); // 复制按钮
accountContainer.appendChild(accountRow);
accountContainer.appendChild(createValue(accountInfo.username || "[无账号信息]")); // 显示账号
var passwordRow = document.createElement("div");
passwordRow.style.display = "flex";
passwordRow.style.justifyContent = "space-between";
passwordRow.appendChild(createLabel("密码:")); // 密码标签
passwordRow.appendChild(createCopyButton("复制", accountInfo.password)); // 复制按钮
accountContainer.appendChild(passwordRow);
accountContainer.appendChild(createValue(accountInfo.password)); // 显示密码
// 新增:优先级复选框
var priorityRow = document.createElement("div");
priorityRow.style.display = "flex"; // 确保子元素按行排列
priorityRow.style.alignItems = "center"; // 垂直居中对齐
var priorityCheckbox = document.createElement("input");
priorityCheckbox.type = "checkbox";
// 设置复选框的初始状态
priorityCheckbox.checked = storedData.priority === currentPageIndex + 1;
priorityCheckbox.onchange = function() {
// 修改优先级
if (priorityCheckbox.checked) {
storedData.priority = currentPageIndex + 1;
} else {
storedData.priority = 0; // 取消勾选时,设置优先级为0
}
setStoredData(currentDomain, storedData); // 保存修改后的数据
updateAccountDisplay(); // 更新显示
};
priorityRow.appendChild(priorityCheckbox);
priorityRow.appendChild(createLabel("自动填入此页面")); // 优先级标签
accountContainer.appendChild(priorityRow);
fillCredentials(accountInfo.username, accountInfo.password); // 填充账号和密码
} else {
// 无账户信息情况
accountContainer.appendChild(createLabel("账号:"));
accountContainer.appendChild(createNoInfoText("[无账号信息]")); // 显示无账号信息
accountContainer.appendChild(createLabel("密码:"));
accountContainer.appendChild(createNoInfoText("[无密码信息]")); // 显示无密码信息
}
// 更新页码显示
displayAreaDiv.querySelector(".pageLabel").textContent = (currentPageIndex + 1) + "/" + Math.ceil(storedData.accounts.length);
prevPageButton.style.display = currentPageIndex > 0 ? "inline" : "none"; // 显示或隐藏上一页按钮
nextPageButton.style.display = (currentPageIndex + 1) < storedData.accounts.length ? "inline" : "none"; // 显示或隐藏下一页按钮
}
// 编辑页面
function showEditPage(accountInfo) {
var editDiv = document.createElement("div");
editDiv.setAttribute("class", "passwordEditArea");
editDiv.style.position = "fixed";
editDiv.style.bottom = "70px";
editDiv.style.right = "20px";
editDiv.style.background = "white";
editDiv.style.padding = "10px";
editDiv.style.border = "1px solid #ccc";
editDiv.style.zIndex = "2147483647"; // 确保显示在最上层
editDiv.style.maxWidth = "250px";
editDiv.style.fontSize = "14px";
editDiv.innerHTML = `
<p><label>账号:<input type="text" id="editUsername" style="width: 100%;" value="${accountInfo.username}"></label></p>
<p><label>密码:<input type="password" id="editPassword" style="width: 100%;" value="${accountInfo.password}"></label></p>
<div style="display: flex; justify-content: space-between; margin-top: 10px;">
<button id="cancelEdit">取消</button>
<button id="saveEdit">保存</button>
<button id="deleteEntry">删除</button>
</div>
`;
document.body.appendChild(editDiv); // 添加编辑页面
// 取消按钮事件处理程序
document.getElementById("cancelEdit").onclick = function() {
document.body.removeChild(editDiv); // 关闭编辑页面
};
// 保存按钮事件处理程序
document.getElementById("saveEdit").onclick = function() {
var username = document.getElementById("editUsername").value.trim(); // 获取用户名
var password = document.getElementById("editPassword").value; // 获取密码
if (!validateInput(username, password)) { // 验证输入
return;
}
var storedData = getStoredData(currentDomain); // 获取存储数据
storedData.accounts[currentPageIndex] = { username, password }; // 更新账号信息
setStoredData(currentDomain, storedData); // 保存数据
document.body.removeChild(editDiv); // 关闭编辑页面
currentPageIndex = 0; // 重置页面索引
updateAccountDisplay(); // 更新显示
};
// 删除按钮事件处理程序
document.getElementById("deleteEntry").onclick = function() {
var storedData = getStoredData(currentDomain); // 获取存储数据
// 检查当前条目是否为优先级条目
if (storedData.priority === currentPageIndex + 1) {
if (storedData.accounts.length > 1) {
storedData.priority = Math.max(1, currentPageIndex); // 设置优先级为当前条目的索引
} else {
storedData.priority = 0; // 删除唯一条目时,优先级重置为0
}
}
storedData.accounts.splice(currentPageIndex, 1); // 删除当前条目
setStoredData(currentDomain, storedData); // 保存修改后的数据
document.body.removeChild(editDiv); // 关闭编辑页面
currentPageIndex = 0; // 重置页面索引
updateAccountDisplay(); // 更新显示
};
}
// 验证输入
function validateInput(username, password) {
return true; // 暂时不使用详细的验证逻辑
}
//---------------------------------------------------
// 加载时匹配填充
function autoFillOnLoad() {
var storedData = getStoredData(currentDomain); // 获取存储数据
if (storedData.priority > 0) { // 如果优先级大于0,则填充优先级账号
var priorityAccount = storedData.accounts[storedData.priority - 1];
fillCredentials(priorityAccount.username, priorityAccount.password); // 自动填充账号和密码
}
}
// 自动填充账号密码
function fillCredentials(username, password) {
if (autoFillEnabled) { // 检查是否启用自动填充
var editAreaExists = document.querySelector(".passwordEditArea");
if (editAreaExists) {
return; // 如果编辑区域已存在,则不执行填充
}
var storedData = getStoredData(currentDomain); // 获取存储数据
if (storedData.priority > 0) { // 如果优先级大于0,则填充优先级账号
var priorityAccount = storedData.accounts[storedData.priority - 1];
username = priorityAccount.username;
password = priorityAccount.password;
}
// 填充输入框
var usernameField = document.querySelector("input[type='text'], input[type='email']");
var passwordField = document.querySelector("input[type='password']");
if (usernameField && passwordField) {
usernameField.value = username;
passwordField.value = password;
}
}
}
//----------------------------------------------
// 创建主按钮
function createControlButton() {
var controlButton = document.createElement("button");
controlButton.textContent = "显示账号和密码";
controlButton.style.position = "fixed";
controlButton.style.bottom = "10px";
controlButton.style.right = "10px";
controlButton.style.fontSize = "10px"; // 设置字体大小
controlButton.style.cursor = "pointer"; // 设置鼠标指针为手形
controlButton.style.zIndex = "2147483647"; // 确保显示在最上层
controlButton.onclick = function() {
// 检测模块是否存在
if (typeof GM_getValue === 'undefined' ||
typeof GM_setValue === 'undefined' ||
typeof GM_deleteValue === 'undefined' ||
typeof GM_listValues === 'undefined' ||
typeof GM_addStyle === 'undefined') {
// 提示用户,提前退出
confirm("记录账号和密码\n脚本出现错误:\n某些必要的模块不存在,无法继续执行操作。请确保浏览器包含本脚本需要的脚本支持库。");
return;
}
controlButton.onclick = function() {
if (!displayAreaDiv) {
createDisplayArea(); // 仅在首次点击时创建显示区域
}
displayAreaDiv.style.display = displayAreaDiv.style.display === "none" ? "block" : "none"; // 切换显示状态
if (displayAreaDiv.style.display === "block") {
updateAccountDisplay(); // 更新显示
}
};
document.body.appendChild(controlButton); // 添加控制按钮
};
document.body.appendChild(controlButton); // 添加控制按钮
}
//-----------------------------------------
createControlButton(); // 创建控制按钮
autoFillOnLoad(); // 页面加载时自动填充
})();