首页 > 其他分享 >一个前端页面各布局块自由伸缩的js插件

一个前端页面各布局块自由伸缩的js插件

时间:2024-07-17 17:52:30浏览次数:17  
标签:插件 style height width fb separator let js 页面

可在任意两个元素之间插入伸缩控件,不需要改元素代码,添加插件代码即可。

效果:

 

用法:

引入js

<script src="./flexible-bar.js"></script>

在需要伸缩的两个元素之间添加伸缩块:

<flexible-bar size="10px" lineColor="#409eff" handleColor="white" hoverShadow="0 0 3px #333"></flexible-bar>

 

配置项:

lineColor:分隔条的颜色,默认#ddd
size: 分隔条的粗细值,默认3px
handle:是否显示手柄,默认yes
handleColor:手柄的颜色,默认white
hoverShadow:鼠标移动到分隔条时显示的阴影

 

示例页面代码:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>example</title>
        <script src="./flexible-bar.js"></script>
    </head>
    <body style="margin:0;padding:0;">
        <div style="width:100%;height:100vh;display: flex;flex-direction: column;">
            <div style="height:100px;background-color:#eee;">
                Top Area
            </div>
            <flexible-bar></flexible-bar>
            <div style="flex:1;display: flex;">

                <!-- 左侧栏 -->
                <div style="width:100px;background-color:#ffe;"> div 1 </div>
                <flexible-bar size="10px" lineColor="#409eff" handleColor="white" hoverShadow="0 0 3px #333"></flexible-bar>
                <!-- 右侧栏 -->
                <div style="width:400px;background-color:#ffe;overflow: hidden;">

                    <!-- 右上 -->
                    <div style="width:100%;height:50%;background:#fef;"> div 2 </div>
                    <flexible-bar handleColor="#409eff"></flexible-bar>
                    <!-- 右下 -->
                    <div style="width:100%;height:50%;background:#eff;"> div 3 </div>

                </div>
            </div>
        </div>
    </body>
</html>

 

插件js源码:

/**
 * flexible-bar.js 1.0 容器元素伸缩条
 * [email protected]
 * 
 * 用法示例:
 * <flexible-bar size="10px" lineColor="#409eff" handleColor="white" hoverShadow="0 0 3px #333"></flexible-bar>
 * 
 * 可配置属性:
 * lineColor:分隔条的颜色,默认#ddd
 * size: 分隔条的粗细值,默认3px
 * handle:是否显示手柄,默认yes
 * handleColor:手柄的颜色,默认white
 * hoverShadow:鼠标移动到分隔条时显示的阴影
 */
(() => {
    function flexibleBar(fb) {
        const prev = fb.previousElementSibling // 上一个兄弟节点
        const next = fb.nextElementSibling // 下一个兄弟节点
        console.log('prev', prev)
        console.log('next', next)
        if (!prev || !next) {
            throw new Error('<flexible-bar>必须放到两个元素之间')
        }

        /**
         * 判断横向还是纵向,
         * 若上一个的bottom大于等于下一个的top,则是纵向布局的,
         * 若上一个的right大于等于下一个的left,则是左右布局的,
         * 若两个情况同时满足,那可能是以下这种情况:
         * ---------
         *   口
         *      口
         * ---------
         * 这种情况无法支持,抛出错误。
         * 
         * 原理:
         * 通过控件所放位置的兄弟节点来生成伸缩条,点住条子拖动时动态改变兄弟节点的宽度或高度实现伸缩效果。
         * 点击伸缩条时在伸缩条dom里生成一个position:absolute的div节点,高宽度足够大,用来接收鼠标移动事件。全透明,无边框。鼠标按键松开时取消div样式。
         * 可以在伸缩条上拖拽,也可以在中间手柄上拖拽,手柄也是一个position:absolute的div节点,做了鼠标事件转移,在上面按住鼠标时会mousedown事件转给伸缩条。
         * 
         */

        let prevRect = prev.getBoundingClientRect()
        let nextRect = next.getBoundingClientRect()

        let direction = ''
        if (prevRect.bottom <= nextRect.top) {
            direction += 'column'
        }
        if (prevRect.right <= nextRect.left) {
            direction += 'row'
        }

        if (direction.includes('column') && direction.includes('row')) {
            throw new Error('布局不支持伸缩条')
        }

        let separatorBackground = fb.getAttribute('lineColor') || '#ddd'
        let size = fb.getAttribute('size') || '3px'
        let showHandle = fb.getAttribute('handle') || 'yes'
        let handleBackground = fb.getAttribute('handleColor') || 'white'
        let hoverShadow = fb.getAttribute('hoverShadow') || ''


        
        let separatorCssText = `display:flex;justify-content: center;align-items: center;background: ${separatorBackground};position:relative;transition:box-shadow .5s ease;`
        // pointer-events:none;
        let handleCssText = `position:absolute;background:${handleBackground};border-radius:15px;box-shadow: 0 0 2px #000;display:flex;justify-content: center;align-items: center;`
        let handleSymbolCssText = ``
        

        // 分隔栏
        const separator = document.createElement('div')
        separator.style.position = 'absolute'
        separator.style.width = '100%'
        separator.style.height = '100%'
        // separator.style.background = '#0008'
        

        if (direction === 'column') {
            // 取两个块最大的那个块的边作为伸缩柄的尺寸
            const width = prevRect.width > nextRect.width ? prevRect.width : nextRect.width
            separatorCssText += `width:${width}px;height:${size};cursor: ns-resize;`
            handleCssText += `width:50px;height:10px;flex-direction: column;`
            handleSymbolCssText = `width:60%;height:1px;background:#aaa;margin:1px;`
        }
        
        if (direction === 'row') {
            // 取两个块最大的那个块的边作为伸缩柄的尺寸
            const height = prevRect.height > nextRect.height ? prevRect.height : nextRect.height
            separatorCssText += `width:${size};height:${height}px;cursor: ew-resize;`
            handleCssText += `width:10px;height:50px;flex-direction: row;`
            handleSymbolCssText = `width:1px;height:60%;background:#aaa;margin:1px;`
        }


        let mouseDownPageX = 0
        let mouseDownPageY = 0

        let mouseStatus = 'up'
        let handleMouseDowned = false
        separator.onmousedown = (e) => {
            mouseStatus = 'down'
            if (!handleMouseDowned) {
                mouseDownPageX = e.pageX
                mouseDownPageY = e.pageY
            }
            // console.log('mouseDownPageX: ', mouseDownPageX, 'mouseDownPageY: ', mouseDownPageY)

            prevRect = prev.getBoundingClientRect()
            nextRect = next.getBoundingClientRect()
            separator.style.zIndex = 65535
            if (direction === 'column') {
                separator.style.width = '100%'
                separator.style.height = '500px'
            } else if (direction === 'row') {
                separator.style.height = '100%'
                separator.style.width = '500px'
            }
            e.preventDefault()
        }

        let cha = 0
        let newPrevHeight = 0
        let newNextHeight = 0
        let newPrevWidth = 0
        let newNextWidth = 0
        separator.onmousemove = (e) => {
            handleMouseDowned = false
            // console.log(e.pageX, e.pageY)
            if (mouseStatus !== 'down') {
                return
            }
            if (direction === 'column') {
                cha = e.pageY - mouseDownPageY
                newPrevHeight = prevRect.height + cha
                newNextHeight = nextRect.height - cha
                if (newPrevHeight < 2 || newNextHeight < 2) {
                    return
                }
                prev.style.height = newPrevHeight + 'px'
                next.style.height = newNextHeight + 'px'
            } else if (direction === 'row') {
                cha = e.pageX - mouseDownPageX
                newPrevWidth = prevRect.width + cha
                newNextWidth = nextRect.width - cha
                if (newPrevWidth < 2 || newNextWidth < 2) {
                    return
                }
                prev.style.width = newPrevWidth + 'px'
                next.style.width = newNextWidth + 'px'
            }
        }

        const resetHandle = () => {
            separator.style.width = '100%'
            separator.style.height = '100%'
            separator.style.zIndex = 'unset'
        }

        separator.onmouseup = (e) => {
            mouseStatus = 'up'
            handleMouseDowned = false
            resetHandle()
            e.preventDefault()
        }
        
        separator.onmouseenter = (e) => {
            // console.log('separator.onmouseenter')
            fb.style.boxShadow = hoverShadow
        }

        separator.onmouseleave = (e) => {
            // console.log('separator.onmouseleave')
            fb.style.boxShadow = 'unset'
            mouseStatus = 'leave'
            resetHandle()
            e.preventDefault()
        }

        fb.style.cssText = separatorCssText
        fb.appendChild(separator)

        if (showHandle === 'yes') {
            
            // 拖拽手柄
            const handle = document.createElement('div')
            const line1 = document.createElement('div')
            const line2 = document.createElement('div')
            line1.style.cssText = handleSymbolCssText
            line2.style.cssText = handleSymbolCssText
            
            handle.appendChild(line1)
            handle.appendChild(line2)
            handle.style.cssText = handleCssText
    
            handle.onmousedown = (e) => {
                e.preventDefault()
                handleMouseDowned = true
                mouseDownPageX = e.pageX
                mouseDownPageY = e.pageY
                var event = new MouseEvent('mousedown', {
                    bubbles: true, // 是否允许事件冒泡
                    cancelable: true, // 是否可以取消事件默认行为
                    view: window
                });
                separator.dispatchEvent(event);
            }
            handle.onmouseenter = (e) => {
                fb.style.boxShadow = hoverShadow
            }
            handle.onmouseleave = (e) => {
                fb.style.boxShadow = 'unset'
            }
            fb.appendChild(handle)
        }

    }


    // 初始化
    window.addEventListener('load', () => {
        const flexibles = document.querySelectorAll('flexible-bar')
        flexibles.forEach(fb => {
            flexibleBar(fb)
        })
    })

    // 若发生窗体变动则删除已生成的dom,重新初始化
    window.addEventListener('resize', () => {
        const flexibles = document.querySelectorAll('flexible-bar')
        flexibles.forEach(fb => {
            fb.childNodes.forEach(child => {
                fb.removeChild(child)
            })
            flexibleBar(fb)
        })
    })

})()

 

标签:插件,style,height,width,fb,separator,let,js,页面
From: https://www.cnblogs.com/jsper/p/18307987

相关文章

  • mysql json语法总结
    json字段定义和插入创建一个带有json字段的表createtabletest10( idintnotnullauto_incrementcomment'id', namevarchar(64)nulldefault""comment'name', json_datajsondefaultnullcomment"json格式数据", primarykey(id))插......
  • 【java计算机毕设】网上购书管理系统MySQL servlet JSP项目设计源代码 期末寒暑假作业
    目录1项目功能2项目介绍3项目地址1项目功能【java计算机毕设】网上购书管理系统MySQLservletJSP项目设计源代码期末寒暑假作业小组作业 2项目介绍系统功能:servlet网上购书管理系统包括管理员、用户两种角色。管理员功能包括订单管理(已处理,未处理),顾客管理(添......
  • python gradio 页面控件
    1、textbox的使用importgradioasgrimportrequestsdefmobile(mobilephone):url='https://api.oioweb.cn/api/common/teladress?mobile='+str(mobilephone)headers={}payload={}response=requests.request("GET",url,......
  • 前端JS箭头函数和普通函数的区别全解 面试必问
    基本语法:普通函数functionfunctionfc(a1,b2,...,pnan){sumnews;}即格式为:funtion 函数名(参数列表) {    语句;    return表达式}2.箭头函数 //当只有一个参数时,圆括号是可选的(singleParam)=>{statements}singleParam=>{......
  • FastJson详解
    文章目录一、FastJson介绍二、FastJson序列化API1、序列化Java对象2、序列化List集合3、序列化Map集合三、FashJson反序列化API1、反序列化Java对象2、反序列化List集合3、反序列化Map集合(带泛型)四、SerializerFeature枚举1、默认字段为null的不显示2、格式化五、@JSo......
  • vue数据渲染页面数据展示出现闪烁问题
    在使用vue绑定数据的时候,渲染页面时会出现变量闪烁,例如{{value.name}}在加载的时候会看到{{value.name}}原因:由于JavaScript去操作DOM,都会等待DOM加载完成(DOMready)。对于vuejs、angularjs这些会在DOMready完会才回去解析htmlviewTemplate,所以对于Chrome这类快速的浏览......
  • JS 实现在指定的时间点播放列表中的视频
     为了实现在指定的时间点播放列表中的视频,你可以使用JavaScript中的setTimeout或setInterval结合HTML5的<video>元素。但是,由于你需要处理多个时间点,并且每个时间点播放不同的视频,使用setTimeout会更直接一些,因为你可以为每个时间点设置一个独立的定时器。以下是一个基本的实......
  • ComfyUI进阶:Comfyroll插件 (二)
    ComfyUI进阶:Comfyroll插件(二)前言:学习ComfyUI是一场持久战,而ComfyrollStudio是一款功能强大的自定义节点集合,专为ComfyUI用户打造,旨在提供更加丰富和专业的图像生成与编辑工具。借助这些节点,用户可以在静态图像的精细调整和动态动画的复杂构建方面进行深入探索。ComfyrollS......
  • js 将table转成Excel
    1.情景展示如何使用js将网页中的表格转成Excel文件?2.具体分析通过SheetJS的xlsx.js文件实现。3.解决方案下载地址:https://github.com/SheetJS/sheetjs/archive/refs/tags/v0.18.5.zip打开压缩包,找到dis目录下的xlsx.full.min.js将该文件解压出来,放到项目当中。在需要......
  • 购买一台云服务器,安装nvm,能够将配置全局命令链接js文件执行
    全局安装@vue/cli为什么会添加命令vuelinux或者MAC系统中通过whichvue查看vue地址,通过进入该地址查看文件发现软链接指向真实文件,真实文件同级别下的package.json中的bin字段中的名决定了输入命令vue2.全区安装@vue/cli时将包放在了node安装位置的node_modules下并且在包中的p......