vue3 可拖动的左右面板分割组件实现

目录
  • 分解组件
    • 左侧面板
    • 右侧面板
  • 入参分解
    • props
    • slots
  • 具体实现
    • 如何拖动呢?
    • 事件监听
    • 宽度处理
    • 优化
    • bug
  • git地址

最近在使用vue的时候,遇到一个需求,实现左右div可通过中间部分拖拽调整宽度,本文就整理一下,分享给大家,具体如下:

效果图

分解组件

整体使用flex布局

左侧面板

  • 面板的具体内容通过slot具名插槽传入。
  • title通过prop传入
  • 可拖动,为了保证内容样式不会被拖动所破坏,对面板的宽度设定最大值/最小值

右侧面板

  • 右侧面板宽度随着左侧面板的宽度变化而变化,此处需注意,内容的宽度使用flex-auto自动适应。
  • 需要做移动端的自适应。
  • 自适应使用tailwind的媒体查询

入参分解

props

  • @param {Number} maxWidth 最大宽度
  • @param {Number} minWidth 最小宽度
  • @param {String} leftTitle 左标题
  • @param {String} rightTitle 右标题?
  • @param {Boolean} sotoreage 是否存储与localstorege

slots

  • left-content {Element}  左侧内容
  • right-content {Element} 右侧内容

具体实现

如何拖动呢?

在左侧面板与右侧面板之间添加一个隐藏的盒子,我将这个盒子隐藏在box-shadow之中。具体事件放在这个div中实现

<div id="line" class="w-2 cursor-move hidden md4:block"onMousedown={hnadleMouseDown}>
</div>

事件监听

    const hnadleMouseDown = (evt: MouseEvent) => {
      /* 获取起始点位,并存储 */
      let { pageX, pageY } = evt;
      basePosition.pageX = pageX;
      basePosition.pageY = pageY;
      /* 监听鼠标的移动事件 */
      document.addEventListener("mousemove", handleMouseMove);
      document.addEventListener("mouseup", handleMouseUp);
    };
    const handleMouseMove = evt => {
      /* 阻止浏览器默认事件,防止触发浏览器的手势功能 */
      evt.preventDefault();
      /* 设置定时器,防止dom多次回流 */
      clearTimeout(timer.value);
      timer.value = setTimeout(() => {
        let { pageX } = evt;
        const baseDiv = document.querySelector(".right-border-shadow");
        /* 处理宽度,是否处于最大值/最小值之间 */
        let baseWidth: Number | undefined =
          Number(baseDiv?.clientWidth) + (pageX - basePosition.pageX);
        baseWidth =
          baseWidth > Number(props?.maxWidth) ? props.maxWidth : baseWidth;
        baseWidth =
          Number(baseWidth) < Number(props?.minWidth)
            ? props.minWidth
            : baseWidth;
        baseDiv?.setAttribute("style", `width:${baseWidth}px`);
        /* emit宽度改变的事件 */
        ctx.emit("drugend");
        /* 存储到store */
        setStore(baseWidth);
      }, 50);
    };
    const handleMouseUp = evt => {
      /* 结束拖动之后,取消事件监听,并emit出最终宽度 */
      const width = document.querySelector(".right-border-shadow")?.clientWidth;
      document.removeEventListener("mousemove", handleMouseMove);
      document.removeEventListener("mouseup", handleMouseUp);
      ctx.emit("drugend", width);
    };

宽度处理

style={`width:${
            store.get("split-width")
              ? store.get("split-width")
              : props.minWidth
              ? props.minWidth
              : 384
          }px`}

优化

手动改变浏览器视窗宽度

nextTick(() => {
        ctx.emit("load", ctx);
        MutationObserver = window.MutationObserver;
        if (MutationObserver) {
          /* 监听浏览器的窗口变化,在部分情况下需要这个api */
          mo = new MutationObserver(function() {
            const __wm = document.querySelector("#rezie-id");
            // 只在__wm元素变动才重新调用 __canvasWM
            if (!__wm) {
              // 避免一直触发
              mo.disconnect();
              mo = null;
              ctx.emit("resize");
            }
          });
          mo.observe(document.querySelector("#rezie-id"), {
            attributes: true,
            subtree: true,
            childList: true,
          });
        }
      });

未生效,求指点

bug

父组件的onMounted钩子中获取子元素的slot元素节点报错,为null。目前的解决办法是在子组件的onMounted钩子中抛出一个load事件,父组件使用onLoad去处理接下来的逻辑。

git地址

仓库地址
预览地址

到此这篇关于vue3 可拖动的左右面板分割组件实现的文章就介绍到这了,更多相关vue3 可拖动左右分割面板内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用vue实现点击按钮滑出面板的实现代码

    在通信的时候容易出错,或者信息根本传不过来.那么这里就示例一下,怎么通过组件之间的通信完成点击事件. index.vue文件中: <div> <el-button type="primary" @click="onShow">点我</el-button> </div> 传递中介 <addForm :show="formShow" @onHide="formShow = false&q

  • vue使用Split封装通用拖拽滑动分隔面板组件

    前言 手动封装一个类似Iview中的Split组件,可将一片区域,分割为可以拖拽调整宽度或高度的两部分区域,最终效果如下: 开始 基础布局 在vue工程中创建SplitPane组件,引入页面使用. <template> <div class="page"> <SplitPane /> </div> </template> <script> import SplitPane from './components/sp

  • vuejs实现折叠面板展开收缩动画效果

    vuejs通过css3实现元素固定高度到auto高度的动画和auto高度到固定高度的动画. 循环列表,html: <template> <div class="newslist"> <ul> <li v-for="(item,index) in newslist" :key="index"> <p class="p" ref="liCon">{{i

  • vue自定义指令之面板拖拽的实现

    前言 在指令里获取的this并不是vue对象,vnode.context才是vue对象,一般来说,指令最好不要访问vue上的data,以追求解耦,但是可以通过指令传进来的值去访问method或ref之类的. vue指令 官方文档其实已经解释的蛮清楚了,这里挑几个重点的来讲. 1.arguments el: 当前的node对象,用于操作dom binding:模版解析之后的值 vNode: Vue 编译生成的虚拟节点,可以在上面获取vue对象 oldVnode: 使用当前指令上一次变化的node内

  • vue3 可拖动的左右面板分割组件实现

    目录 分解组件 左侧面板 右侧面板 入参分解 props slots 具体实现 如何拖动呢? 事件监听 宽度处理 优化 bug git地址 最近在使用vue的时候,遇到一个需求,实现左右div可通过中间部分拖拽调整宽度,本文就整理一下,分享给大家,具体如下: 效果图 分解组件 整体使用flex布局 左侧面板 面板的具体内容通过slot具名插槽传入. title通过prop传入 可拖动,为了保证内容样式不会被拖动所破坏,对面板的宽度设定最大值/最小值 右侧面板 右侧面板宽度随着左侧面板的宽度变化而

  • vue3.0实现点击切换验证码(组件)及校验

    本文实例为大家分享了vue3.0实现点击切换验证码(组件)及校验的具体代码,供大家参考,具体内容如下 先看效果 父组件 <template> <div class="login"> <van-field center clearable label="验证码" placeholder="输入验证码" v-model="verify" > <template #button> &l

  • vue3如何按需加载第三方组件库详解

    前言 以Element Plus为例,配置按需加载组件和样式. 环境 vue3.0.5 vite2.3.3 安装 Element Plus yarn add element-plus # OR npm install element-plus --save 完整引入 import { createApp } from 'vue' import ElementPlus from 'element-plus'; import 'element-plus/lib/theme-chalk/index.c

  • 利用Vue3和element-plus实现图片上传组件

    目录 前言 具体代码 图片上传 上传组件 前言 element-plus 提供了 uploader 组件,但是不好定制化,所以自己又造了个轮子,实现了一个图片上传的组件,它的预期行为是: 1.还没上传图片时,显示上传卡片 2.上传图片时显示进度条,隐藏上传卡片 3.上传成功时显示图片缩略图,上传失败则显示失败提示 4.支持上传图片的预览和删除 具体如下图所示: 具体代码 图片上传 这里使用的图床是牛图网,无需注册,貌似也没有图片大小的限制,但是请不要上传违规图像. <code>import a

  • vue-Split实现面板分割

    本文实例为大家分享了vue-Split实现面板分割的具体代码,供大家参考,具体内容如下 <template>   <div class="split-pane-wrapper">     <div class="pane pane-left" :style="{width:leftOffsetPercent}">       <button @click="handleClick"&g

  • Vue3 封装 Element Plus Menu 无限级菜单组件功能的详细代码

    目录 1 数据结构定义 1.1 菜单项数据结构 1.2 菜单配置数据结构 2 使用 tsx 实现封装 2.1 tsx 基本结构 2.2 定义 prop 2.3 递归实现组件 3 使用 SFC 实现菜单封装 3.1 封装菜单项的渲染 3.2 封装菜单组件 4 测试组件 4.1 菜单测试数据 4.2 测试页面 4.3 运行效果 总结: 本文分别使用 SFC(模板方式)和 tsx 方式对 Element Plus el-menu 组件进行二次封装,实现配置化的菜单,有了配置化的菜单,后续便可以根据路由

  • vue3封装侧导航文字骨架效果组件

    vue3 项目封装侧导航文字骨架效果组件-全局封装,供大家参考,具体内容如下 目的 当显示页面的时候,有些数据是需要从后台加载,网络不好的时候可能需要等待,那就可以做一个骨架层闪动动画,增加用户体验 大致步骤 - 需要一个组件,做占位使用.这个占位组件有个专业术语:骨架屏组件.       ·暴露一些属性:高,宽,背景,是否有闪动画. - 这是一个公用组件,需要全局注册,将来这样的组件建议再vue插件中定义. - 使用组件完成左侧分类骨架效果. 落地代码 一.封装组件 <template> &

  • 在vue3.0中封装button使用slot组件

    目录 封装button使用slot组件 需求 子组件 父组件引用 vue带你封装一个button 创建一个 ShowButton.vue 的组件 新建一个 Button.vue ShowButton.vue 内使用 封装button使用slot组件 需求 同一个button在不同页面使用,只有文字不一样;有的内容为登录有的为注册 下面我们自封一个button组件 子组件 <template> <!-- :type="type" 为按钮类型 :disabled=&quo

  • vue3.0封装轮播图组件的步骤

    接着上一篇文章,熟悉vue3.0的基本用法,和使用一段时间以后,开始准备开发适用于vue3.0使用的pc端的组件库.会陆续跟新一些组件库的写法和注意事项,有兴趣的同学可以多多关注哦,不多bb,开始. 开发一个轮播图组件,适用pc端,(暂无考虑app), 使用于vue3.0 + TS 大致的实现效果是这样: 图片自由轮播,对应圆点图片跳转,左右指示器跳转等.暴露以下options配置: 以上是主要的options,下面展开来说一下具体如何封装. 一:封装思想 在vue3.0和vue2.0中封装组件

  • vue3组件通信的方式总结及实例用法

    vue3组件通信方式为以下几种 props $emit $expose / ref $attrs v-model provide / inject Vuex mitt props <child :msg2="msg2" /> <script setup> const props = defineProps({ // 写法一 msg2:String // 写法二 msg2:{ type:String, default:'' } }) console.log(pro

随机推荐