Greasy Fork is available in English.

Drawer_gz页面侧边抽屉组件

页面侧边抽屉组件

สคริปต์นี้ไม่ควรถูกติดตั้งโดยตรง มันเป็นคลังสำหรับสคริปต์อื่น ๆ เพื่อบรรจุด้วยคำสั่งเมทา // @require https://update.greasyfork.org/scripts/516282/1483127/Drawer_gz%E9%A1%B5%E9%9D%A2%E4%BE%A7%E8%BE%B9%E6%8A%BD%E5%B1%89%E7%BB%84%E4%BB%B6.js

// ==UserScript==
// @name        Drawer_gz页面侧边抽屉组件
// @namespace   http://tampermonkey.net/
// @license     Apache-2.0
// @version     0.4
// @author      byhgz
// @description 页面侧边抽屉组件
// @noframes
// ==/UserScript==

/**
 * 页面侧边抽屉组件对象
 * 需要new一个实例对象,按需传入配置对象
 * showDrawer()方法可以切换抽屉显示或隐藏
 * show()方法可以设置面板显示或隐藏
 * setTitle()方法可以设置标题
 * titleShow()方法可以设置标题是否显示
 * setBodyHtml()方法可以设置面板内容html
 * 详情自行看源码(懒得写)
 * @param config {object} 配置对象
 * @param config.show {boolean} 是否显示,默认false
 * @param config.direction {string} 方向,默认right
 * @param config.width {string} 宽度,默认500px
 * @param config.height {string} 高度,默认500px
 * @param config.backgroundColor {string} 面板背景色,默认#ffffff
 * @param config.bodyHtml {string} 面板内容html
 * @param config.title {string} 标题,默认null
 * @param config.zIndex {string|number} 层级,默认1500
 * @param config.drawerBorder {string} 边框,格式为粗细度 样式 颜色
 * @param config.titleShow {boolean} 标题显示或隐藏,默认显示
 * @param config.headerShow {boolean} 顶栏显示或隐藏,默认显示
 * @param config.headerHrShow {boolean} 顶栏中底部的横线显示隐藏,默认显示
 * @param config.externalButtonText {string} 外部开关按钮文本
 * @param config.externalButtonWidth {string} 外部开关按钮宽度,默认不填
 * @param config.externalButtonColor {string} 外部开关按钮背景色
 * @param config.externalButtonBorder {string} 外部开关按钮背景色,默认无边框,参数详情可参考css中的border属性,默认0px solid #ffffff00
 * @param config.externalButtonShow {boolean} 外部开关显示或隐藏,默认true,显示
 * @param config.externalButtonOffset {string}外部开关按钮位置偏移,建议用百分比,默认为0
 * @param config.externalButtonDirection {string} 外部开关按钮位置方向,默认left,只能是left、right、top、bottom
 * @param config.externalButtonTextColor {string} 外部按钮字体颜色,默认#FFFFFFFF白色
 * @returns {Drawer_gz} 实例对象
 * @version 0.3
 * @author hgz
 * @constructor
 */
function Drawer_gz(config) {
    const __data = {
        outerDiv: null,
        titleHeaderEl: null,
        titleEl: null,
        headerEl: null,
        headerHrEl: null,
        externalButEl: null,
    };
    config = {
        ...{
            show: false,
            //默认右侧
            direction: 'right',
            width: '500px',
            height: '500px',
            backgroundColor: '#ffffff',
            bodyHtml: '',
            title: "侧边栏默认标题",
            drawerBorder: "",
            zIndex: "1500",
            titleShow: true,
            headerShow: true,
            headerHrShow: true,
            externalButtonText: "开关",
            externalButtonColor: "#860429",
            externalButtonTextColor: "#FFFFFFFF",
            externalButtonBorder: "0px solid #ffffff00",
            externalButtonShow: true,
            externalButtonOffset: "0",
            externalButtonDirection: "left"
        }, ...config
    }

    //判断当前是否显示
    this.isShow = () => {
        return config.show;
    };
    //设置面板显示或隐藏
    this.show = (bool) => {
        config.show = bool;
        setDivShowAndHideStyle();
    }

    //设置标题内容
    this.setTitle = (title) => {
        __data.titleEl.textContent = title.trim();
    }

    //设置标题是否显示
    this.titleShow = (bool) => {
        __data.titleEl.style.visibility = bool ? "" : "hidden";
    }

    //顶栏分割线显示隐藏
    this.setHeaderHrShow = (bool) => {
        config.headerHrShow = bool;
        __data.headerHrEl.style.display = bool ? "" : "none";
    }

    //设置面板内容html
    this.setBodyHtml = (html) => {
        panel.innerHTML = html;
    }
    //显示或隐藏顶栏
    this.headerShow = (bool) => {
        __data.titleHeaderEl.style.display = bool ? "" : "none";
    }
    /**
     * 插入html到面板指定位置
     * position:插入的位置,可以是以下值之一:
     * 'beforebegin':在元素自身之前。
     * 'afterbegin':在元素的第一个子节点之前。
     * 'beforeend':在元素的最后一个子节点之后。
     * 'afterend':在元素自身之后。
     * @param html {string} 要插入的html
     * @param position {string} 插入位置 beforebegin afterbegin beforeend afterend
     */
    this.insertAdjacentHTML = (html, position = "beforeend") => {
        panel.insertAdjacentHTML(position, html);
    }

    //设置层级
    this.setZIndex = (zIndex) => {
        config.zIndex = zIndex;
        __data.outerDiv.style.zIndex = zIndex;
    }

    //外部按钮显示或隐藏
    this.externalButtonShow = (bool) => {
        __data.externalButEl.style.display = bool ? "" : "none";
        config.externalButtonShow = bool;
    }

    //设置外部开关按钮偏移
    this.setExternalButtonOffset = (value) => {
        const butExStyle = __data.externalButEl.style;
        if (config.direction === "top" || config.direction === "bottom") {
            if (config.externalButtonDirection === "left") {
                butExStyle.left = value;
            }
            if (config.externalButtonDirection === "right") {
                butExStyle.right = value;
            }
        }
        if (config.direction === "left" || config.direction === "right") {
            if (config.externalButtonDirection === "top") {
                butExStyle.top = value;
            }
            if (config.externalButtonDirection === "bottom") {
                butExStyle.bottom = value;
            }
        }
        config.externalButtonOffset = value;
    }

    //设置外部开关方向
    this.setExternalButtonDirection = (direction) => {
        if (config.direction === "left" || config.direction === "right") {
            // __data.externalButEl.style.left = "";
            // __data.externalButEl.style.right = "";
            if (direction === "top") {
                __data.externalButEl.style.top = "0";
                __data.externalButEl.style.bottom = "";
            }
            if (direction === "bottom") {
                __data.externalButEl.style.bottom = "0";
                __data.externalButEl.style.top = "";
            }
        }
        if (config.direction === "top" || config.direction === "bottom") {
            if (direction === "left") {
                __data.externalButEl.style.left = "0";
                __data.externalButEl.style.right = "";
            }
            if (direction === "right") {
                __data.externalButEl.style.right = "0";
                __data.externalButEl.style.top = "";
            }
            // __data.externalButEl.style.top = "";
            // __data.externalButEl.style.bottom = "";
        }
        config.externalButtonDirection = direction;
        //设置方向之后复原偏移
        this.setExternalButtonOffset(config.externalButtonOffset);
    }

    //设置外部开关按钮宽度
    this.setExternalButtonWidth=(value)=>{
        __data.externalButEl.style.width = value;
    }

    //验证direction参数
    const validateDirection = (direction) => {
        if (!["top", "bottom", "left", "right"].includes(direction)) {
            const message = "方向只能是top、bottom、left、right";
            alert(message);
            throw new Error(message);
        }
    }

    validateDirection(config.direction);
    //todo: 待后续实现手动切换方向功能
    // const setDirection = (direction) => {
    //     validateDirection(direction);
    //     config.direction = direction;
    //     debugger;
    //     setDivShowAndHideStyle();
    // }

    const setDivShowAndHideStyle = () => {
        const div = __data.outerDiv;
        if (config.direction === "left" || config.direction === "right" || config.direction === "top") div.style.top = "0";
        if (config.direction === "left" || config.direction === "top" || config.direction === "bottom") div.style.left = "0";
        if (config.direction === "right" || config.direction === "top" || config.direction === "bottom") div.style.right = "0";
        if (config.direction === "right") div.style.left = "";
        if (config.direction === "bottom") div.style.bottom = "0";
        if (config.direction === "top" || config.direction === "bottom") {
            div.style.width = "100vw";
        } else {
            div.style.height = "100vh";
        }
        if (this.isShow()) {
            if (config.direction === "left" || config.direction === "right") {
                div.style.transform = 'translateX(0)';
            }
            if (config.direction === "top" || config.direction === "bottom") {
                div.style.transform = 'translateY(0)';
            }
        } else {
            if (config.direction === "left") {
                div.style.transform = 'translateX(-100%)';
            }
            if (config.direction === "right") {
                div.style.transform = 'translateX(100%)';
            }
            if (config.direction === "top") {
                div.style.transform = 'translateY(-100%)';
            }
            if (config.direction === "bottom") {
                div.style.transform = 'translateY(100%)';
            }
        }
    }

    const setPanelShowAndHideStyle = (externalPanel, panel) => {
        if (config.direction === "left" || config.direction === "right") {
            panel.style.width = config.width;
            panel.style.height = "100vh";
        } else {
            panel.style.height = config.height;
        }
    }

    const setExternalButtonDirectionStyle = () => {
        const butEl = __data.externalButEl;
        const butExStyle = butEl.style;
        if (config.direction === "right") {
            butExStyle.transform = "translateX(-100%)";
        }
        if (config.direction === "left") {
            butExStyle.right = 0;
            butExStyle.transform = "translateX(100%)";
        }
        if (config.direction === "top") {
            butExStyle.transform = "translateY(100%)";
            butExStyle.bottom = 0;
        }
        if (config.direction === "bottom") {
            butExStyle.transform = "translateY(-100%)";
        }
    }

    const addTitleHeaderElement = (panel) => {
        const headerEl = document.createElement('div');
        const el = document.createElement("div");
        const leftTitleEl = document.createElement('div');
        const span = document.createElement("span");
        const closeDivEl = document.createElement('div');
        const closeBtnEl = document.createElement('button');
        const hrEl = document.createElement('hr');
        __data.titleEl = leftTitleEl;
        __data.titleHeaderEl = headerEl;
        __data.headerHrEl = hrEl;
        headerEl.className = "drawer_gz_header";
        this.titleShow(config.titleShow);
        this.headerShow(config.headerShow);
        el.style.display = "flex";
        el.style.justifyContent = "space-between";
        leftTitleEl.style.display = "flex";
        leftTitleEl.style.alignItems = "center";
        leftTitleEl.style.padding = "20px 20px 0"
        this.setTitle(config.title);
        leftTitleEl.appendChild(span);
        closeDivEl.style.padding = "20px 20px 0";
        closeBtnEl.textContent = "关闭";
        closeBtnEl.setAttribute("gz_type", "");
        closeBtnEl.addEventListener('click', () => {
            this.show(false);
        })
        closeDivEl.appendChild(closeBtnEl);
        hrEl.style.width = "90%";
        el.appendChild(leftTitleEl);
        el.appendChild(closeDivEl);
        headerEl.appendChild(el);
        headerEl.appendChild(hrEl);
        panel.appendChild(headerEl);
    }


    const documentFragment = document.createDocumentFragment();
    //外层
    const outerDiv = document.createElement('div');
    __data.outerDiv = outerDiv;
    outerDiv.style.position = 'fixed';
    outerDiv.style.transition = 'transform 0.5s';
    outerDiv.style.zIndex = config.zIndex;
    setDivShowAndHideStyle();
    this.showDrawer = () => {
        if (this.isShow()) {
            this.show(false);
        } else {
            this.show(true);
        }
        setDivShowAndHideStyle();
    }

    //添加外部开关按钮
    const addExternalButtonElement = (panel) => {
        const divEl = document.createElement('button');
        __data.externalButEl = divEl;
        divEl.textContent = config.externalButtonText || "默认开关";
        divEl.style.position = 'absolute';
        divEl.style.cursor = "pointer";
        divEl.style.borderRadius = "8px";
        divEl.style.lineHeight = "35px";
        divEl.style.textAlign = "center";
        divEl.style.backgroundColor = config.externalButtonColor;
        divEl.style.color = config.externalButtonTextColor;
        divEl.style.fontSize = "14px";
        divEl.style.border = config.externalButtonBorder;
        this.setExternalButtonWidth(config.externalButtonWidth);
        this.externalButtonShow(config.externalButtonShow);
        divEl.addEventListener('click', () => {
            this.showDrawer();
        });
        panel.appendChild(divEl);
    }

    const externalPanel = document.createElement('div');
    const panel = document.createElement('div');
    externalPanel.style.backgroundColor = config.backgroundColor;
    externalPanel.style.border = config.drawerBorder;
    panel.innerHTML = config.bodyHtml;
    panel.style.overflowY = 'auto';
    addTitleHeaderElement(externalPanel);
    addExternalButtonElement(outerDiv);
    setExternalButtonDirectionStyle();
    this.setExternalButtonDirection(config.externalButtonDirection);
    this.setHeaderHrShow(config.headerHrShow);
    setPanelShowAndHideStyle(externalPanel, panel);
    documentFragment.appendChild(__data.outerDiv);
    __data.outerDiv.appendChild(externalPanel);
    externalPanel.appendChild(panel);
    document.body.appendChild(documentFragment);
    return this;
}