在页面右下角添加一个悬浮面板,提供按“年份”和“引用数”排序的功能,两者均可切换升/降序。
当前为
// ==UserScript==
// @name 谷歌学术排序工具箱 (年份与引用数)
// @namespace http://tampermonkey.net/
// @version 2025.07.10.003
// @description 在页面右下角添加一个悬浮面板,提供按“年份”和“引用数”排序的功能,两者均可切换升/降序。
// @author heyue
// @match https://scholar.google.com/scholar?*
// @match https://sc.panda985.com/scholar?*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant none
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// --- 状态变量 ---
// true = 下次点击为降序, false = 下次点击为升序
let isNextYearSortDescending = true;
let isNextCiteSortDescending = true;
// --- 数据提取辅助函数 ---
/**
* 从单个结果节点中提取年份。
* @param {HTMLElement} node - 代表单个搜索结果的 .gs_or 元素。
* @returns {number} 提取到的四位年份数字,找不到则返回 0。
*/
function getYear(node) {
const authorLine = node.querySelector('.gs_a');
if (!authorLine) return 0;
const text = authorLine.textContent;
const yearMatch = text.match(/\b(19|20)\d{2}\b/);
return yearMatch ? parseInt(yearMatch[0], 10) : 0;
}
/**
* 从单个结果节点中提取引用次数。
* @param {HTMLElement} node - 代表单个搜索结果的 .gs_or 元素。
* @returns {number} 引用次数。
*/
function getCiteCount(node) {
// "被引用次数" 链接的文本
const citeLink = node.querySelector('a[href*="/scholar?cites"]');
if (!citeLink) return 0;
const citeText = citeLink.textContent;
const citeMatch = citeText.match(/\d+/);
return citeMatch ? parseInt(citeMatch[0], 10) : 0;
}
// --- 核心排序逻辑 ---
/**
* 对当前页面的搜索结果按指定键进行排序。
* @param {string} sortKey - 'year' 或 'cite',决定排序依据。
* @param {boolean} isDescending - true为降序,false为升序。
*/
function sortElements(sortKey, isDescending) {
const gsResCclMid = document.getElementById('gs_res_ccl_mid');
if (!gsResCclMid) {
console.error('错误:未找到结果容器 #gs_res_ccl_mid');
return;
}
const elementsWithValue = [...gsResCclMid.querySelectorAll('.gs_or')]
.map(node => {
const value = sortKey === 'year' ? getYear(node) : getCiteCount(node);
return { node, value };
});
elementsWithValue.sort((a, b) => {
return isDescending ? b.value - a.value : a.value - b.value;
});
gsResCclMid.innerHTML = '';
gsResCclMid.append(...elementsWithValue.map(item => item.node));
console.log(`当前页已按【${sortKey === 'year' ? '年份' : '引用数'}】进行【${isDescending ? '降序' : '升序'}】排序。`);
}
// --- UI 创建与交互 ---
/**
* 在页面上创建并添加排序工具面板。
*/
function createSortPanel() {
// 1. 创建面板容器
const panel = document.createElement('div');
panel.style.position = 'fixed';
panel.style.bottom = '20px';
panel.style.right = '20px';
panel.style.zIndex = '9999';
panel.style.backgroundColor = '#f8f9fa';
panel.style.border = '1px solid #dadce0';
panel.style.borderRadius = '8px';
panel.style.padding = '12px';
panel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.15)';
panel.style.display = 'flex';
panel.style.flexDirection = 'column';
panel.style.gap = '8px'; // 按钮之间的间距
// 2. 创建通用按钮样式的函数
const createButton = (text) => {
const button = document.createElement('button');
button.textContent = text;
button.style.backgroundColor = '#4285F4';
button.style.color = 'white';
button.style.border = 'none';
button.style.borderRadius = '4px';
button.style.padding = '8px 12px';
button.style.fontSize = '13px';
button.style.fontWeight = '500';
button.style.cursor = 'pointer';
button.style.textAlign = 'center';
button.style.transition = 'background-color 0.2s';
button.onmouseover = () => { button.style.backgroundColor = '#357ae8'; };
button.onmouseout = () => { button.style.backgroundColor = '#4285F4'; };
return button;
};
// 3. 创建年份排序按钮
const yearButton = createButton('');
const updateYearButtonText = () => {
yearButton.textContent = isNextYearSortDescending ? '按年份排序 (新→旧)' : '按年份排序 (旧→新)';
};
yearButton.addEventListener('click', () => {
sortElements('year', isNextYearSortDescending);
isNextYearSortDescending = !isNextYearSortDescending;
updateYearButtonText();
});
// 4. 创建引用数排序按钮
const citeButton = createButton('');
const updateCiteButtonText = () => {
citeButton.textContent = isNextCiteSortDescending ? '按引用数排序 (高→低)' : '按引用数排序 (低→高)';
};
citeButton.addEventListener('click', () => {
sortElements('cite', isNextCiteSortDescending);
isNextCiteSortDescending = !isNextCiteSortDescending;
updateCiteButtonText();
});
// 5. 初始化按钮文本并添加到面板
updateYearButtonText();
updateCiteButtonText();
panel.appendChild(yearButton);
panel.appendChild(citeButton);
// 6. 将面板添加到页面
document.body.appendChild(panel);
}
// 等待页面完全加载后再执行
if (document.readyState === 'complete') {
createSortPanel();
} else {
window.addEventListener('load', createSortPanel);
}
})();