您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在知乎问题标题旁添加标记为已读的按钮,并允许导出和导入已读数据
// ==UserScript== // @name 知乎问题标记已读 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 在知乎问题标题旁添加标记为已读的按钮,并允许导出和导入已读数据 // @author shaoz // @match *://*.zhihu.com/* // @grant none // @run-at document-end // @license MIT // ==/UserScript== (function() { 'use strict'; function addButton(element, questionId) { if (element.querySelector('.mark-as-read')) { return; // 避免重复添加按钮 } const isRead = localStorage.getItem('read_' + questionId) === 'true'; const readButton = document.createElement('button'); readButton.className = 'mark-as-read'; readButton.innerText = isRead ? '已读' : '标记为已读'; readButton.style.marginLeft = '10px'; readButton.style.color = '#000000'; readButton.style.backgroundColor = isRead ? '#4CAF50' : '#e0e0e0'; readButton.style.border = '1px solid #dcdcdc'; readButton.style.padding = '1px 4px'; readButton.style.fontSize = '12px'; readButton.style.fontWeight = 'normal'; readButton.style.cursor = 'pointer'; readButton.onclick = function() { const currentState = localStorage.getItem('read_' + questionId) === 'true'; localStorage.setItem('read_' + questionId, !currentState); this.style.backgroundColor = currentState ? '#e0e0e0' : '#4CAF50'; this.innerText = currentState ? '标记为已读' : '已读'; }; // 使按钮在标题的同一行显示 element.style.display = 'inline-flex'; element.style.alignItems = 'center'; element.appendChild(readButton); } function processPage() { // 尝试从详情页获取问题ID const dataElement = document.getElementById('js-initialData'); if (dataElement) { try { const initialData = JSON.parse(dataElement.textContent); const questionId = initialData.initialState.entities.questions[Object.keys(initialData.initialState.entities.questions)[0]].id; const titleElement = document.querySelector('.QuestionHeader-title'); if (titleElement) { addButton(titleElement, questionId); } } catch (e) { console.error('Error parsing initial data:', e); } } // 主页或搜索结果页 document.querySelectorAll('.ContentItem-title, .SearchResult-Card .ContentItem-title').forEach(title => { const linkElement = title.querySelector('a[href*="/question/"]'); if (linkElement) { const href = linkElement.getAttribute('href'); const match = href.match(/question\/(\d+)/); if (match) { addButton(title, match[1]); } } }); } function exportReadData() { const data = {}; for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); if (key.startsWith('read_')) { data[key] = localStorage.getItem(key); } } const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'read_data.json'; a.click(); URL.revokeObjectURL(url); } function importReadData() { const input = document.createElement('input'); input.type = 'file'; input.accept = 'application/json'; input.onchange = function(event) { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = function() { try { const importedData = JSON.parse(reader.result); for (const [key, value] of Object.entries(importedData)) { if (key.startsWith('read_') && localStorage.getItem(key) === null) { localStorage.setItem(key, value); } } alert('数据导入成功!'); } catch (e) { alert('导入失败,文件格式不正确!'); } }; reader.readAsText(file); }; input.click(); } function addExportImportButtons() { const container = document.createElement('div'); container.style.position = 'fixed'; container.style.bottom = '10px'; container.style.right = '10px'; container.style.zIndex = '1000'; container.style.display = 'flex'; container.style.gap = '10px'; const exportButton = document.createElement('button'); exportButton.innerText = '导出已读数据'; exportButton.style.padding = '5px 10px'; exportButton.style.cursor = 'pointer'; exportButton.onclick = exportReadData; const importButton = document.createElement('button'); importButton.innerText = '导入已读数据'; importButton.style.padding = '5px 10px'; importButton.style.cursor = 'pointer'; importButton.onclick = importReadData; container.appendChild(exportButton); container.appendChild(importButton); document.body.appendChild(container); } const observer = new MutationObserver(mutations => { processPage(); }); observer.observe(document.body, { childList: true, subtree: true }); processPage(); addExportImportButtons(); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址