Drawer_gz页面侧边抽屉组件

页面侧边抽屉组件

目前为 2024-11-08 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/516282/1479802/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.2
// @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.border {string} 边框,格式为粗细度 样式 颜色,详情可参考css中的border属性,默认1px solid red
 * @returns {Drawer_gz} 实例对象
 * @version 0.1
 * @author hgz
 * @constructor
 */
function Drawer_gz(config) {
    const __data = {
        outerDiv: null,
        titleHeaderEl: null,
        titleEl: null,
    };
    config = {
        ...{
            show: false,
            direction: 'right',
            width: '500px',
            height: '500px',
            backgroundColor: '#ffffff',
            bodyHtml: '',
            title: null,
            border: "1px solid red",
            zIndex: "1500",
        }, ...config
    }

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

    //设置标题
    this.setTitle = (title) => {
        if (title.trim() === "") {
            throw new Error("要设置的标题不能为空");
        }
        if (__data.titleHeaderEl.style.display === "none") {
            __data.titleHeaderEl.style.display = "flex";
        }
        __data.titleEl.textContent = title;
    }

    //设置标题是否显示
    this.titleShow = (bool) => {
        if (bool) {
            if (__data.titleEl.textContent.trim() === "") {
                throw new Error("标题为空");
            }
            __data.titleHeaderEl.style.display = "flex";
        } else {
            __data.titleHeaderEl.style.display = "none";
        }
    }

    //设置面板内容html
    this.setBodyHtml = (html) => {
        panel.innerHTML = html;
    }
    /**
     * 插入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;
    }


    //验证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 addTitleHeaderElement = (panel) => {
        const el = document.createElement('div');
        if (config.title) {
            el.style.display = "flex";
        } else {
            el.style.display = "none";
        }
        __data.titleHeaderEl = el;
        el.style.height = "40px";
        el.style.alignItems = "center";
        el.style.padding = "20px 20px 0"
        const span = document.createElement("span");
        span.textContent = config.title;
        __data.titleEl = span;
        el.appendChild(span);
        panel.appendChild(el);
    }


    const documentFragment = document.createDocumentFragment();
    //外层
    __data.outerDiv = document.createElement('div');
    __data.outerDiv.style.position = 'fixed';
    __data.outerDiv.style.transition = 'transform 0.5s';
    __data.outerDiv.style.zIndex = config.zIndex;
    setDivShowAndHideStyle();
    this.showDrawer = () => {
        if (this.isShow()) {
            this.show(false);
        } else {
            this.show(true);
        }
        setDivShowAndHideStyle();
    }
    const externalPanel = document.createElement('div');
    const panel = document.createElement('div');
    externalPanel.style.backgroundColor = config.backgroundColor;
    externalPanel.style.border = config.border;
    panel.innerHTML = config.bodyHtml;
    addTitleHeaderElement(externalPanel);
    panel.style.overflowY = 'auto';
    setPanelShowAndHideStyle(externalPanel, panel);
    documentFragment.appendChild(__data.outerDiv);
    __data.outerDiv.appendChild(externalPanel);
    externalPanel.appendChild(panel);
    document.body.appendChild(documentFragment);
    return this;
}