Greasy Fork is available in English.
拦截抖音搜索页面的点击事件,将关键词拼接到搜索URL[/root/search/${keyword}?source=pc_click_hashtag_feed, /jingxuan/search/${keyword}?source=comment_related_search]并跳转
// ==UserScript==
// @name 抖音免登录搜索跳转
// @namespace http://tampermonkey.net/
// @version 1.0.0
// @description 拦截抖音搜索页面的点击事件,将关键词拼接到搜索URL[/root/search/${keyword}?source=pc_click_hashtag_feed, /jingxuan/search/${keyword}?source=comment_related_search]并跳转
// @author SHANGDISHIGE109
// @source https://github.com/SHANGDISHIGE109/douyin-notlogin-search
// @supportURL https://github.com/SHANGDISHIGE109/douyin-notlogin-search/issues
// @license MIT
// @match https://www.douyin.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=douyin.com
// @grant none
// @run-at document-end
// ==/UserScript==
(function() {
'use strict';
// 搜索按钮
function getSearchButton() {
return document.querySelector('button[data-e2e="searchbar-button"]');
}
// 搜索输入框
function getSearchInput() {
return document.querySelector('input[data-e2e="searchbar-input"]');
}
// 历史记录
function getSearchHistoryList() {
let container = document.querySelector('div[data-e2e="search-history-container"]');
if (!container) return [];
return Array.from(container.children);
}
// 猜你想搜
function getSearchGuessList() {
let container = document.querySelector('div[data-e2e="search-guess-container"]');
if (!container) return [];
return Array.from(container.children);
}
// 抖音热点
function getSearchHotList() {
let container = document.querySelector('div[data-e2e="search-hot-container"]');
if (!container) return [];
return Array.from(container.children);
}
// 搜索框输入联想建议
function getSearchSuggestList() {
return Array.from(document.querySelectorAll('div[data-isrichsug="0"]'));
}
// 获取文本内容的通用函数
function getTextFromElement(element) {
return element.textContent.trim();
}
// 统一的事件处理函数(避免重复创建函数实例)
const handleSearchItemClick = function(event) {
event.preventDefault();
event.stopPropagation();
const keyword = getTextFromElement(this);
redirectToSearch(keyword);
};
const handleSearchBtnClick = function(event) {
event.preventDefault();
event.stopPropagation();
const searchInput = getSearchInput();
const inputText = searchInput ? searchInput.value.trim() : '';
inputText && redirectToSearch(inputText);
};
const handleInputEnter = function(event) {
if (event.key === 'Enter' || event.keyCode === 13) {
event.preventDefault();
event.stopImmediatePropagation();
const searchInput = getSearchInput();
const inputText = searchInput ? searchInput.value.trim() : '';
inputText && redirectToSearch(inputText);
return false;
}
};
// 清理已有事件监听(关键:防止重复绑定)
function clearExistingListeners() {
const searchInput = getSearchInput();
searchInput.removeEventListener('keydown', handleInputEnter);
const searchBtn = getSearchButton();
searchBtn.removeEventListener('click', handleSearchBtnClick);
}
function clearExistingListenersDynamic() {
// 清理各类搜索项的点击事件
const allItems = [
...getSearchHistoryList(),
...getSearchGuessList(),
...getSearchHotList(),
...getSearchSuggestList(),
...oldDynamicElements
];
allItems.forEach(item => item.removeEventListener('click', handleSearchItemClick));
oldDynamicElements.length = 0;
}
// 拦截元素点击事件的函数
function interceptClickEvents() {
// 先清理旧监听,再绑定新监听
clearExistingListeners();
// 拦截搜索按钮点击
getSearchButton().addEventListener('click', handleSearchBtnClick, { once: false, passive: false });
// 拦截搜索输入框回车事件
getSearchInput().addEventListener('keydown', handleInputEnter, { once: false, passive: false });
interceptClickEventsDynamic();
}
function interceptClickEventsDynamic() {
// 这几个list是动态插入到DOM中的,需要在父容器上使用事件委托来监听点击事件,避免频繁绑定和解绑
globalObserver = new MutationObserver(function(mutations) {
let hasNewNodes = mutations.some(mut => mut.type === 'childList' && mut.addedNodes.length > 0);
if (hasNewNodes) {
// 延长一点时间,确保DOM完全渲染,减少无效执行
setTimeout(() => {
clearExistingListenersDynamic();
// 拦截历史记录/猜你想搜/热点项点击(优化:事件委托替代逐个绑定)
const bindItemEvents = (listGetter) => {
const items = listGetter();
items.forEach(item => {
item.addEventListener('click', handleSearchItemClick, { once: false, passive: false });
});
oldDynamicElements.push(...items);
};
bindItemEvents(getSearchHistoryList);
bindItemEvents(getSearchGuessList);
bindItemEvents(getSearchHotList);
bindItemEvents(getSearchSuggestList);
}, 80);
}
});
globalObserver.observe(getSearchButton().parentNode, {
childList: true,
subtree: true,
});
}
// 执行重定向到搜索结果页
function redirectToSearch(keyword) {
if (keyword && keyword.trim()) {
const encodedKeyword = encodeURIComponent(keyword.trim());
const targetUrl = `https://www.douyin.com/root/search/${keyword}?source=comment_related_search`;
window.location.href = targetUrl;
} else {
console.log("关键词为空,无法跳转");
}
}
// 初始化函数
function initializeSearchInterceptor() {
// 确保脚本的绑定事件在页面原生事件之后执行
const hasNativeClick = getSearchButton().onclick;
if (hasNativeClick) {
interceptClickEvents();
console.log('搜索拦截器已初始化');
}else {
const intervalId = setInterval(() => {
const hasNativeClick = getSearchButton().onclick;
if (hasNativeClick) {
clearInterval(intervalId);
interceptClickEvents();
console.log('搜索拦截器已初始化');
}
}, 2000);
intervalIds.push(intervalId);
}
}
// 检查并初始化搜索拦截器
function checkAndInitialize() {
// 检查搜索按钮和搜索输入框是否存在
if (getSearchButton() && getSearchInput()) {
// 元素存在,直接初始化
initializeSearchInterceptor();
} else {
// 如果没有找到搜索按钮或搜索输入框,则设置定时器每两秒检查一次
const intervalId = setInterval(function() {
if (getSearchButton() && getSearchInput()) {
clearInterval(intervalId);
// 元素已加载,执行初始化
initializeSearchInterceptor();
}
}, 2000);
intervalIds.push(intervalId);
}
}
// 销毁所有观察者和定时器
function destroyResources() {
// 销毁全局DOM观察者
if (globalObserver) {
globalObserver.disconnect();
globalObserver = null;
}
// 清理所有定时器
intervalIds.forEach(id => clearInterval(id));
intervalIds = [];
// 清理事件监听
clearExistingListeners();
clearExistingListenersDynamic();
console.log('已销毁所有资源');
}
// 只对非登录用户生效
if (document.querySelectorAll('.semi-button.semi-button-primary').length == 0) {
return;
}
let globalObserver = null;
let intervalIds = [];
let oldDynamicElements = [];
// 页面卸载时清理所有资源
window.addEventListener('beforeunload', destroyResources);
// 检查文档加载状态并相应处理
if (document.readyState === 'loading') {
// 文档仍在加载中,监听 DOMContentLoaded 事件
document.addEventListener('DOMContentLoaded', function() {
checkAndInitialize();
});
} else {
// 文档已加载完成,直接执行初始化
checkAndInitialize();
}
})();