前端实现拖拽布局完成界面_vue拖拽布局

前端实现拖拽布局完成界面_vue拖拽布局页面布局也是在实际开发中经常用到的技术。 在大的方面,可以实现整个页面的布局,比如左侧导航、header、footer… 在小的方面,可以是内容布局,比如文章。

前言

页面布局也是在实际开发中经常用到的技术。

  • 在大的方面,可以实现整个页面的布局,比如左侧导航、header、footer…
  • 在小的方面,可以是内容布局,比如文章。
  • 考虑布局时,需要兼顾桌面浏览器和移动端的情况,也就是常说的 responsive。

在 react 中实现,和经典实现其实没什么大的区别。

实现布局有这几种方式

  • 从 0 开始使用 CSS 实现,这是必须掌握的技能
  • 使用 CSS Grid 系统(网状页面),可以使用不同尺寸的屏幕
  • 使用组件库,例如 antd
    • Grid:24 栅格系统
    • Layout:页面级整体布局

CSS 实现基础布局

上中下布局

layout-1.png

.app-layout1 {
  width: 500px;
  height: 400px;
  position: relative;
  text-align: center;
}

.app-layout1 .header {
  line-height: 60px;
}
.app-layout1 .content {
  position: absolute;
  bottom: 60px;
  top: 60px;
  left: 0;
  right: 0;
}
.app-layout1 .footer {
  line-height: 60px;
  bottom: 0;
  left: 0;
  right: 0;
  position: absolute;
}

Sider + 上中下布局

layout-2.png

使用 left: 150px,留出 Sider 的位置

.app-layout2 {
  width: 500px;
  height: 400px;
  position: relative;
  text-align: center;
}
.app-layout2 .header {
  position: absolute;
  left: 150px;
  top: 0;
  right: 0;
}
.app-layout2 .content {
  position: absolute;
  bottom: 60px;
  top: 60px;
  left: 150px;
  right: 0;
}
.app-layout2 .footer {
  bottom: 0;
  left: 150px;
  right: 0;
  position: absolute;
}
.app-layout2 .sider {
  width: 150px;
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
}

进阶:侧边栏宽度可拖拽

样式布局

style.css

.layout {
  position: relative;
  width: 100%;
  height: 400px;
}
.sider {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  background-color: #ddd;
}
.header {
  background-color: #aaa;
  height: 60px;
}

index.js

通过状态 siderWidth 控制 layoutpaddingLeft

import { useState } from 'react';
import './style.css';

export default function ResizeLayout() {
  const [siderWidth, setSiderWidth] = useState(150);
  const pxWidth = `${siderWidth}px`;

  return (
    <div className="layout" style={{ paddingLeft: pxWidth }}> <div className="sider" style={{ width: pxWidth }}> sider </div> <div className="header">header</div> <div className="content">content</div> </div>
  );
}

拖放逻辑

视觉上,我们拖拽的是侧边栏 Sider 的右边框,其实并不是。我们会在右边框位置放置一个“隐身”的 bar — sider-resizer

.sider-resizer {
  position: absolute;
  width: 6px;
  top: 0;
  bottom: 0;
  cursor: col-resize;
}

当鼠标在 sider-resizer 上,触发 onMouseDown 时,记录下鼠标的初始位置,同时标记 dragging 状态为 true

const handleMouseDown = (event) => {
  setStartPageX(event.pageX);
  setDragging(true);
};

伴随着 dragging 状态的改变,我们会为页面铺上一层遮罩 — resize-mask,以便后续 事件的监听:

{
  dragging && (
    <div className="resize-mask" onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} />
  );
}
.resize-mask {
  background: rgba(0, 0, 0, 0);
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  cursor: col-resize;
}

onMouseMove 的过程中,实时更新 siderWidth 以及对 startPageX 的更新,就会产生拖拽的效果。

最终在 onMouseUp 时,结束拖拽状态。

const handleMouseMove = (event) => {
  const currentSiderWidth = siderWidth + event.pageX - startPageX;
  setSiderWidth(currentSiderWidth);
  setStartPageX(event.pageX);
};
const handleMouseUp = () => {
  setDragging(false);
};

localStorage 存储宽度位置

在拖拽结束时,保存 siderWidthlocalStorage;初始化 siderWidth 时,检查 localStorage 是否有值。

const [siderWidth, setSiderWidth] = useState(
  parseInt(localStorage.getItem('siderWidth')) || 150,
);
const handleMouseUp = () => {
  setDragging(false);
  localStorage.setItem('siderWidth', siderWidth);
};

完整代码

style.css

.layout {
  position: relative;
  width: 100%;
  height: 400px;
}
.sider {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  background-color: #ddd;
}
.header {
  background-color: #aaa;
  height: 60px;
}
.sider-resizer {
  position: absolute;
  width: 6px;
  top: 0;
  bottom: 0;
  cursor: col-resize;
}
.resize-mask {
  background: rgba(0, 0, 0, 0);
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  cursor: col-resize;
}

index.js

import { useState } from 'react';
import './style.css';

export default function ResizeLayout() {
  const [siderWidth, setSiderWidth] = useState(
    parseInt(localStorage.getItem('siderWidth')) || 150,
  );
  const [dragging, setDragging] = useState(false);
  const [startPageX, setStartPageX] = useState(0);
  const pxWidth = `${siderWidth}px`;
  const handleMouseDown = (event) => {
    setStartPageX(event.pageX);
    setDragging(true);
  };
  const handleMouseMove = (event) => {
    const currentSiderWidth = siderWidth + event.pageX - startPageX;
    setSiderWidth(currentSiderWidth);
    setStartPageX(event.pageX);
  };
  const handleMouseUp = () => {
    setDragging(false);
    localStorage.setItem('siderWidth', siderWidth);
  };
  return (
    <div className="layout" style={{ paddingLeft: pxWidth }}> <div className="sider" style={{ width: pxWidth }}> sider </div> <div className="header">header</div> <div className="content">content</div> <div className="sider-resizer" style={{ left: pxWidth }} onMouseDown={handleMouseDown} > {dragging && ( <div className="resize-mask" onMouseMove={handleMouseMove} onMouseUp={handleMouseUp} /> )} </div> </div>
  );
}

React 最佳实践

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/12942.html

(0)

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注