demo open talk

课件. 又拍云 open talk 公开课 油猴脚本 —— 只为更好的交互体验

Versión del día 15/4/2020. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// 脚本名称
// @name         demo open talk
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  课件. 又拍云 open talk 公开课 油猴脚本 —— 只为更好的交互体验
// @author       You
// 在哪些页面生效, 支持通配符
// @match        https://www.zhihu.com/question/*
// GM_addStyle 油猴内置的 api, `@grant GM_addStyle` 的作用相当于 import, 这样就可以在当前页面调用 GM_addStyle 这个接口了. GM_addStyle 这个可以用来添加样式.
// @grant        GM_addStyle
// ==/UserScript==

// 隐藏右边栏. display: none 是要隐藏选中的节点
// 因为 CSS 中可能会存在多个样式渲染到同一个节点上, 为了达到我们想要的效果, 这些样式有一个优先级,
// 使用 `!important` 就表明我们当前的样式优先级比较高
GM_addStyle('.Question-sideColumn {display: none !important}');
// 加宽内容栏
// with 表示盒子的宽度,
GM_addStyle('.Question-mainColumn {width: 1000px !important}');

(function() {
    'use strict';

    // Your code here...
    // 创建元素
    function createEle(eleName, text, attrs){
        let ele = document.createElement(eleName);
        // innerText 也就是 <p>text会被添加到这里</p>
        ele.innerText = text;
        // attrs 的类型是一个 map
        for (let k in attrs) {
            // 遍历 attrs, 给节点 ele 添加我们想要的属性
           ele.setAttribute(k, attrs[k]);
        }
        // 返回节点
        return ele;
    }

    // 复制到剪贴板
    function updateClipboard(newClip) {
        // 把内容复制到剪贴板. then 是代表回调的意思
        navigator.clipboard.writeText(newClip).then(function() {
            // 一切都没问题的话会执行 alert 操作
        alert('succeed copy');
        }, function(err) {
            // 失败时执行的函数
            /* clipboard write failed */
            console.info('failed copy', err);
            alert('faild copy')
        });
    }

    const added = [];
    // btnStyle 是一个我事先写好的样式.
    // 因为写样式调试的时间比较久,我就不一一向大家演示了.
    const btnStyle = 'background-color: #0084ff; margin-top: 15px; margin-bottom: 15px; margin-left:-5px; cursor:pointer; color: #fff; border-radius: 3px; border: 1px solid; padding: 3px 6px';


    // 加转载按钮
    function addBtn() {
        //  获取回答列表
        // querySelectorAll 这个 api 可以获取一组 api 节点
        const all = document.querySelectorAll('div[class="List-item"]');
        for (let item of all) {
            // 定位到每个节点的 meta 节点
            const meta = item.querySelector('div[class="ContentItem-meta"]');
            // 因为知乎规则, 每个人只允许回答一次, 所以我们可以使用 who 作为每个答案的 id;
            // todo: 这个地方是有 bug 的, 因为知乎规则中是允许匿名回答的, 匿名的时候会导致当前节点的节点为空, 导致重复添加
            // 解决办法是, 多从 meta 中获取几个属性, 拼接成一个独一无二的 id, 这里为了演示, 简单起见, 暂不考虑这种情况.
            const who = meta.querySelector('meta[itemprop="url"]').getAttribute('content').split('/').pop();
            // added 是一个全局变量, 用来保存已经添加过按钮的节点.
            // 这步的作用是, 已经添加按钮节点不重复添加
            if (added.indexOf(who) > -1) {
                continue;
            }
            // createEle 是我封住的一个工具函数, 可以生成一个节点.
            const btn = createEle('button', '转载按钮', {style: btnStyle});
            // text 是我们选中的文本.
            const text = item.querySelector('div[class="RichContent-inner"]').innerText;
            // 给 btn 节点添加一个鼠标点击事件
            // 当 btn 节点接听到鼠标事件后, 会触发后面的方法
            // ()=>{}, 这种是箭头函数, 是 ES6 的语法.
            btn.addEventListener('click', ()=>{updateClipboard(text)});
            // 把创建好的 btn 节点添加到 meta 后面.
            meta.append(btn);
            // 添加了 btn后的推到 added 列表, 不再重复添加.
            added.push(who);
        }
    }

    // 给 window 对象添加一个滚动事件, 当滚动时触发就执行对应的操作.
    window.addEventListener('scroll', addBtn);

})();