Javascript 在 html 中进行拆分窗格的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12194469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to do a split pane in html
提问by mortb
Does anyone know of a good technique to make a resizable split pane in html?
有谁知道在 html 中制作可调整大小的拆分窗格的好技术?
May it be done using css / jquery / javascript or does someone know a good javascript library that they've used?
可以使用 css / jquery / javascript 或有人知道他们使用过的好的 javascript 库吗?
(An example of a split pane is the favorites bar in internet explorer which you may have docked to the left of your main browser window)
(拆分窗格的一个示例是 Internet Explorer 中的收藏夹栏,您可能已将其停靠在主浏览器窗口的左侧)
回答by nathancahill
I wanted a vanilla, lightweight (jQuery UI Layout weighs in at 185kb), no dependency option (all existing libraries require jQuery) so I wrote Split.js.
我想要一个普通的、轻量级的(jQuery UI 布局的重量为 185kb),没有依赖选项(所有现有的库都需要 jQuery)所以我写了Split.js。
It weights less than 2kb and does not require any special markup. It supports older browsers back to IE9 (or IE8 with polyfills). For modern browsers, you can use it with Flexbox and Grid layouts.
它小于 2kb,不需要任何特殊标记。它支持旧浏览器回到 IE9(或带有 polyfills 的 IE8)。对于现代浏览器,您可以将其与 Flexbox 和 Grid 布局一起使用。
回答by personal_cloud
Improving on Reza's answer:
改进Reza 的回答:
- prevent browser from interfering with drag
- prevent setting element to negative size
- prevent drag getting out of sync with mouse due to incremental delta interaction with element width saturation
- 防止浏览器干扰拖动
- 防止将元素设置为负大小
- 防止由于与元素宽度饱和的增量增量交互而导致拖动与鼠标不同步
<html><head><style>
.splitter {
width: 100%;
height: 100px;
display: flex;
}
#separator {
cursor: col-resize;
background-color: #aaa;
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='30'><path d='M2 0 v30 M5 0 v30 M8 0 v30' fill='none' stroke='black'/></svg>");
background-repeat: no-repeat;
background-position: center;
width: 10px;
height: 100%;
/* prevent browser's built-in drag from interfering */
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#first {
background-color: #dde;
width: 20%;
height: 100%;
min-width: 10px;
}
#second {
background-color: #eee;
width: 80%;
height: 100%;
min-width: 10px;
}
</style></head><body>
<div class="splitter">
<div id="first"></div>
<div id="separator" ></div>
<div id="second" ></div>
</div>
<script>
// function is used for dragging and moving
function dragElement( element, direction)
{
var md; // remember mouse down info
const first = document.getElementById("first");
const second = document.getElementById("second");
element.onmousedown = onMouseDown;
function onMouseDown( e )
{
//console.log("mouse down: " + e.clientX);
md = {e,
offsetLeft: element.offsetLeft,
offsetTop: element.offsetTop,
firstWidth: first.offsetWidth,
secondWidth: second.offsetWidth};
document.onmousemove = onMouseMove;
document.onmouseup = () => {
//console.log("mouse up");
document.onmousemove = document.onmouseup = null;
}
}
function onMouseMove( e )
{
//console.log("mouse move: " + e.clientX);
var delta = {x: e.clientX - md.e.x,
y: e.clientY - md.e.y};
if (direction === "H" ) // Horizontal
{
// prevent negative-sized elements
delta.x = Math.min(Math.max(delta.x, -md.firstWidth),
md.secondWidth);
element.style.left = md.offsetLeft + delta.x + "px";
first.style.width = (md.firstWidth + delta.x) + "px";
second.style.width = (md.secondWidth - delta.x) + "px";
}
}
}
dragElement( document.getElementById("separator"), "H" );
</script></body></html>
回答by Reza
I wrote a simple code for it without any third-party library; This code is only for horizontal splitter (vertical is the same)
我为它写了一个简单的代码,没有任何第三方库;此代码仅用于水平分离器(垂直相同)
function onload()
{
dragElement( document.getElementById("seperator"), "H" );
}
// function is used for dragging and moving
function dragElement( element, direction, handler )
{
// Two variables for tracking positions of the cursor
const drag = { x : 0, y : 0 };
const delta = { x : 0, y : 0 };
/* if present, the handler is where you move the DIV from
otherwise, move the DIV from anywhere inside the DIV */
handler ? ( handler.onmousedown = dragMouseDown ): ( element.onmousedown = dragMouseDown );
// function that will be called whenever the down event of the mouse is raised
function dragMouseDown( e )
{
drag.x = e.clientX;
drag.y = e.clientY;
document.onmousemove = onMouseMove;
document.onmouseup = () => { document.onmousemove = document.onmouseup = null; }
}
// function that will be called whenever the up event of the mouse is raised
function onMouseMove( e )
{
const currentX = e.clientX;
const currentY = e.clientY;
delta.x = currentX - drag.x;
delta.y = currentY - drag.y;
const offsetLeft = element.offsetLeft;
const offsetTop = element.offsetTop;
const first = document.getElementById("first");
const second = document.getElementById("second");
let firstWidth = first.offsetWidth;
let secondWidth = second.offsetWidth;
if (direction === "H" ) // Horizontal
{
element.style.left = offsetLeft + delta.x + "px";
firstWidth += delta.x;
secondWidth -= delta.x;
}
drag.x = currentX;
drag.y = currentY;
first.style.width = firstWidth + "px";
second.style.width = secondWidth + "px";
}
}
.splitter {
width: 500px;
height: 100px;
display: flex;
}
#seperator {
cursor: col-resize;
background: url(https://raw.githubusercontent.com/RickStrahl/jquery-resizable/master/assets/vsizegrip.png) center center no-repeat #535353;
width: 10px;
height: 100px;
min-width: 10px;
}
#first {
background-color: green;
width: 100px;
height: 100px;
min-width: 10px;
}
#second {
background-color: red;
width: 390px;
height: 100px;
min-width: 10px;
}
<html>
<head>
<link rel="stylesheet" href="T10-Splitter.css">
<script src="T10-Splitter.js"></script>
</head>
<body onload="onload()">
<div class="splitter">
<div id="first"></div>
<div id="seperator"></div>
<div id="second"></div>
</div>
</body>
</html>
回答by ling
Here is my lightweight vanilla js approach, using flexbox:
这是我使用 flexbox 的轻量级 vanilla js 方法:
http://codepen.io/lingtalfi/pen/zoNeJp
http://codepen.io/lingtalfi/pen/zoNeJp
Tested successfully in chrome 54, firefox 50, safari 10, don't know about other browsers.
在chrome 54、firefox 50、safari 10下测试成功,其他浏览器不知道。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.rawgit.com/lingtalfi/simpledrag/master/simpledrag.js"></script>
<style type="text/css">
html, body {
height: 100%;
}
.panes-container {
display: flex;
width: 100%;
overflow: hidden;
}
.left-pane {
width: 18%;
background: #ccc;
}
.panes-separator {
width: 2%;
background: red;
position: relative;
cursor: col-resize;
}
.right-pane {
flex: auto;
background: #eee;
}
.panes-container,
.panes-separator,
.left-pane,
.right-pane {
margin: 0;
padding: 0;
height: 100%;
}
</style>
</head>
<body>
<div class="panes-container">
<div class="left-pane" id="left-pane">
<p>I'm the left pane</p>
<ul>
<li><a href="#">Item 1</a></li>
<li><a href="#">Item 2</a></li>
<li><a href="#">Item 3</a></li>
</ul>
</div>
<div class="panes-separator" id="panes-separator"></div>
<div class="right-pane" id="right-pane">
<p>And I'm the right pane</p>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A accusantium at cum cupiditate dolorum, eius eum
eveniet facilis illum maiores molestiae necessitatibus optio possimus sequi sunt, vel voluptate. Asperiores,
voluptate!
</p>
</div>
</div>
<script>
var leftPane = document.getElementById('left-pane');
var rightPane = document.getElementById('right-pane');
var paneSep = document.getElementById('panes-separator');
// The script below constrains the target to move horizontally between a left and a right virtual boundaries.
// - the left limit is positioned at 10% of the screen width
// - the right limit is positioned at 90% of the screen width
var leftLimit = 10;
var rightLimit = 90;
paneSep.sdrag(function (el, pageX, startX, pageY, startY, fix) {
fix.skipX = true;
if (pageX < window.innerWidth * leftLimit / 100) {
pageX = window.innerWidth * leftLimit / 100;
fix.pageX = pageX;
}
if (pageX > window.innerWidth * rightLimit / 100) {
pageX = window.innerWidth * rightLimit / 100;
fix.pageX = pageX;
}
var cur = pageX / window.innerWidth * 100;
if (cur < 0) {
cur = 0;
}
if (cur > window.innerWidth) {
cur = window.innerWidth;
}
var right = (100-cur-2);
leftPane.style.width = cur + '%';
rightPane.style.width = right + '%';
}, null, 'horizontal');
</script>
</body>
</html>
This html code depends on the simpledragvanilla js lightweight library (less than 60 lines of code).
这段html代码依赖于simpledragvanilla js 轻量级库(不到 60 行代码)。
回答by NVRM
Simplest html+css accordion, with just css resize.
最简单的 html+css 手风琴,只需css resize。
div {
resize: vertical;
overflow: auto;
border: 1px solid
}
.menu {
display: grid
/* Try height: 100% or height: 100vh */
}
<div class="menu">
<div>
Hello world!
</div>
<div>
Hello world!
</div>
<div>
Hello world!
</div>
</div>
Simplest html+css vertical resizable panes:
最简单的 html+css 垂直可调整大小的窗格:
div {
resize: horizontal;
overflow: auto;
border: 1px solid;
display: inline-flex;
height:90vh
}
<div>
Hello world!
</div>
<div>
Hello world!
</div>
The plain html, details element!.
纯 html,详细信息元素!.
<details>
<summary>Morning</summary>
<p>Hello world!</p>
</details>
<details>
<summary>Evening</summary>
<p>How sweat?</p>
</details>
Simplest html+css topbar foldable menu
最简单的html+css顶栏折叠菜单
div{
display: flex
}
summary,p{
margin: 0px 0 -1px 0px;
padding: 0 0 0 0.5rem;
border: 1px black solid
}
summary {
padding: 0 1rem 0 0.5rem
}
<div>
<details>
<summary>FILE</summary>
<p>Save</p>
<p>Save as</p>
</details>
<details>
<summary>EDIT</summary>
<p>Pump</p>
<p>Transfer</p>
<p>Review</p>
<p>Compile</p>
</details>
<details>
<summary>PREFERENCES</summary>
<p>How sweat?</p>
<p>Powered by html</p>
</details>
</div>
Fixed bottom menu bar, unfolding upward.
固定底部菜单栏,向上展开。
div{
display: flex;
position: fixed;
bottom: 0;
transform: rotate(180deg)
}
summary,p{
margin: 0px 0 -1px 0px;
padding: 0 0 0 0.5rem;
border: 1px black solid;
transform: rotate(180deg)
}
summary {
padding: 0 1rem 0 0.5rem;
}
<div>
<details>
<summary>FILE</summary>
<p>Save</p>
<p>Save as</p>
</details>
<details>
<summary>EDIT</summary>
<p>Pump</p>
<p>Transfer</p>
<p>Review</p>
<p>Compile</p>
</details>
<details>
<summary>PREF</summary>
<p>How?</p>
<p>Power</p>
</details>
</div>
Simplest resizable pane, using javascript.
最简单的可调整大小的窗格,使用 javascript。
let ismdwn = 0
rpanrResize.addEventListener('mousedown', mD)
function mD(event) {
ismdwn = 1
document.body.addEventListener('mousemove', mV)
document.body.addEventListener('mouseup', end)
}
function mV(event) {
if (ismdwn === 1) {
pan1.style.width = event.clientX * 2 + "px"
} else {
end
}
}
const end = (e) => {
ismdwn = 0
document.body.removeEventListener('mouseup', end)
rpanrResize.removeEventListener('mousemove', mV)
}
div {
display: flex;
border: 1px black solid;
width: 100%;
height: 456px;
}
#rpanrResize {
position: sticky;
background: #1b1b51;
width: 0.2rem;
cursor: col-resize;
margin: 0 0 0 auto;
}
#pan {
min-width: 2rem
}
<div>
<div id="pan1">MENU
<div id="rpanrResize"> </div>
</div>
<div>BODY</div>
</div>
回答by Faust
In the old days, you would use frames to achieve this. There are several reasons why this approach is not so good. See Reece's response to why frames are bad. See also Jakob Nielson's Why Frames Suck (Most of the Time)
在过去,您会使用框架来实现这一点。这种方法不太好有几个原因。请参阅 Reece 对帧为什么不好的回应。另请参阅 Jakob Nielson 的《为什么帧很烂(大部分时间)》
A Somewhat newer approach is to use inline frames. This has pluses and minuses as well: Are iframes considered 'bad practice'?
一种较新的方法是使用内联框架。这也有优点和缺点:iframe 是否被认为是“不好的做法”?
An even better approach is to use fixed positioning. By placing the navigation content (e.g. the favorites links in your example) in a block element (like a div
) then applying position:fixed
to that element and setttnig the left, top and bottom properties like this:
更好的方法是使用固定定位。通过将导航内容(例如,您的示例中的收藏夹链接)放在块元素(如 a div
)中,然后应用position:fixed
到该元素并设置 left、top 和 bottom 属性,如下所示:
#myNav {
position:fixed;
left:0px;
top:0px;
bottom:0px;
width:200px;
}
... you will achieve a vertical column down the left side of the page that will not move when the user scrolls the page.
...您将在页面左侧下方实现一个垂直列,当用户滚动页面时该列不会移动。
The rest of the content on the page will not "feel" the presence of this nav element, so it must take into account the 200px of space it occupies. You can do this by placing the rest for the content in another div and setting margin-left:200px;
.
页面上的其余内容不会“感觉到”这个导航元素的存在,因此它必须考虑到它占用的 200px 空间。您可以通过将内容的其余部分放在另一个 div 中并设置margin-left:200px;
.
回答by ColacX
Hmm I came across this property in CSS3. This might be easier to use. https://www.w3schools.com/cssref/css3_pr_resize.asp
嗯,我在 CSS3 中遇到了这个属性。这可能更容易使用。 https://www.w3schools.com/cssref/css3_pr_resize.asp
回答by freeworlder
You can do it with JqueryUI without another JS library. Just add a function to the .resizable
resize event to adjust the width of the other div.
您可以使用 JqueryUI 来完成,而无需其他 JS 库。只需在.resizable
resize 事件中添加一个函数来调整另一个 div 的宽度。
$("#left_pane").resizable({
handles: 'e', // 'East' side of div draggable
resize: function() {
$("#right_pane").outerWidth( $("#container").innerWidth() - $("#left_pane").outerWidth() );
}
});
Here's the complete JS Fiddle.
这是完整的JS Fiddle。
回答by Steve M
One totally different approach is to put things in a grid, such as ui-grid or Kendo's grid, and have the columns be resizable. A downside is that users would not be able to resize the rows, though the row size could be set programmatically.
一种完全不同的方法是将事物放在网格中,例如 ui-grid 或 Kendo 的网格,并使列可调整大小。缺点是用户无法调整行大小,但可以通过编程方式设置行大小。
回答by Bergi
You can use absolute of fixed positioning. This CSS for example will dock a 2em-bar on the left side of your page:
您可以使用绝对的固定定位。例如,此 CSS 将在页面左侧停靠一个 2em-bar:
body {
padding-left: 2.5em;
}
body > #bar {
position:fixed;
top:0; left:0;
width: 2em;
height: 100%;
border-right: 2px solid #55F; background: #ddd;
}