react实现窗口悬浮框,可拖拽、折叠、滚动

news2024/11/28 3:14:30

1、效果如下

2、如下两个文件不需要修改

drag.js

import React from "react";
import PropTypes from "prop-types";

export default class DragM extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired
  };
  static defaultProps = {
    //默认是移动children dom,覆盖该方法,可以把tranform行为同步给外部
    updateTransform: (transformStr, tx, ty, tdom) => {
      tdom.style.transform = transformStr;
    }
  };
  position = {
    startX: 0,
    startY: 0,
    dx: 0,
    dy: 0,
    tx: 0,
    ty: 0
  };
  start = event => {
    if (event.button != 0) {
      //只允许左键,右键问题在于不选择conextmenu就不会触发mouseup事件
      return;
    }
    document.addEventListener("mousemove", this.docMove);
    this.position.startX = event.pageX - this.position.dx;
    this.position.startY = event.pageY - this.position.dy;
  };
  docMove = event => {
    const tx = event.pageX - this.position.startX;
    const ty = event.pageY - this.position.startY;
    const transformStr = `translate(${tx}px,${ty}px)`;
    this.props.updateTransform(transformStr, tx, ty, this.tdom);
    this.position.dx = tx;
    this.position.dy = ty;
  };
  docMouseUp = event => {
    document.removeEventListener("mousemove", this.docMove);
  };

  componentDidMount() {
    this.tdom.addEventListener("mousedown", this.start);
    //用document移除对mousemove事件的监听
    document.addEventListener("mouseup", this.docMouseUp);
  }

  componentWillUnmount() {
    this.tdom.removeEventListener("mousedown", this.start);
    document.removeEventListener("mouseup", this.docMouseUp);
    document.removeEventListener("mousemove", this.docMove);
  }

  render() {
    const {children} = this.props;
    const newStyle = {
      ...children.props.style,
      cursor: "move",
      userSelect: "none"
    };
    return React.cloneElement(React.Children.only(children), {
      ref: tdom => {
        return (this.tdom = tdom);
      },
      style: newStyle
    });
  }
}

index.js

import React from "react";
import PropTypes from "prop-types";
import DragM from "./drag";
import {Modal} from "antd";

class BuildTitle extends React.Component {
  updateTransform = transformStr => {
    this.modalDom.style.transform = transformStr;
  };

  componentDidMount() {
    const modalList = document.getElementsByClassName("ant-modal"); //modal的class是ant-modal
    this.modalDom = modalList[modalList.length - 1];
  }

  render() {
    const {title} = this.props;
    return (
        <DragM updateTransform={this.updateTransform}>
          <div>{title}</div>
        </DragM>
    );
  }
}

export default class DragModal extends React.Component {
  static propTypes = {
    drag: PropTypes.bool,
    destroyOnClose: PropTypes.bool
  };

  static defaultProps = {
    drag: true,
    destroyOnClose: true
  };

  render() {
    const {
      drag,
      visible,
      title,
      destroyOnClose,
      children,
      ...restProps
    } = this.props;

    //是否可拖拽
    const _title =
        title && drag ? (
            <BuildTitle visible={visible} title={title}/>
        ) : (
            title
        );

    return (
        <Modal
            visible={visible}
            title={_title}
            destroyOnClose={destroyOnClose}
            {...restProps}
        >
          {children}
        </Modal>
    );
  }
}

3、如下两个文件,自己适当修改接口数据来源即可

index.js

import React from "react";
import styles from "./index.less";
import {Badge, Icon, Tabs} from "antd";
import DragModal from "../DragModal";
import classNames from 'classnames';
import NHFetch from "../../../../utils/NHFetch";

const TabPane = Tabs.TabPane;

export default class ModalContent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: undefined,
      open: true
    };
  }

  componentDidMount() {
    this.getMessage();
  }

  componentDidUpdate(prevProps) {
    // 当props.params变化时获取新数据
    if (this.props.params !== prevProps.params) {
      console.log('----------------------------------------')
      this.getMessage();
    }
  }
  getMessage = () => {
    let xsid = this.props.params
    if (xsid) {
      NHFetch('api/zhxg-yxwz/shxd/getZzbdInfoList', 'get', {xsid: xsid}).then((res) => {
        if (res && res.code === 200) {
          this.setState({data: res.data});
        }
      })

    }
  }
  // 切换状态
  onChangeOpen = () => {
    this.setState({
      open: !this.state.open
    });
  };


  render() {
    const {data, open} = this.state;
    const {studentName} = this.props
    return (
        <DragModal
            className={classNames({
              [styles.modalClese]: !open
            })}
            wrapClassName={styles.dragWrap}
            closable={false}
            width={300}
            title={
              <div>
                {studentName + ":"}自助报道办理情况
                <div
                    className={styles.modalBtn}
                    onClick={this.onChangeOpen}

                >
                  {open ? <Icon type="down"/> : <Icon type="up"/>}
                </div>
              </div>
            }
            mask={false}
            visible={this.props.params}
            footer={false}
        >
          <div className={styles.modalContent}>
            {
                data && data.map((item, i) => {
                  return (
                      <div key={i} className={styles.modalListHeader}>
                        <Badge status={item.BLZT === '1' ? "success" : "processing"}/>
                        {item.HJMC + "  "}
                        <span style={item.BLZT === '1' ? {color: "green"} : {color: 'red'}}>
                        {item.BLZT === '1' ? '已办理' : "未办理"}
                        </span>
                      </div>
                  );
                })
            }
          </div>
        </DragModal>
    );
  }
}

css文件,index.less

.box {
  background-color: #fff;

  .danger {
    color: #f5222d
  }

  .primary {
    color: #1990ff
  }
}

/* 页签 */
.tabs {
  :global {
    .ant-tabs-bar {
      margin-bottom: 0;
    }

    .ant-tabs-tab {
      margin-right: 0;
    }

    .ant-badge {
      margin-left: 4px;
      margin-top: -4px;
    }

    .ant-badge-count {
      height: 16px;
      line-height: 16px;
    }

    .ant-badge-multiple-words {
      padding: 0 4px;
    }
  }

  .tabsExtra {
    :global {
      .ant-input {
        width: 270px;
      }

      .ant-btn {
        width: 80px;
        margin-left: 10px;
      }

      .ant-select-selection {
        border: none;
        box-shadow: none;
      }
    }
  }
}

/* 菜单 */
.menuLayout {
  &:global(.ant-layout) {
    background: #fff;
  }

  :global {
    .ant-layout-sider {
      box-shadow: 2px 0 4px 0 rgba(217, 217, 217, 0.5);
    }

    .ant-layout-content {
      padding: 10px;
    }
  }
}

.menu {
  padding: 10px 0;

  :global {
    .ant-menu-item {
      width: 100%;
      margin-top: 0;
      margin-bottom: 0 !important;

      &:after {
        right: inherit;
        left: 0;
      }
    }
  }
}

/* 表格 */
.tableTop {
  overflow: hidden;

  .tableTopLeft {
    float: left;

    button {
      margin-right: 10px;
    }
  }

  .tableTopRight {
    float: right;
  }
}

.table {
  margin-top: 10px;

  .audit {
    position: absolute;
    left: -70px;
    top: 50%;
    width: 80px;
    height: 56px;
    margin-top: -28px;
    pointer-events: none
  }

  :global {
    .ant-table-thead {
      position: relative;
      height: 50px;

      &:after {
        content: "";
        display: block;
        position: absolute;
        left: 0;
        right: 0;
        top: 42px;
        background-color: #fff;
        height: 10px;
      }

      tr {
        background: rgba(25, 144, 255, 0.2);

        &:first-child > th:first-child {
          border-top-left-radius: 0;
        }

        &:first-child > th:last-child {
          border-top-right-radius: 0;
        }
      }

      th {
        padding: 10px;
        height: 50px;
        padding-bottom: 20px;
        white-space: nowrap;
      }
    }

    .ant-table-tbody {
      border-left: 1px solid #e8e8e8;
      border-right: 1px solid #e8e8e8;

      tr:first-child td {
        border-top: 1px solid #e8e8e8;
      }

      tr > td {
        position: relative;

        &:after {
          content: "";
          position: absolute;
          right: 0;
          top: 16px;
          bottom: 16px;
          border-right: 1px solid #e8e8e8;
        }

        &:last-child,
        &:first-child {
          &:after {
            display: none;
          }
        }
      }
    }
  }
}

.tablePage {
  overflow: hidden;
  margin-top: 10px;
  padding: 0 10px;

  .tablePageLeft {
    float: left;
    color: #999;
    line-height: 32px;
  }

  .tablePageRight {
    float: right;
  }
}

/* 弹窗 */
.dragWrap {
  overflow: hidden;
  pointer-events: none;

  .modalBtn {
    position: absolute;
    top: 0;
    right: 0;
    height: 50px;
    width: 50px;
    text-align: center;
    line-height: 50px;
    cursor: pointer;
    user-select: none;
  }

  .modalClese {
    :global {
      .ant-modal-body {
        height: 0;
      }
    }
  }

  .modalContent {
    width: 300px;
    padding: 0 20px 10px 20px;
  }

  .modalListHeader {
    padding: 10px;
  }

  .modalListItem {
    position: relative;
    padding: 5px 30px 5px 23px;
    background-color: rgba(25, 144, 255, 0.05);
    border-radius: 8px;
    margin-bottom: 6px;
  }

  .modalItemBadge {
    position: absolute;
    left: 10px;
    top: 5px;
  }

  .itemInfo {
    font-size: 12px;
    color: #999;

    span {
      color: #1990ff;
    }
  }

  .modalItemIcon {
    position: absolute;
    right: 10px;
    top: 50%;
    margin-top: -15px;
    color: #1990ff;
    font-size: 20px;
  }

  :global {
    .ant-modal {
      position: absolute;
      top: auto;
      bottom: 0;
      right: 0;
      margin: 0;
      padding-bottom: 0;
      pointer-events: auto;
    }

    .ant-modal-header {
      padding: 14px 10px;
      background-color: #1990ff;

      .ant-modal-title {
        padding-right: 50px;
        color: #fff;
        font-size: 14px;
      }
    }

    .ant-modal-content {
      overflow: hidden;
    }

    .ant-modal-close {
      color: #fff;
    }

    .ant-modal-close-x {
      height: 50px;
      line-height: 50px;
    }

    .ant-modal-body {
      max-height: 350px;
      padding: 0;
      overflow: hidden;
      overflow-y: scroll;
      margin-right: -20px;
      transition: all 0.3s;
    }
  }
}

4、最后适当位置使用组件即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1844662.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

神经网络 #数据挖掘 #Python

神经网络是一种受生物神经元系统启发的人工计算模型&#xff0c;用于模仿人脑的学习和决策过程。它由大量互相连接的节点&#xff08;称为神经元&#xff09;组成&#xff0c;这些节点处理和传递信息。神经网络通常包含输入层、隐藏层&#xff08;可有多个&#xff09;和输出层…

MySQL安装教程,包含root账户密码的修改(绿色版安装)---超简单好用

1、下载(mysql-8.0.27-winx64) 2、下载地址:https://dev.mysql.com/downloads/mysql/ 3、已经将 mysql-8.0.27-winx64 文件放在了文章最后,有需要的自取(解压配置即可用)。 4、配置环境变量: 右键点击我的电脑->属性->高级系统设置->高级->环境变量->系…

PostgreSQL的学习心得和知识总结(一百四十五)|深入理解PostgreSQL数据库之ShowTransactionState的使用及父子事务有限状态机

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Windows11平台C++在VS2022中安装和使用Matplot++绘图库的时候出现的问题和解决方法

Matplot 是一个基于 C 的绘图库&#xff0c;专门用于绘制高质量的数据图表。它提供了一个简洁而强大的接口&#xff0c;使得用户能够轻松地创建各种类型的图表&#xff0c;包括线图、散点图、柱状图、饼图等。Matplot 的设计目标是提供与 MATLAB 相似的绘图体验&#xff0c;同时…

apache-tomcat、apache-maven、apache-zookeeper等的本地环境配置

一、介绍 1.apache-tomcat apache-tomcat充当了一个Web服务器和一个Java应用程序服务器的角色&#xff0c;可以用来部署和运行Java Web应用程序&#xff0c;使开发者能够轻松地部署和管理Java Web应用程序。 2.apache-maven apache-maven是一个项目管理工具&#xff0c;主要…

助力草莓智能自动化采摘,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建果园种植采摘场景下草莓成熟度智能检测识别系统

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;技术已经渗透到我们生活的方方面面&#xff0c;从智能家居到自动驾驶&#xff0c;再到医疗健康&#xff0c;其影响力无处不在。然而&#xff0c;当我们把目光转向中国的农业领域时&#xff0c;一个令人惊讶的…

【调试笔记-20240620-Windows- Tauri + Vue 中实现部分区域滚动】

调试笔记-系列文章目录 调试笔记-20240620-Windows- Tauri Vue 中实现部分区域滚动 文章目录 调试笔记-系列文章目录调试笔记-20240620-Windows- Tauri Vue 中实现部分区域滚动 前言一、调试环境操作系统&#xff1a;Windows 10 专业版调试环境调试目标 二、调试步骤搜索相似…

力扣144A

文章目录 1. 题目链接2. 题目代码3. 题目总结4. 代码分析 1. 题目链接 Arrival of the General 2. 题目代码 #include<iostream> using namespace std;int heightOfSoldier[110];int main(){int numberOfSoldier;cin >> numberOfSoldier;int maxHeight -1;int mi…

IT入门知识第七部分《移动开发》(7/10)

目录 第七部分&#xff1a;移动开发 —— 触手可及的未来 引言 1. 移动开发平台 1.1 Android 1.2 iOS 2. 跨平台开发 2.1 React Native 2.2 Flutter 3.移动开发的重要性 3.1 用户体验 3.2 可访问性 3.3 市场机会 4.移动开发面临的挑战 4.1 设备多样性 4.2 系统更…

【uni-app学习手札】

uni-app&#xff08;vue3&#xff09;编写微信小程序 编写uni-app不必拘泥于HBuilder-X编辑器&#xff0c;可用vscode进行编写&#xff0c;在《微信开发者工具》中进行热加载预览&#xff0c; 主要记录使用uni-app过程中自我备忘一些api跟语法&#xff0c;方便以后编写查找使用…

HTML静态网页成品作业(HTML+CSS)——手机电子商城网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有4个页面。 二、作品演示 三、代…

前端vue实战项目结构、常用编辑器vs code 配置

5.Complete JSDoc Tags 6.Custom CSS and JS Loader 7.Debugger for Chrome 8.EditorConfig for VS Code 9.ESLint ☆☆☆ 10.gitignore 11.GitLens — Git supercharged 12.npm 13.PostCSS syntax !important 14.Vetur ☆ 15.vscode-icons 16.vue-i18n 17.Markdow…

【C语言】排序算法 -------- 计数排序

个人主页 创作不易&#xff0c;感谢大家的关注&#xff01; 文章目录 1. 计数排序的概念2. 计数排序使用场景3. 计数排序思想4. 计数排序实现过程5. 计数排序的效率6. 总结&#xff08;附源代码&#xff09; 1. 计数排序的概念 计数排序是一种非比较的排序算法&#xff0c;其…

雷达标定与解析

融合雷达与解析雷达数据的相关代码。感谢开源社区的贡献。以下代码继承了很多人的工作。 如果是单雷达&#xff1a; 直接进行标定&#xff0c;所以就是接收相关的话题然后发布。 lidar_calibration_params.yaml&#xff1a; calibration:在这个接口里面x_offset: 0.0y_offset:…

前端 CSS 经典:clip-path 裁剪

前言&#xff1a;clip-path 可以把一个元素裁剪成任意你想要的形状。clip-path 裁剪路径生成器&#xff0c;通过改变数值&#xff0c;还可以做出有趣的动画。 效果&#xff1a; 代码实现&#xff1a; <!DOCTYPE html> <html lang"en"><head><…

创新实训2024.06.17日志:大模型微调总结

前段时间其实我们已经部署了大模型&#xff0c;并开放了对外的web接口。不过由于之前某几轮微调实验的大模型在对话时会有异常表现&#xff08;例如响应难以被理解&#xff09;&#xff0c;因此我在项目上线后&#xff0c;监控了数据库里存储的对话记录。确定了最近一段时间部署…

『 Linux 』 进程间通信概述

文章目录 什么是进程间通信为什么要有进程间通信如何进行进程间通信 什么是进程间通信 进程间通信(IPC)指的是在操作系统重,允许两个或者多个进程之间传递信息或者数据的机制; 进程是操作系统重独立运行的实体,即进程间具有独立性,存在自己的地址空间; 因此进程间默认无法直接访…

多模块开发

简介 Git 通过子模块来解决复用模块的问题。 submodule允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中&#xff0c;同时还保持提交的独立。而subtree可以将子模块合并到主模块由主模块完全管理。 git subModule Git地址&#…

MySQL----利用Mycat配置读写分离

首先确保主从复制是正常的&#xff0c;具体步骤在MySQL----配置主从复制。MySQL----配置主从复制 环境 master(CtenOS7)&#xff1a;192.168.200.131 ----ifconfig查看->ens33->inetslave(win10)&#xff1a;192.168.207.52 ----ipconfig查看->无线局域网适配器 WLA…

RabbitMQ 开发指南

连接RabbitMQ 连接方式一&#xff1a; 也可以选择使用URI的方式来实现 连接方式二&#xff1a; Connection接口被用来创建一个Channel&#xff0c;在创建之后&#xff0c;Channel可以用来发送或者接收消息。 Channel channel conn.createChannel();使用交换器和队列 声明…