支持PC 用于统计购物车域名列表,方便统计计算
// ==UserScript==
// @name Namecheap 购物车域名列表
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgODUgNDYuNTciPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjU5Ljk5IiB5MT0iNDQuMTYiIHgyPSI4MC4wMSIgeTI9IjEuMjMiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNkNDIwMmMiLz48c3RvcCBvZmZzZXQ9IjAuMSIgc3RvcC1jb2xvcj0iI2RjM2QyOSIgc3RvcC1vcGFjaXR5PSIwLjc5Ii8+PHN0b3Agb2Zmc2V0PSIwLjIiIHN0b3AtY29sb3I9IiNlNDU5MjYiIHN0b3Atb3BhY2l0eT0iMC41OCIvPjxzdG9wIG9mZnNldD0iMC4zMiIgc3RvcC1jb2xvcj0iI2VhNzEyMyIgc3RvcC1vcGFjaXR5PSIwLjQiLz48c3RvcCBvZmZzZXQ9IjAuNDMiIHN0b3AtY29sb3I9IiNmMDg1MjEiIHN0b3Atb3BhY2l0eT0iMC4yNSIvPjxzdG9wIG9mZnNldD0iMC41NSIgc3RvcC1jb2xvcj0iI2Y0OTQxZiIgc3RvcC1vcGFjaXR5PSIwLjE0Ii8+PHN0b3Agb2Zmc2V0PSIwLjY4IiBzdG9wLWNvbG9yPSIjZjc5ZjFlIiBzdG9wLW9wYWNpdHk9IjAuMDYiLz48c3RvcCBvZmZzZXQ9IjAuODIiIHN0b3AtY29sb3I9IiNmOGE1MWQiIHN0b3Atb3BhY2l0eT0iMC4wMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2Y5YTcxZCIgc3RvcC1vcGFjaXR5PSIwIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9ImIiIHgxPSIxNzc3LjQ4IiB5MT0iMTA0OC43NiIgeDI9IjE3OTcuNSIgeTI9IjEwMDUuODMiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTgwMy41IDEwNTIuNikgcm90YXRlKDE4MCkiIHhsaW5rOmhyZWY9IiNhIi8+PC9kZWZzPjx0aXRsZT5jbi1sb2dvPC90aXRsZT48cGF0aCBkPSJNNzcuMTcuNzFhNy44Nyw3Ljg3LDAsMCwwLTYuODgsNC4wNWwtLjE2LjMzTDY0LDE3LjI1bC03LjgsMTUuMzcsNS4xMSwxMC4wNy4yOC41NUE4LDgsMCwwLDAsNjUsNDYuNDdhOC4wNSw4LjA1LDAsMCwwLDMuNDEtMy4yM2wuMjgtLjU1TDg0LDEyLjQ4bC4zNy0uNzNhNy44Niw3Ljg2LDAsMCwwLTcuMTktMTFaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMSAtMC43MSkiIGZpbGw9IiNmZjUxMDAiLz48cGF0aCBkPSJNMjkuODUsMTUuMzRsLTUuMS0xMC0uMjgtLjU1YTcuODksNy44OSwwLDAsMC0zLjQtMy4yMiw3LjkyLDcuOTIsMCwwLDAtMy40LDMuMjFsLS4yOS41NkwyLjA1LDM1LjUybC0uMzcuNzJhNy44Niw3Ljg2LDAsMCwwLDE0LjA2LDdsLjE3LS4zMiw2LjE3LTEyLjE2TDI5Ljg3LDE1LjRaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMSAtMC43MSkiIGZpbGw9IiNmZjUxMDAiLz48cGF0aCBkPSJNNzcuMTUuNzFhNy44Niw3Ljg2LDAsMCwwLTYuODcsNC4wNWwtLjE3LjMzTDYzLjk0LDE3LjI1LDU2LjEzLDMyLjYybDUuMTIsMTAuMDcuMjguNTVhNy45NCw3Ljk0LDAsMCwwLDMuNDEsMy4yMyw3Ljk0LDcuOTQsMCwwLDAsMy40MS0zLjIzbC4yOS0uNTVMODQsMTIuNDhsLjM2LS43M2E3Ljg2LDcuODYsMCwwLDAtNy4xOS0xMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xIC0wLjcxKSIgZmlsbD0idXJsKCNhKSIvPjxwYXRoIGQ9Ik04Ljg2LDQ3LjI5YTcuODYsNy44NiwwLDAsMCw2Ljg3LTRsLjE3LS4zMyw2LjE4LTEyLjE2LDcuOC0xNS4zN0wyNC43Nyw1LjMxbC0uMjgtLjU1YTgsOCwwLDAsMC0zLjQyLTMuMjMsOCw4LDAsMCwwLTMuNDEsMy4yM2wtLjI4LjU1TDIsMzUuNTJsLS4zNy43M2E3Ljg2LDcuODYsMCwwLDAsNy4xOSwxMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0xIC0wLjcxKSIgZmlsbD0idXJsKCNiKSIvPjxwYXRoIGQ9Ik0yOS44NSwxNS4zNGwtNS4xLTEwLS4yOC0uNTVhNy45NCw3Ljk0LDAsMCwwLTMuNDEtMy4yM0E4LjMxLDguMzEsMCwwLDEsMjIuNTUsMWE4LjE2LDguMTYsMCwwLDEsMi0uMjVIMzUuMjNhNy45Miw3LjkyLDAsMCwxLDYuODYsNGwuMjguNTVMNTYuMTgsMzIuNjZsNS4wOSwxMCwuMjguNTVBOCw4LDAsMCwwLDY1LDQ2LjQ3YTguMDUsOC4wNSwwLDAsMS0zLjQ3LjgxSDUwLjc5YTcuOTEsNy45MSwwLDAsMS02Ljg1LTRsLS4yOS0uNTVaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMSAtMC43MSkiIGZpbGw9IiNmZjhjNDQiLz48L3N2Zz4K
// @match *://www.namecheap.com/shoppingcart/*
// @grant GM_addStyle
// @version 2025.7.25
// @author ayersltd
// @description 支持PC 用于统计购物车域名列表,方便统计计算
// @license GPL-3.0-only
// @require https://cdnjs.cloudflare.com/ajax/libs/fuse.js/6.6.2/fuse.min.js
// @namespace https://greasyfork.org/users/1497923
// ==/UserScript==
(function() {
// 添加自定义样式
GM_addStyle(`
#domainListPanel {
position: fixed;
top: 50px;
right: 50px;
background: #fff;
border: 1px solid #e1e1e1;
border-radius: 8px;
box-shadow: 0 8px 30px rgba(0,0,0,0.12);
z-index: 99999;
width: 380px;
max-height: 85vh;
display: flex;
flex-direction: column;
font-family: 'Segoe UI', system-ui, sans-serif;
}
.panel-header {
padding: 16px;
background: #f8f8f8;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 8px 8px 0 0;
}
.panel-title {
font-weight: 600;
font-size: 16px;
color: #333;
margin: 0;
}
.panel-close {
background: none;
border: none;
font-size: 18px;
cursor: pointer;
color: #888;
}
.panel-actions {
padding: 12px 16px;
display: flex;
gap: 8px;
border-bottom: 1px solid #eee;
}
.search-box {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.action-btn {
padding: 6px 12px;
background: #f2f2f2;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
}
.action-btn:hover {
background: #e8e8e8;
}
.panel-content {
flex: 1;
overflow: auto;
padding: 0;
}
.domain-list {
list-style: none;
padding: 0;
margin: 0;
}
.domain-item {
padding: 12px 16px;
border-bottom: 1px solid #f5f5f5;
font-size: 14px;
display: flex;
justify-content: space-between;
align-items: center;
}
.domain-name {
word-break: break-all;
padding-right: 10px;
}
.domain-count {
background: #f0f5ff;
color: #2f5bea;
border-radius: 12px;
padding: 3px 8px;
font-size: 12px;
font-weight: 500;
min-width: 60px;
text-align: center;
}
.panel-footer {
padding: 12px 16px;
text-align: center;
background: #f8f8f8;
border-top: 1px solid #eee;
font-size: 13px;
color: #666;
border-radius: 0 0 8px 8px;
}
.view-toggle {
display: flex;
gap: 8px;
margin-bottom: 12px;
justify-content: center;
}
.view-option {
padding: 4px 12px;
border-radius: 15px;
background: #f0f0f0;
cursor: pointer;
font-size: 12px;
}
.view-option.active {
background: #e1ecff;
color: #2f5bea;
font-weight: 500;
}
.section-title {
padding: 10px 16px;
background: #f8f8f8;
font-weight: 600;
font-size: 13px;
color: #666;
border-bottom: 1px solid #eee;
position: sticky;
top: 0;
}
.tld-group {
margin-bottom: 15px;
}
`);
// 主功能
function initDomainList() {
// 创建面板容器
const panel = document.createElement('div');
panel.id = 'domainListPanel';
// 添加头部
panel.innerHTML = `
<div class="panel-header">
<h3 class="panel-title">域名购物车</h3>
<button class="panel-close">×</button>
</div>
<div class="panel-actions">
<input type="text" class="search-box" placeholder="搜索域名..." id="domainSearch">
<button class="action-btn" id="copyAllBtn">复制所有</button>
</div>
<div class="view-toggle">
<span class="view-option active" data-view="list">列表视图</span>
<span class="view-option" data-view="tld">按后缀分组</span>
</div>
<div class="panel-content">
<ul class="domain-list" id="domainList"></ul>
</div>
<div class="panel-footer">
<div class="domain-count">共计: <span id="totalCount">0</span> 个域名</div>
</div>
`;
document.body.appendChild(panel);
// 获取元素引用
const domainList = document.getElementById('domainList');
const searchBox = document.getElementById('domainSearch');
const copyAllBtn = document.getElementById('copyAllBtn');
const totalCount = document.getElementById('totalCount');
const closeBtn = document.querySelector('.panel-close');
const viewOptions = document.querySelectorAll('.view-option');
let allDomains = [];
let currentView = 'list';
// 关闭面板
closeBtn.addEventListener('click', () => {
panel.style.display = 'none';
});
// 视图切换
viewOptions.forEach(option => {
option.addEventListener('click', () => {
viewOptions.forEach(o => o.classList.remove('active'));
option.classList.add('active');
currentView = option.dataset.view;
updateDomainListView(allDomains);
});
});
// 搜索功能
searchBox.addEventListener('input', (e) => {
const keyword = e.target.value.trim().toLowerCase();
if (!keyword) {
updateDomainListView(allDomains);
return;
}
const filteredDomains = allDomains.filter(domain =>
domain.toLowerCase().includes(keyword)
);
updateDomainListView(filteredDomains);
});
// 复制所有域名
copyAllBtn.addEventListener('click', () => {
if (allDomains.length === 0) return;
const domainsText = allDomains.join('\n');
navigator.clipboard.writeText(domainsText).then(() => {
showNotification(`已复制 ${allDomains.length} 个域名到剪贴板`);
});
});
// 拖拽功能
initPanelDrag(panel);
// 初始加载域名
setTimeout(loadDomainList, 1500);
// 加载域名列表
function loadDomainList() {
const domains = [];
// 使用XPath查找所有域名文本节点
const xpath = "//div[@data-e2e-id='sc-product-container']//p[@data-e2e-id='sc-product-sub-title']/text()";
const result = document.evaluate(
xpath,
document,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
// 提取域名文本
for (let i = 0; i < result.snapshotLength; i++) {
const node = result.snapshotItem(i);
const domain = node.nodeValue.trim();
if (domain) domains.push(domain);
}
if (domains.length === 0) {
showNotification("未找到有效域名");
return;
}
allDomains = domains;
totalCount.textContent = domains.length;
updateDomainListView(domains);
}
// 更新域名列表视图
function updateDomainListView(domains) {
domainList.innerHTML = '';
if (domains.length === 0) {
domainList.innerHTML = '<div class="domain-item">未找到匹配域名</div>';
return;
}
if (currentView === 'tld') {
renderTLDGroupView(domains);
} else {
renderListView(domains);
}
}
// 渲染列表视图
function renderListView(domains) {
domains.forEach((domain, index) => {
const li = document.createElement('li');
li.className = 'domain-item';
li.innerHTML = `
<span class="domain-name">${index + 1}. ${domain}</span>
`;
domainList.appendChild(li);
});
}
// 渲染TLD分组视图
function renderTLDGroupView(domains) {
// 按TLD分组
const groups = {};
domains.forEach(domain => {
const tld = domain.split('.').pop();
if (!groups[tld]) groups[tld] = [];
groups[tld].push(domain);
});
// 渲染分组视图
Object.entries(groups).forEach(([tld, domainListInGroup]) => {
const section = document.createElement('div');
section.className = 'tld-group';
section.innerHTML = `
<div class="section-title">.${tld} (${domainListInGroup.length})</div>
`;
const ul = document.createElement('ul');
ul.className = 'domain-list';
domainListInGroup.forEach((domain, index) => {
const li = document.createElement('li');
li.className = 'domain-item';
li.innerHTML = `<span class="domain-name">${index + 1}. ${domain}</span>`;
ul.appendChild(li);
});
section.appendChild(ul);
domainList.appendChild(section);
});
}
}
// 拖拽功能
function initPanelDrag(panel) {
let isDragging = false;
let offsetX, offsetY;
const header = panel.querySelector('.panel-header');
header.addEventListener('mousedown', (e) => {
isDragging = true;
offsetX = e.clientX - panel.getBoundingClientRect().left;
offsetY = e.clientY - panel.getBoundingClientRect().top;
});
document.addEventListener('mousemove', (e) => {
if (isDragging) {
panel.style.left = `${e.clientX - offsetX}px`;
panel.style.top = `${e.clientY - offsetY}px`;
}
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
}
// 显示通知
function showNotification(message) {
const notification = document.createElement('div');
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: #4caf50;
color: white;
padding: 12px 24px;
border-radius: 4px;
z-index: 10000;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
animation: fadeInOut 3s ease;
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
// 延迟初始化,确保页面加载完成
if (document.readyState === 'complete') {
initDomainList();
} else {
window.addEventListener('load', initDomainList);
}
})();