// ==UserScript== // @name 知乎手机网页版改进 // @namespace https://www.zhihu.com/ // @match https://www.zhihu.com/question/* // @grant none // @version 1.0 // @author nameldk // @description 使手机网页版可以加载更多答案 // @downloadURL none // ==/UserScript== var questionNumber = (location.href.match(/\/question\/(\d+)/)||[])[1]; var inDetailPage = location.href.match(/\/question\/\d+\/answer\/\d+/); var fromMobile = navigator.userAgent.match(/Android|iPhone|iPad|iPod|Opera Mini|IEMobile/i); var offset = 0; var limit = 5; var is_end = 0; var elList = null; var elLoading = null; var loadInterval = null; var viewportElCheckList = []; function removeIt(s) { // 删除 Array.prototype.forEach.call(document.querySelectorAll(s), function (ele) { ele.remove(); }); } function skipOpenApp() { // 跳过App内打开 // .ContentItem.AnswerItem // .RichContent.is-collapsed.RichContent--unescapable Array.prototype.forEach.call(document.querySelectorAll('.ContentItem.AnswerItem'), function (ele) { ele.classList.add('my-fold'); var elRichContentInner = ele.querySelector('.RichContent-inner'); var button = ele.querySelector('button'); if (button) { button.remove(); } if (elRichContentInner) { elRichContentInner.insertAdjacentHTML('afterend', `↓展开↓↑收起↑`); elRichContentInner.parentElement.classList.remove('is-collapsed'); elRichContentInner.setAttribute("style", ""); processFold(elRichContentInner.parentElement); } ele.addEventListener("click", function (event) { event.preventDefault(); event.stopPropagation(); if (elRichContentInner) { elRichContentInner.setAttribute("style", ""); } }); }); document.body.style.overflow = "auto"; } function removeAds() { // 移除广告 Array.prototype.forEach.call(document.querySelectorAll('.MBannerAd'), function (ele) { ele.parentNode.removeChild(ele) }); } function removeBlock() { removeIt('.MobileModal-backdrop'); removeIt('.MobileModal--plain.ConfirmModal'); removeIt('.AdBelowMoreAnswers'); removeIt('div.Card.HotQuestions'); removeIt('button.OpenInAppButton.OpenInApp'); } function formatNumber(num) { if (num > 10000) { return (num / 10000).toFixed(2) + '万'; } else { return num; } } function processContent(content) { if (!content) return ''; var r = //g; return content.replace(r, ''); } function loadContent(offset, limit) { var url = `https://www.zhihu.com/api/v4/questions/${questionNumber}/answers?include=data%5B%2A%5D.is_normal%2Cadmin_closed_comment%2Creward_info%2Cis_collapsed%2Cannotation_action%2Cannotation_detail%2Ccollapse_reason%2Cis_sticky%2Ccollapsed_by%2Csuggest_edit%2Ccomment_count%2Ccan_comment%2Ccontent%2Ceditable_content%2Cvoteup_count%2Creshipment_settings%2Ccomment_permission%2Ccreated_time%2Cupdated_time%2Creview_info%2Crelevant_info%2Cquestion%2Cexcerpt%2Crelationship.is_authorized%2Cis_author%2Cvoting%2Cis_thanked%2Cis_nothelp%2Cis_labeled%2Cis_recognized%2Cpaid_info%2Cpaid_info_content%3Bdata%5B%2A%5D.mark_infos%5B%2A%5D.url%3Bdata%5B%2A%5D.author.follower_count%2Cbadge%5B%2A%5D.topics&limit=${limit}&offset=${offset}&platform=desktop&sort_by=default`; // return $.get(url); return fetch(url).then(response => response.json()); } function buildHtml(data) { var content = processContent(data.content); var html = `
${content}
↓展开↓ ↑收起↑
`; return html; } function getListWrap() { if (!elList) { elList = document.querySelectorAll('.Question-main .List'); if (elList) elList = elList[elList.length - 1]; } return elList; } function loadAnswer() { if (is_end) { return; } if (elLoading) { elLoading.classList.remove('hide'); } loadContent(offset, limit).then(function (data) { if (elLoading) { elLoading.classList.add('hide'); } console.log('get data:', offset, limit); if (data.paging.is_end) { is_end = 1; alert('到底了~'); return; } offset += data.data.length; data.data.forEach(function (item) { let elListItemWrap = document.createElement('div'); elListItemWrap.innerHTML = buildHtml(item); getListWrap().insertAdjacentElement("beforeend", elListItemWrap); processFold(elListItemWrap); }); }) } function isElementInViewport (el) { // https://stackoverflow.com/questions/123999/how-can-i-tell-if-a-dom-element-is-visible-in-the-current-viewport if (!el) return false; var rect = el.getBoundingClientRect(); if (rect.top >= 0) { // ↓ return rect.top < window.innerHeight; } else { return rect.top + rect.height > 0; } } function addViewportCheckList(elListItem) { if (elListItem) { viewportElCheckList.push(elListItem); } } function removeViewportCheckList(elListItem) { viewportElCheckList.forEach(function (v, i) { if (v === elListItem) { viewportElCheckList.splice(i, 1); } }) } function processFold(elRichContent) { var elMoreBtn = elRichContent.querySelector('.my-more-btn'); var elLessBtn = elRichContent.querySelector('.my-less-btn'); var elContentItem = elLessBtn.closest('.ContentItem'); if (elMoreBtn && elLessBtn && elContentItem) { elMoreBtn.addEventListener('click', function (e) { elContentItem.classList.add('my-unfold'); elContentItem.classList.remove('my-fold'); addViewportCheckList(elContentItem); }); elLessBtn.addEventListener('click', function (e) { elContentItem.classList.add('my-fold'); elContentItem.classList.remove('my-unfold'); removeViewportCheckList(elContentItem); }); } } function bindLoadData() { var el = document.querySelector('div.Card.ViewAllInappCard'); if (inDetailPage) { el.style.textAlign = "center"; el.innerHTML = '查看所有问题'; return; } el.insertAdjacentHTML('beforebegin', `
`); elLoading = document.getElementById('my-loading'); window.onscroll = function(ev) { if ((window.innerHeight + window.scrollY + 50) >= document.body.offsetHeight) { console.log('reach bottom'); if (loadInterval) { clearTimeout(loadInterval); } loadInterval = setTimeout(function(){ console.log('to load', offset, limit); loadAnswer(); }, 100); } }; } function bindProcessViewport() { var interval; document.addEventListener('scroll', function () { if (interval) { clearTimeout(interval); } interval = setTimeout(function () { // console.log('scroll-view:', viewportElCheckList.length); if (viewportElCheckList.length) { viewportElCheckList.forEach(function (elListItem) { var elLessBtn = elListItem.querySelector('.my-less-btn'); if (isElementInViewport(elListItem)) { elLessBtn.classList.remove('hide'); } else { elLessBtn.classList.add('hide'); } }); } }, 100); }, false); } function addCss() { var style = ` `; document.body.insertAdjacentHTML('beforeend', style); } // init if (fromMobile) { setTimeout(function () { addCss(); skipOpenApp(); removeAds(); removeBlock(); bindLoadData(); bindProcessViewport(); }, 200); setTimeout(function () { offset += document.querySelectorAll('.List-item').length; }, 1000); }