如果任何网站则修改为 :@match *://*/*
// ==UserScript==
// @name 屏蔽包含特定关键词的商品(精确匹配独立关键词)
// @namespace http://tampermonkey.net/
// @version 1.2
// @description 自动隐藏标题中包含指定的独立关键词的商品
// @author Your Name
// @match https://shop.gigab2b.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// 创建设置面板
function createSettingsPanel() {
const panel = document.createElement('div');
panel.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
background: #ffffff;
padding: 20px;
border-radius: 10px;
z-index: 9999;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
max-width: 600px;
min-width: 400px;
transition: transform 0.3s ease;
`;
panel.innerHTML = `
<style>
.keyword-filter-panel h3 {
margin: 0 0 20px 0;
color: #333;
font-size: 18px;
border-bottom: 2px solid #f0f0f0;
padding-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.keyword-filter-panel input[type="text"] {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
transition: border-color 0.3s;
outline: none;
}
.keyword-filter-panel input[type="text"]:focus {
border-color: #4a90e2;
box-shadow: 0 0 0 2px rgba(74,144,226,0.2);
}
.keyword-filter-panel select {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 14px;
background-color: white;
cursor: pointer;
outline: none;
}
.keyword-filter-panel button {
padding: 8px 16px;
border: none;
border-radius: 6px;
font-size: 14px;
cursor: pointer;
transition: all 0.3s;
}
.keyword-filter-panel .primary-btn {
background: #4a90e2;
color: white;
}
.keyword-filter-panel .primary-btn:hover {
background: #357abd;
}
.keyword-filter-panel .secondary-btn {
background: #f5f5f5;
color: #666;
}
.keyword-filter-panel .secondary-btn:hover {
background: #e8e8e8;
}
.keyword-filter-panel .remove-btn {
background: #ff4d4f;
color: white;
padding: 6px 12px;
}
.keyword-filter-panel .remove-btn:hover {
background: #ff7875;
}
.keyword-filter-panel .rule-row {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 15px;
padding: 10px;
background: #f9f9f9;
border-radius: 8px;
}
.keyword-filter-panel .button-group {
margin-top: 20px;
display: flex;
gap: 10px;
justify-content: flex-end;
}
.minimize-btn {
background: none;
border: none;
color: #666;
cursor: pointer;
padding: 4px 8px;
font-size: 20px;
}
.minimize-btn:hover {
color: #333;
}
.panel-minimized {
transform: translateY(calc(100% - 40px));
}
.panel-header {
cursor: pointer;
user-select: none;
}
</style>
<div class="keyword-filter-panel">
<h3 class="panel-header">
<span>关键词过滤设置</span>
<button class="minimize-btn">_</button>
</h3>
<div id="keywordPairs"></div>
<div class="button-group">
<button id="addKeywordPair" class="secondary-btn">添加新规则</button>
<button id="saveSettings" class="primary-btn">保存设置</button>
</div>
</div>
`;
document.body.appendChild(panel);
return panel;
}
// 创建规则输入行
function createKeywordPairRow() {
const row = document.createElement('div');
row.className = 'rule-row';
row.innerHTML = `
<input type="text" placeholder="关键词A" style="width: 100px;">
<input type="text" placeholder="关键词B" style="width: 100px;">
<select>
<option value="AorB">包含A或B</option>
<option value="AnotB">包含A不含B</option>
<option value="AandB">同时包含A和B</option>
<option value="notA">不包含A</option>
</select>
<input type="text" placeholder="备注" style="width: 150px;">
<button class="remove-btn removeRule">删除</button>
`;
return row;
}
// 保存设置到localStorage
function saveSettings() {
const keywordPairs = [];
document.querySelectorAll('#keywordPairs > div').forEach(row => {
const inputs = row.querySelectorAll('input');
const select = row.querySelector('select');
if (inputs[0].value || inputs[1].value) {
keywordPairs.push({
keywordA: inputs[0].value,
keywordB: inputs[1].value,
condition: select.value,
note: inputs[2].value
});
}
});
localStorage.setItem('keywordFilterSettings', JSON.stringify(keywordPairs));
hideProductsByKeywords();
// 显示保存成功提示
const toast = document.createElement('div');
toast.style.cssText = `
position: fixed;
bottom: 80px;
right: 20px;
background: rgba(0,0,0,0.7);
color: white;
padding: 10px 20px;
border-radius: 4px;
z-index: 10000;
`;
toast.textContent = '设置已保存';
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 2000);
}
// 从localStorage加载设置
function loadSettings() {
const settings = localStorage.getItem('keywordFilterSettings');
return settings ? JSON.parse(settings) : [];
}
// 检查标题是否匹配条件
function checkTitle(title, config) {
if (!config.keywordA && !config.keywordB) return false;
const regexA = config.keywordA ? new RegExp(`\\b${config.keywordA}\\b`, 'i') : null;
const regexB = config.keywordB ? new RegExp(`\\b${config.keywordB}\\b`, 'i') : null;
switch(config.condition) {
case 'AorB':
return (regexA && regexA.test(title)) || (regexB && regexB.test(title));
case 'AnotB':
return (regexA && regexA.test(title)) && (!regexB || !regexB.test(title));
case 'AandB':
return (regexA && regexB && regexA.test(title) && regexB.test(title));
case 'notA':
return regexA && !regexA.test(title);
default:
return false;
}
}
// 处理按钮状态
function handleImportButton(button) {
if (button.textContent.trim() === 'Edit On import List') {
button.disabled = true;
button.style.opacity = '0.5';
button.style.cursor = 'not-allowed';
}
}
// 隐藏商品的主函数
function hideProductsByKeywords() {
const settings = loadSettings();
// 首先重置所有商品的显示状态
document.querySelectorAll('.card-outter-container').forEach(item => {
const productContainer = item.closest('div');
if (productContainer) {
productContainer.style.display = '';
}
});
// 如果没有规则,直接返回,保持所有商品显示
if (settings.length === 0) {
return;
}
// 然后根据规则隐藏符合条件的商品
document.querySelectorAll('.card-outter-container').forEach(item => {
const title = item.innerText.toLowerCase();
const productContainer = item.closest('div');
for (const config of settings) {
if (checkTitle(title, config)) {
if (productContainer) {
productContainer.style.display = 'none';
console.log(`已隐藏商品: ${title} (${config.note})`);
}
break;
}
}
});
// 处理所有导入按钮
document.querySelectorAll('.el-button.el-button--info.sh-button.product-btn').forEach(handleImportButton);
}
// 初始化设置面板
const panel = createSettingsPanel();
const keywordPairsContainer = panel.querySelector('#keywordPairs');
// 添加已保存的规则
const savedSettings = loadSettings();
savedSettings.forEach(setting => {
const row = createKeywordPairRow();
const inputs = row.querySelectorAll('input');
const select = row.querySelector('select');
inputs[0].value = setting.keywordA || '';
inputs[1].value = setting.keywordB || '';
select.value = setting.condition;
inputs[2].value = setting.note || '';
keywordPairsContainer.appendChild(row);
});
// 如果没有保存的规则,添加一个空行
if (savedSettings.length === 0) {
keywordPairsContainer.appendChild(createKeywordPairRow());
}
// 绑定事件
panel.querySelector('#addKeywordPair').addEventListener('click', () => {
keywordPairsContainer.appendChild(createKeywordPairRow());
});
panel.querySelector('#saveSettings').addEventListener('click', saveSettings);
// 删除规则的事件委托
keywordPairsContainer.addEventListener('click', (e) => {
if (e.target.classList.contains('removeRule')) {
e.target.parentElement.remove();
// 如果删除后没有规则了,添加一个空行
if (keywordPairsContainer.children.length === 0) {
keywordPairsContainer.appendChild(createKeywordPairRow());
}
saveSettings();
}
});
// 最小化功能
const minimizeBtn = panel.querySelector('.minimize-btn');
const panelHeader = panel.querySelector('.panel-header');
let isMinimized = false;
function toggleMinimize() {
isMinimized = !isMinimized;
panel.classList.toggle('panel-minimized');
minimizeBtn.textContent = isMinimized ? '□' : '_';
}
minimizeBtn.addEventListener('click', (e) => {
e.stopPropagation();
toggleMinimize();
});
panelHeader.addEventListener('click', () => {
if (isMinimized) {
toggleMinimize();
}
});
// 等待页面加载完成后执行脚本
window.addEventListener('load', hideProductsByKeywords);
// 处理动态加载的内容
const observer = new MutationObserver((mutations) => {
hideProductsByKeywords();
// 额外检查新加载的按钮
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === 1) { // 元素节点
const buttons = node.querySelectorAll('.el-button.el-button--info.sh-button.product-btn');
buttons.forEach(handleImportButton);
}
});
});
});
observer.observe(document.body, { childList: true, subtree: true });
})();