阿星的博客

一个知乎脚本,用来自动收起已读的答案

自用的一个 chrome 脚本,请搭配 Tampermonkey 链接 使用。

前言

很多时候,知乎里的长帖很多很多,有时候想在看过的问题里寻找新答案,很是痛苦,所以有了这么个脚本。

正文

直接上图,请看效果图: Snipaste_2018-07-27_18-15-41.png

  • 第一次查看答案时,记录查看时间。
  • 再次查看到已读答案时,自动淡化并收起。

脚本

请复制以下代码后另存为zhihu.no_see_read_again2.user.js 文件使用。

// ==UserScript==
// @name           zhihu.no_see_read_again2
// @description    zhihu.no_see_read_again2
// @auth           wyx@wanyaxing.com
// @include        https://www.zhihu.com/*
// @include        http://www.zhihu.com/*
// @grant           GM_getValue
// @grant           GM_setValue

// ==/UserScript==
if (!this.GM_getValue || this.GM_getValue.toString().indexOf("not supported")>-1) {
    this.GM_getValue=function (key,def) {
        return localStorage[key] || def;
    };
    this.GM_setValue=function (key,value) {
        return localStorage[key]=value;
    };
}

var ON_SCREEN_HEIGHT = 0;
// var ON_SCREEN_HEIGHT = Infinity;
var ON_SCREEN_WIDTH = 0;
// var ON_SCREEN_WIDTH = Infinity;

var isOnScreen = function (element) {
    var rect = element.getBoundingClientRect();
    var windowHeight = window.innerHeight || document.documentElement.clientHeight;
    var windowWidth = window.innerWidth || document.documentElement.clientWidth;

    var elementHeight = element.offsetHeight;
    var elementWidth = element.offsetWidth;

    var onScreenHeight = ON_SCREEN_HEIGHT > elementHeight ? elementHeight : ON_SCREEN_HEIGHT;
    var onScreenWidth = ON_SCREEN_WIDTH > elementWidth ? elementWidth : ON_SCREEN_WIDTH;

    // 元素在屏幕上方
    var elementBottomToWindowTop = rect.top + elementHeight;
    var bottomBoundingOnScreen = elementBottomToWindowTop >= onScreenHeight;

    // 元素在屏幕下方
    var elementTopToWindowBottom = windowHeight - (rect.bottom - elementHeight);
    var topBoundingOnScreen = elementTopToWindowBottom >= onScreenHeight;

    // 元素在屏幕左侧
    var elementRightToWindowLeft = rect.left + elementWidth;
    var rightBoundingOnScreen = elementRightToWindowLeft >= onScreenWidth;

    // 元素在屏幕右侧
    var elementLeftToWindowRight = windowWidth - (rect.right - elementWidth);
    var leftBoundingOnScreen = elementLeftToWindowRight >= onScreenWidth;

    return bottomBoundingOnScreen && topBoundingOnScreen && rightBoundingOnScreen && leftBoundingOnScreen;
};

Date.prototype.format = function(format)
{
    var o =
    {
    "M+" : this.getMonth()+1, //month
    "d+" : this.getDate(), //day
    "h+" : this.getHours(), //hour
    "m+" : this.getMinutes(), //minute
    "s+" : this.getSeconds(), //second
    "q+" : Math.floor((this.getMonth()+3)/3), //quarter
    "S" : this.getMilliseconds() //millisecond
    };

    if(/(y+)/.test(format))
    {
        format = format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
    }

    for(var k in o)
    {
        if(new RegExp("("+ k +")").test(format))
        {
            format = format.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
        }
    }
    return format;
};

var _uniqueCheck;
function uniqueCheck()
{
    if (!_uniqueCheck)
    {
        linkCheck2();
    }
    else if (_uniqueCheck)
    {
        clearTimeout(_uniqueCheck);
    }
    _uniqueCheck = setTimeout( ()=> {
        linkCheck2();
        _uniqueCheck = null;
    }, 500);
}

function linkCheck2()
{
    console.log('linkCheck2');
    // 新版正文
    // var aNodes = document.querySelectorAll('.ContentItem-time a:not([no_see_read_again])');
    var aNodes = document.querySelectorAll('.ContentItem[name]:not([no_see_read_again])');
    Array.prototype.forEach.call(aNodes, function(el, i){
        var _this = el;
        // console.log(_this);
        var answer = _this.getAttribute('name');
        if (answer)
        {
            var lastView = GM_getValue('answer_'+answer);
            if (lastView)
            {
                _this.setAttribute('no_see_read_again','read_before');
                // 淡化效果
                var zm_item_answer = _this;//.closest('.ContentItem');
                if (_this.closest('.List-item'))
                {
                    _this.closest('.List-item').setAttribute('no_see_read_again','read_before');
                }
                zm_item_answer.style.opacity='0.3';
                // 补充显示上次查看
                var divNode = document.createElement('span');
                divNode.style.cssText = 'float:right;';
                divNode.innerHTML = ' 上次查看:'+lastView;
                _this.prepend(divNode);
                // 开始处理正文
                var zm_editable_content = zm_item_answer.querySelector('.RichContent .RichContent-inner');
                // 放弃注释掉图片属性,因为速度太快,图片都下载回来了。

                // 收起正文
                zm_editable_content.style.maxHeight = '30px';
                zm_editable_content.style.overflow = 'hidden';
                zm_editable_content.style.borderBottom = '1px dotted black';
                // 注册点击事件
                zm_item_answer.onclick = function(){
                    zm_editable_content.style.maxHeight = 'none';
                    zm_editable_content.style.overflow = 'none';
                    zm_editable_content.style.borderBottom = 'none';
                    zm_item_answer.style.opacity='1';
                };

            }
            else
            {
                if (isOnScreen(_this))
                {
                    lastView = (new Date()).format('yyyy-MM-dd hh:mm:ss');
                    GM_setValue('answer_'+answer, lastView);
                    _this.setAttribute('no_see_read_again','read_now');
                    var divNode = document.createElement('span');
                    divNode.style.cssText = 'float:right;';
                    divNode.innerHTML = '已记录本次查看';
                    _this.prepend(divNode);
                }
            }
        }
    });
    var listItemNodes = document.querySelectorAll('#QuestionAnswers-answers .List-item[no_see_read_again]');
    if (listItemNodes.length>10)
    {
        Array.prototype.forEach.call(listItemNodes, function(el, i){
            el.parentNode.removeChild(el);
        });
        document.body.scrollTop = 0;// document.body.scrollHeight;
        document.documentElement.scrollTop = 0;// document.body.scrollHeight;
    }

}

uniqueCheck();

//当滚动结束时触发检测。
var lastScrollTime2 = null;
unsafeWindow.onscroll = function(){
    var thisTime = lastScrollTime2 = (new Date).getTime();
    setTimeout(function(){
        if (thisTime == lastScrollTime2)
        {
            uniqueCheck();
        }
    },100);
};

if (document.querySelector('.List-item'))
{
    document.querySelector('.List-item').parentNode.addEventListener("DOMNodeInserted", function() {
        setTimeout(function(){
            uniqueCheck();
        },500);
    });
}

后语

很久前写的这么个脚本,功能能用,就一直这么用着了,代码如上,供大家参考。

原文来自阿星的博客:https://wanyaxing.com/blog/20180727181232.html

X