Vue3实现面板分割

news2024/11/22 9:05:40

Vue3实现面板分割

下面是将你提供的 Vue 组件使用 SCSS,并以 Vue 3 的组合式 API 形式的面板分割代码。
1、建立组件相关的文件夹
在这里插入图片描述

2、将下面代码拷贝到index.vue中

<template>
  <div class="g-split" ref="gSplit">
    <!-- 水平方向 -->
    <div class="horizontal" v-if="showHorizontal">
      <div class="left-panel position" :style="horizontalLeftPanel">
        <slot name="left"></slot>
      </div>
      <div
        class="horizontal-trigger-panel position"
        :style="horizontaltriggerPanel"
        ref="horizontalTriggerPanel"
      >
        <slot name="trigger" v-if="$slots.trigger"></slot>
        <div class="trigger-content-default-wrap" v-else>
          <div class="trigger-content">
            <i class="trigger-bar" v-for="n in 7" :key="n"></i>
          </div>
        </div>
      </div>
      <div class="right-panel position" :style="horizontalRightPanel">
        <slot name="right"></slot>
      </div>
    </div>
    <!-- 垂直方向 -->
    <div class="vertical" v-if="showVertical">
      <div class="top-panel position" :style="verticalTopPanel">
        <slot name="top"></slot>
      </div>
      <div
        class="vertical-trigger-panel position"
        :style="verticaltriggerPanel"
        ref="verticalTriggerPanel"
      >
        <slot name="trigger" v-if="$slots.trigger"></slot>
        <div class="trigger-content-default-wrap" v-else>
          <div class="trigger-content">
            <i class="trigger-bar" v-for="n in 7" :key="n"></i>
          </div>
        </div>
      </div>
      <div class="bottom-panel position" :style="verticalBottomPanel">
        <slot name="bottom"></slot>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';

// 注意:页面偏移量单位统一使用百分比计算
const props = defineProps({
  value: {
    type: [String, Number],
    default: 0.5,
  },
  mode: {
    type: String,
    validator(value) {
      return ["horizontal", "vertical"].includes(value);
    },
    default: "horizontal",
  },
  min: {
    type: [String, Number],
    default: 0.1,
  },
  max: {
    type: [String, Number],
    default: 0.9,
  },
});
import { defineEmits } from 'vue';

const emit = defineEmits(['onMoveStart', 'onMoving', 'onMoveEnd']);

const gSplit = ref(null);
const horizontalTriggerPanel = ref(null);
const verticalTriggerPanel = ref(null);

const left = ref(props.value);
const top = ref(props.value);
const gSplitWidth = ref(0);
const gSplitHeight = ref(0);
const horizontalTriggerPanelWidth = ref(0);
const verticalTriggerPanelHeight = ref(0);

const showHorizontal = computed(() => props.mode === "horizontal");
const showVertical = computed(() => props.mode === "vertical");

const horizontalLeftPanel = computed(() => ({
  left: 0,
  right: (1 - left.value) * 100 + "%",
}));

const horizontalRightPanel = computed(() => ({
  left: (left.value + horizontalTriggerPanelWidth.value / gSplitWidth.value) * 100 + "%",
}));

const horizontaltriggerPanel = computed(() => ({
  left: left.value * 100 + "%",
}));

const verticalTopPanel = computed(() => ({
  top: 0,
  bottom: (1 - top.value) * 100 + "%",
}));

const verticalBottomPanel = computed(() => ({
  top: (top.value + verticalTriggerPanelHeight.value / gSplitHeight.value) * 100 + "%",
}));

const verticaltriggerPanel = computed(() => ({
  top: top.value * 100 + "%",
}));

const initDom = () => {
  gSplitWidth.value = gSplit.value.clientWidth;
  gSplitHeight.value = gSplit.value.clientHeight;
  if (props.mode === "horizontal") {
    horizontalTriggerPanelWidth.value = horizontalTriggerPanel.value.clientWidth;
  } else {
    verticalTriggerPanelHeight.value = verticalTriggerPanel.value.clientHeight;
  }
};

const bindEvent = () => {
  if (props.mode === "horizontal") {
    bindHorizontalTriggerPanelEvent();
  } else {
    bindVerticalTriggerPanelEvent();
  }
};

const preventSelectedOnMouseMove = (e) => e.preventDefault();

const bindHorizontalTriggerPanelEvent = () => {
  resolveMouseFn("horizontal", horizontalTriggerPanel.value);
};

const bindVerticalTriggerPanelEvent = () => {
  resolveMouseFn("vertical", verticalTriggerPanel.value);
};

const resolveMouseFn = (type, element) => {
  const mousedown = (e) => {
    document.addEventListener("selectstart", preventSelectedOnMouseMove);
    emit("onMoveStart", e);
    const pos = type === "horizontal" ? "left" : "top";
    const distance = type === "horizontal" ? e.clientX - element.offsetLeft : e.clientY - element.offsetTop;
    const mousemove = (e) => {
      emit("onMoving", e);
      const gSplitSize = type === "horizontal" ? gSplitWidth.value : gSplitHeight.value;
      const newPos = (type === "horizontal" ? e.clientX - distance : e.clientY - distance) / gSplitSize;
      if (newPos < props.min) newPos = props.min;
      if (newPos > 1 - props.min) newPos = 1 - props.min;
      if (pos === "left") left.value = newPos;
      else top.value = newPos;
    };
    const mouseup = () => {
      emit("onMoveEnd", e);
      document.removeEventListener("mousemove", mousemove);
      document.removeEventListener("mouseup", mouseup);
      document.removeEventListener("selectstart", preventSelectedOnMouseMove);
    };
    document.addEventListener("mousemove", mousemove);
    document.addEventListener("mouseup", mouseup);
  };
  element.addEventListener("mousedown", mousedown);
};

onMounted(() => {
  bindEvent();
  initDom();
});
</script>

<style lang="scss">
.g-split {
  height: 100%;
  overflow: hidden;
  .position {
    position: absolute;
  }
  .horizontal {
    position: relative;
    height: 100%;
    .left-panel, .right-panel {
      height: 100%;
    }
    .horizontal-trigger-panel {
      cursor: col-resize;
      height: 100%;
      .trigger-content-default-wrap {
        background-color: #f8f8f9;
        height: 100%;
        position: relative;
        width: 7px;
        .trigger-content {
          position: absolute;
          top: 50%;
          transform: translateY(-50%);
          .trigger-bar {
            width: 7px;
            height: 1px;
            display: block;
            background: rgba(23, 35, 61, 0.25);
            margin-top: 3px;
          }
        }
      }
    }
  }
  .vertical {
    position: relative;
    height: 100%;
    .top-panel, .bottom-panel {
      width: 100%;
    }
    .vertical-trigger-panel {
      width: 100%;
      .trigger-content-default-wrap {
        width: 100%;
        position: relative;
        height: 7px;
        cursor: row-resize;
        background-color: #f8f8f9;
        .trigger-content {
          position: absolute;
          left: 50%;
          top: 0;
          transform: translateX(-50%);
          height: 100%;
          .trigger-bar {
            width: 1px;
            height: 100%;
            display: inline-block;
            background: rgba(23, 35, 61, 0.25);
            margin-left: 3px;
            vertical-align: top;
          }
        }
      }
    }
  }
}
</style>

使用

注册组件

在你的 Vue 项目中,你需要在你的组件或应用程序中注册 GSplitPanel 组件。你可以通过局部注册或全局注册来实现。

局部注册

在你的父组件中导入并注册 GSplitPanel 组件:

<template>
  <div>
    <GSplitPanel mode="horizontal" :value="0.5">
      <template v-slot:left>
        <div>左侧面板内容</div>
      </template>
      <template v-slot:right>
        <div>右侧面板内容</div>
      </template>
    </GSplitPanel>
  </div>
</template>

<script setup>
import GSplitPanel from '@/components/Split/index.vue';
</script>
全局注册

如果你希望在整个项目中使用 GSplitPanel 组件,可以在你的主入口文件(如 main.js 或 main.ts)中全局注册:

import { createApp } from 'vue';
import App from './App.vue';
import GSplitPanel from '@/components/Split/index.vue';

const app = createApp(App);

app.component('GSplitPanel', GSplitPanel);

app.mount('#app');

使用组件

在你的项目中,你现在可以使用 标签来使用这个组件。你可以通过 mode 属性来控制是水平分割还是垂直分割,并通过插槽来填充面板的内容。

vue
<GSplitPanel mode="horizontal" :value="0.5">
  <template v-slot:left>
    <div>左侧面板内容</div>
  </template>
  <template v-slot:right>
    <div>右侧面板内容</div>
  </template>
</GSplitPanel>

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

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

相关文章

数学建模算法与应用 第15章 预测方法

目录 15.1 微分方程模型 Matlab代码示例&#xff1a;求解简单的微分方程 15.2 灰色预测模型&#xff08;GM&#xff09; Matlab代码示例&#xff1a;灰色预测模型 15.3 自回归模型&#xff08;AR&#xff09; Matlab代码示例&#xff1a;AR模型的预测 15.4 指数平滑法 M…

easyocr 本地部署模型 识别图像 ocr - python 实现

使用 easyocr 本地部署识别图像 ocr ,可以满足简单图像场景的ocr识别。 可以进行 中文、英文 ocr 识别。 安装 python 库 pip install easyocr 识别本地模型下载地址&#xff1a;easyocr本地部署模型识别图像ocr-python实现资源-CSDN文库 也可通过程序直接下载官方链接 识…

计算机的错误计算(一百二十一)

摘要 探讨表达式 “((1/3-0.3333333333333333235)(1/3-0.333333333333333759)*0.008)*10^20” 的计算精度问题。 对于下列算式 若用C编程计算&#xff0c;则输出是错误结果[1]。那么别的语言呢&#xff1f; 例1. 计算 不妨用Java代码计算&#xff1a; public class expres…

el-image预览时和el-table边框出现样式穿透问题处理

el-image预览时和el-table边框出现样式穿透问题处理 如图所示 我们只需要在当前组件加一个css即可解决问题 <style lang"scss" scoped> :deep(.el-table__cell) {position: static !important; } </style>

Django学习笔记之Django基础学习

Django笔记 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录…

黑马程序员 javaWeb基础学习,精细点复习【持续更新】

文章目录 WEB开发一、HTML1.html介绍 二、CSS1.CSS介绍2.CSS导入方式3.CSS选择器4.CSS属性 三、JavaScript1.介绍2.浏览器3.js的三种输出方式4.js定义变量5.js数据类型6.js运算符7.全局函数8.函数定义9.js数组对象10.js正则对象11.字符串对象12.自定义对象13.BOM浏览器对象模型…

前端开发笔记--css 黑马程序员1

文章目录 1. css 语法规范2.css的书写风格3.基础选择器选择器的分类标签选择器类选择器类选择器的特殊使用--多类名 id 选择器 字体属性常见字体字体大小字体粗细字体倾斜字体的复合简写字体属性总结 文本属性文本颜色文本对齐装饰文本文本缩进文本间距文本属性总结 css的引入方…

新兴的安全职业挑战

我们经常与安全专业人士交谈&#xff0c;他们希望在努力提升职业发展的同时提高自己的价值并克服组织内部的挑战。在这些谈话中&#xff0c;花费大量时间讨论公司未来将面临的安全问题并不罕见。 安全领导者希望为问题制定计划并获得领导层对其计划的支持。这通常意味着实施修…

关于 文件操作详解 笔记 (含代码解析)

文件 磁盘&#xff08;硬盘&#xff09;上的⽂件是⽂件。 程序设计中&#xff0c;我们⼀般谈的⽂件有两种&#xff1a;程序⽂件、数据⽂件&#xff08;从⽂件功能的⻆度来分类 &#xff09; 程序⽂件 程序⽂件包括源程序⽂件&#xff08;后缀为.c&#xff09;,⽬标⽂件&#…

Mac解决服务端第三方库安装问题

问题&#xff1a; 这周使用Flask框架写了一个数据展示的小网页&#xff0c;在发布的时候发现构建失败&#xff0c;查看日志发现是这次新增的一个第三方库没有安装到服务端&#xff0c;导致构建的时候失败了 解决问题&#xff1a; 服务端发布新增第三方库 解决过程 1、确定服务…

笔记整理—linux网络部分(1)基础网络常用名词与知识

最开始使用在同一电脑主机下进行的通信门后面发展到不同主机之间的通信。 应用编程本章就是使用API socket进行通信。 应用层&#xff1a;低级&#xff08;直接基于socket接口编程&#xff09; 高级&#xff08;基于网络通信应用框架进行编程&#xff09; 更高级&#xff08;ht…

利用 Llama 3.1模型 + Dify开源LLM应用开发平台,在你的Windows环境中搭建一套AI工作流

文章目录 1. 什么是Ollama&#xff1f;2. 什么是Dify&#xff1f;3. 下载Ollama4. 安装Ollama5. Ollama Model library模型库6. 本地部署Llama 3.1模型7. 安装Docker Desktop8. 使用Docker-Compose部署Dify9. 注册Dify账号10. 集成本地部署的 Llama 3.1模型11. 集成智谱AI大模型…

【物联网】物联网智能项目:从概念到实践

物联网智能项目&#xff1a;从概念到实践 1. 物联网简介 物联网&#xff08;IoT, Internet of Things&#xff09;是指通过网络将各种物理设备连接起来进行数据交互的系统&#xff0c;目标是通过智能设备感知、采集和处理环境信息&#xff0c;实现远程控制、自动化操作和智能…

程序员应对AI辅助编程时代:策略与展望

前言 随着AIGC&#xff08;如chatgpt、midjourney、claude等&#xff09;大语言模型接二连三的涌现&#xff0c;AI辅助编程工具日益普及&#xff0c;程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工作&#xff0c;也有人认为AI是提高效率的得力助手。面对这一…

概率 多维随机变量与分布

一、二维 1、二维随机变量及其分布 假设E是随机试验&#xff0c;Ω是样本空间&#xff0c;X、Y是Ω的两个变量&#xff1b;(X,Y)就叫做二维随机变量或二维随机向量。X、Y来自同一个样本空间。 联合分布函数 F(x,y)P(X≤x,Y≤y)&#xff0c;即F(x,y)表示求(x,y)左下方的面积。 …

国内经典多模态大模型工作2——MiniCPM-V系列(MiniCPM-Llama3-V 2.5、MiniCPM-V-2.6解读)(持续更新)

MiniCPM-V系列是面壁智能推出的小参数量的开源多模态大模型&#xff0c;没有超过9B的版本。主打小而强。 官方目前只放出了MiniCPM-Llama3-V 2.5的paper&#xff0c;2.0只有技术博客而且主要是效果展示。 目前一共出了以下几代&#xff1a;MiniCPM-V、MiniCPM-V 2.0、MiniCPM-…

探索 OpenAI 的 Swarm:一个用于多代理系统的实验性框架

OpenAI 最近发布了 Swarm,这是一个轻量级且实验性的框架,旨在支持多代理系统的开发(在其 GitHub 上特别提到这是实验性和教育性的)。 与传统方法依赖于底层的大型语言模型 (LLM) API 不同,Swarm 提供了一个无状态的抽象,用于管理多个代理之间的交互和任务交接。 这一发…

比瓴科技应邀出席金融供应链安全研讨会•引领金融软件供应链安全创新实践

9月25日&#xff0c;广东省金融科技协会在广东省地方金融管理局指导下成功在广州隆重召开“筑‘链’安全 护航发展”金融供应链安全研讨会。 随着信息技术的飞速发展和金融行业的数字化转型&#xff0c;软件在金融领域的应用日益广泛。如何保障软件供应链安全已然成为守护供应…

univer实现excel协同

快速入门 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src&q…

大数据-165 Apache Kylin Cube优化 案例 2 定义衍生维度及对比 聚合组 RowKeys

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…