记录--Vue 右键菜单的秘密:自适应位置的实现方法

这篇具有很好参考价值的文章主要介绍了记录--Vue 右键菜单的秘密:自适应位置的实现方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

记录--Vue 右键菜单的秘密:自适应位置的实现方法

下图这个情景,你是否也遇到过?

当你右键点击网页上的某个元素时,弹出的菜单被屏幕边缘遮挡了,导致你无法看清或选择菜单项?

记录--Vue 右键菜单的秘密:自适应位置的实现方法

上图中右键菜单的选项并不是固定不变的,它会根据不同的元素或场景来显示不同的选项。

也就是说,菜单的内容和大小都是动态生成的,而不是预先设定好的。

这就给我们调整菜单位置带来了一定的难度,不过当你看完这篇文章所有的问题都不再是问题。

分析问题

遇事不决先画图,我们要解决的问题本质上就是菜单生成的位置,所以我们画个图来找一下头绪:

记录--Vue 右键菜单的秘密:自适应位置的实现方法

我们通过上图可以知道,菜单能否在视口中放得下,取决于两个条件:

  1. windowW(视口宽度) - mouseX(鼠标 x 坐标) > menuW(菜单宽度)
  2. windowH(视口高度) - mouseY(鼠标 y 坐标) > menuH(菜单高度)

当同时满足这两个条件的时候说明菜单放得下,那我们就要思考如果不满足条件的时候怎么办了。

如果不满足条件一说明宽度放不下,那我们就让菜单生成到鼠标的左边 mouseX - menuW,就像下图这样。

记录--Vue 右键菜单的秘密:自适应位置的实现方法

 如果不满足条件二说明高度放不下,那我们就让菜单贴底 windowH - menuH,像这样。

记录--Vue 右键菜单的秘密:自适应位置的实现方法

那如果两个条件都不满足,就同时应用两个解决办法。

解决问题

先来看一下现在的代码:

<template>
  <div ref="containerRef">
    <slot></slot>
    <Teleport to="body">
      <div v-if="showMenu" class="context-menu" :style="{
        left: mouseX + 'px',
        top: mouseY + 'px',
        }">
        <div class="menu-list">
          <div @click="handleClick(item)" class="menu-item" v-for="(item, i) in menu" :key="item.label">
            {{ item.label }}
          </div>
        </div>
      </div>
    </Teleport>
  </div>
</template>
<script setup>
  import { ref } from 'vue';
  import useContextMenu from './useContextMenu';
  const props = defineProps({
    menu: {
      type: Array,
      default: () => [],
    },
  });
  const containerRef = ref(null);
  const { mouseX, mouseY, showMenu } = useContextMenu(containerRef);

  function handleClick() {
    showMenu.value = false;
  }
</script>

看到我们现在是直接将鼠标的坐标赋值给了菜单,那么接下来就要给菜单一个经过计算的合适位置。

我们知道视口的大小、鼠标的位置、菜单的大小都是会变化的,所以这几个数据都要是响应式。

现在仅仅知道鼠标的位置,还需要知道视口与菜单的大小。

视口大小我们写一个函数来监听视口大小的变化:

import { ref } from "vue";
const windowW = ref(document.documentElement.clientWidth);
const windowH = ref(document.documentElement.clientHeight);

window.addEventListener("resize", () => {
  windowW.value = document.documentElement.clientWidth;
  windowH.value = document.documentElement.clientHeight;
});

export default function () {
  return {
    windowW,
    windowH,
  };
}
而菜单的大小可以利用之前写过的一个自定义指令来监听菜单大小的变化,代码如下:
const map = new WeakMap();
const ob = new ResizeObserver((entries) => {
  for (const entry of entries) {
    // 这个元素对应的回调函数?
    const handler = map.get(entry.target);
    if (handler) {
      const box = entry.borderBoxSize[0];
      handler({
        width: box.inlineSize,
        height: box.blockSize,
      });
    }
  }
});

export default {
  mounted(el, binding) {
    // 监视尺寸变化
    ob.observe(el);
    map.set(el, binding.value);
  },
  unmounted(el) {
    // 取消监听
    ob.unobserve(el);
  },
};

现在这些值我们都已经知道了,我们去实现一下。

<template>
  <div ref="containerRef">
    <slot></slot>
    <Teleport to="body">
      <!-- 将计算好的位置赋值给菜单 -->
      <div v-if="showMenu" class="context-menu" :style="{
          left: pos.posX + 'px',
          top: pos.posY + 'px',
        }">
        <!-- 指令为全局指令,在菜单上使用指令来监听菜单尺寸的变化并触发函数 -->
        <div v-size-ob="handleSize" class="menu-list">
          <div @click="handleClick(item)" class="menu-item" v-for="(item, i) in menu" :key="item.label">
            {{ item.label }}
          </div>
        </div>
      </div>
    </Teleport>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import useContextMenu from './useContextMenu';
import { computed } from '@vue/reactivity';
// 引入监听视口大小的函数
import useViewport from './useViewport';
const props = defineProps({
  menu: {
    type: Array,
    default: () => [],
  },
});
const containerRef = ref(null);
const { mouseX, mouseY, showMenu } = useContextMenu(containerRef);

// 声明两个响应式变量,用来记录菜单大小的变化。
const menuW = ref(0);
const menuH = ref(0);
function handleSize({ width, height }) {
  menuW.value = width;
  menuH.value = height;
}
// 获得视口的大小
const { windowW, windowH } = useViewport();
// 计算属性,用来计算菜单合适的位置
const pos = computed(() => {
  let posX = mouseX.value;
  let posY = mouseY.value;
  // 宽度放不下生成新的位置
  if (mouseX.value > windowW.value - menuW.value) {
    posX = mouseX.value - menuW.value
  }
  // 高度放不下生成新的位置
  if (mouseY.value > windowH.value - menuH.value) {
    posY = windowH.value - menuH.value
  }
  return {
    posX,
    posY,
  };
});

function handleClick() {
  showMenu.value = false;
}
</script>

我们现在来看一下效果如何。

记录--Vue 右键菜单的秘密:自适应位置的实现方法

效果完美!

总结

这样,我们就实现了一个简单的右键菜单,它可以根据鼠标的位置和视口的大小自动调整菜单的位置,避免被遮挡。

这个功能虽然看起来不起眼,但是却能提高用户的体验和操作的便捷性。

当然,这个功能还有很多可以改进的地方,比如菜单的样式、动画、交互等等。

本文转载于:

https://juejin.cn/post/7250284380231712828

如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

 记录--Vue 右键菜单的秘密:自适应位置的实现方法文章来源地址https://www.toymoban.com/news/detail-710466.html

到了这里,关于记录--Vue 右键菜单的秘密:自适应位置的实现方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3 如何实现一个函数式右键菜单(ContextMenus)

    前言: 最近在公司 PC 端的项目中使用到了右键出现菜单选项这样的一个工作需求,并且自己现在也在实现一个偶然迸发的 idea ( 想用前端实现一个 windows 系统从开机到桌面的 UI ),其中也要用到右键弹出菜单这样的一个功能,个人觉得这个实现还不错,特来分享🎁。 tips:

    2024年02月06日
    浏览(49)
  • Windows注册表开机自启,右键菜单,运行的位置介绍

    开机自启可以把可执行文件的快捷方式放到StartUp目录中,也可以在注册表中实现,大多数都是在勾选设置后修改注册表中的值,这个注册表项的名称如下: 他的字符串值由名称和数据组成,名称就是app的名自定义,数据的值是可执行文件的绝对路径。 在打开运行时如果运行

    2024年02月04日
    浏览(48)
  • Vue3 + Element Plus 实现动态标签页及右键菜单

    目录 先上图  使用el-dropdown绑定右键菜单,为每个tab页绑定一个右键 右键菜单生效后控制每个下拉项的禁用与显示(每一项代表一个功能) 每个右键项对应的功能  控制每次只显示一个右键 完整代码         只有首页的情况         多个tab页的情况  

    2024年02月07日
    浏览(49)
  • QT基础:event 函数重载、筛选鼠标按压事件、获取鼠标位置、右键显示菜单、修改鼠标样式功能演示

    这里演示的是QT基础,主要包含: event 函数重载、筛选鼠标按压事件、获取鼠标位置、右键显示菜单、修改鼠标样式等功能演示, 适合初学者食用 。 演示功能:点击鼠标左键、右键、中键、左右键同时点击,输出鼠标当前坐标;按下鼠标中键,鼠标样式被替换,按下鼠标左

    2024年02月09日
    浏览(48)
  • git bash右键菜单失效解决方法

    git bash右键菜单失效解决方法 这几天重新更新了git,直接安装新版本后,右键菜单失效找不到了。找了好几个博客,发现都不全面,最后总结一下解决方法: (1)按win+r,输入regedit打开注册表,然后分别修改4个位置路径,修改为最后安装的软件的路径。 (2).修改如下四处

    2024年01月24日
    浏览(43)
  • vue中,右键菜单组件v-contextmenu的使用

    vue中,右键菜单组件v-contextmenu的使用 1、效果 右键菜单之禁用和子菜单 2、流程 第一步:安包 第二步:引入 src/main.js package.json 第三步:使用 效果1-右键菜单之禁用和子菜单 index.vue 效果2-基本效果 index.vue 3、使用说明api npm地址——https://www.npmjs.com/package/v-contextmenu 另一个参

    2024年02月06日
    浏览(44)
  • QTreewidget右键菜单功能实现

    QTreewidget有一个信号继承自QWidget的信号void QWidget::customContextMenuRequested(const QPoint pos);我们来看看官方介绍: 简单翻译一下:当widget的 contextMenuPolicy即上下文菜单属性是 Qt::CustomContextMenu,并且用户已request widget上的上下文菜单时(也就是点了右键),会发出此信号。位置 pos 是wi

    2024年02月16日
    浏览(34)
  • Vue单页面实现el-tree el-breadcrumb功能、el-tree右键点击树节点展示菜单功能、树节点编辑节点字段名称功能

    (1) 点击el-tree节点 使用el-breadcrumb展示选中树节点及父项数据         重点: handleNodeClick方法、getTreeNode方法 (2) 选择el-breadcrumb-item设置el-tree节点选中             必须设置属性: current-node-key=\\\"currentNodeKey\\\"  、 node-key=\\\"id\\\"           重点: 设置树节点渲染 this.$refs.tree.set

    2024年02月16日
    浏览(51)
  • Windows11桌面右键菜单恢复为win10操作方法_win11修改邮件菜单

    输入下面的命令 重启之后右键菜单,恢复为win10样式。 恢复Win11新右键菜单的方法

    2024年02月11日
    浏览(62)
  • TS使用 ‘vue-context-menu‘;右键打开菜单,内附安装流程

    1.安装包 2.引入  3.右击tree的节点发生的事件,阻止冒泡和默认事件,然后启用vue-contextMenu的方法 枚举 i18里的数据:  右键打开面板 展示哪些数据 的方法: 安装使用vue-context-menu流程

    2024年03月15日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包