vue 递归创建菜单_如何在Vue中创建类似中等的突出显示菜单

vue 递归创建菜单

by Taha Shashtari

由Taha Shashtari

如何在Vue中创建类似中等的突出显示菜单 (How to Create a Medium-Like Highlight Menu in Vue)

A cool feature in Medium is the highlight menu that pops up when you select some text. This menu contains buttons that allow you to perform certain actions on the selected text like highlight and share.

在一个很酷的功能中是当你选择一些文本在弹出的菜单中的亮点。 此菜单包含一些按钮,这些按钮使您可以对所选文本执行某些操作,例如突出显示和共享。

If you like this feature and you want to have it in your site, I’m going to show you how to create a reusable component that enables this behavior on the text it contains.

如果您喜欢此功能,并且希望在您的网站中使用它,我将向您展示如何创建可重用的组件,以在其包含的文本上启用此行为。

You can try a live demo on CodePen:

您可以在CodePen上尝试现场演示:

View the CodePen here.

在此处查看CodePen。

使用Vue CLI 3创建一个新项目 (Creating a new project with Vue CLI 3)

With Vue CLI 3 instant prototyping, we can rapidly run a Vue app with just a single *.vue file.

借助Vue CLI 3 即时原型 ,我们可以仅使用一个*.vue文件快速运行Vue应用程序。

Note that this is only used for creating prototypes, not for production.

请注意,这仅用于创建原型,而不用于生产。

First, make sure that you have this installed globally:

首先,请确保已在全球范围内安装了此软件:

npm install -g @vue/cli-service-global

npm install -g @vue/cli-service-global

In this app, we’ll only need two files: App.vue and Highlightable.vue.

在此应用程序中,我们仅需要两个文件: App.vueHighlightable.vue

Highlightable.vue is our reusable highlight menu component. And App.vue is the main page component.

Highlightable.vue是我们可重用的突出显示菜单组件。 而App.vue是主要的页面组件。

Create both files in any directory you want; then, run vue serve on App.vue.

在所需的任何目录中创建两个文件; 然后,在App.vue上运行vue serve

vue serve App.vue

实施App.vue (Implementing App.vue)

In App.vue, we'll add two paragraphs. One that can be highlighted, and one that can't.

App.vue中 ,我们将添加两个段落。 一种可以突出显示,另一种不能突出显示。

We’ll also import and use Highlightable.vue before even creating it. (This is helpful to see how we're going to use it.)

我们甚至会在创建之前导入并使用Highlightable.vue 。 (这有助于了解我们将如何使用它。)

Here’s how it should look in the end:

最终效果如下:

<template>  <div class="app">    <highlightable      @share="onShare"      @highlight="onHighlight"    >      <p>        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eveniet at debitis deserunt, optio rem eaque obcaecati non possimus nisi assumenda architecto exercitationem dolore quo praesentium, deleniti reiciendis sed ab nihil!      </p>    </highlightable>    <p>      <strong>This paragraph can't be highlighted.</strong> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Labore ipsam repellat, fugiat aut ex incidunt ut quisquam quasi consequatur ducimus quo in, cum soluta eos dolores tempore unde voluptate modi.    <;/p&gt;  </div></template&gt;<script>import Highlightable from './Highlightable'export default {  components: { Highlightable },  methods: {    onShare (text) {      console.log('share:', text)    },    onHighlight (text) {      console.log('highlight:', text)    }  }}</script><style scoped>* {  box-sizing: border-box;}.app {  width: 800px;  margin: 40px auto;  padding: 10px;  font-family: Verdana;  color: #333;  width: 100%;}p {  line-height: 1.5;}</style>

As you can see above, we're handling two events from Highlightable. These two events are the actions of the buttons in the highlight menu. These are just examples. You can change them to whatever you want.

正如您在上面看到的,我们正在处理Highlightable中的两个事件。 这两个事件是高亮菜单中按钮的动作。 这些仅仅是示例。 您可以将它们更改为任何您想要的。

实施Highlightable.vue (Implementing Highlightable.vue)

The template section consists of two parts: the menu element with buttons and <slot/> to display the text.

模板部分由两部分组成:带按钮的菜单元素和用于显示文本的<slo t />。

Let’s start with this code in the template:

让我们从模板中的以下代码开始:

<template>  <div>    <div      v-show="showMenu"      class="menu"    >      <span class="item">        Share      </span>      <span class="item">        Highlight      </span>      <!-- You can add more buttons here -->    </div>    <!-- The insterted text should be displayed here -->    <slot/>  </div></template>

Note that we're using showMenu, which we haven't created yet, to determine if we should display the menu.

请注意,我们使用尚未创建的showMenu来确定是否显示菜单。

Now let's move to the styling part.

现在,让我们转到样式部分。

Add the following CSS to <style> section:

将以下CSS添加到<sty le>部分:

&lt;style scoped>.menu {  height: 30px;  padding: 5px 10px;  background: #333;  border-radius: 3px;  position: absolute;  top: 0;  left: 0;  transform: translate(-50%, -100%);  transition: 0.2s all;  display: flex;  justify-content: center;  align-items: center;}.menu:after {  content: '';  position: absolute;  left: 50%;  bottom: -5px;  transform: translateX(-50%);  width: 0;  height: 0;  border-left: 6px solid transparent;  border-right: 6px solid transparent;  border-top: 6px solid #333;}.item {  color: #FFF;  cursor: pointer;}.item:hover {  color: #1199ff;}.item + .item {  margin-left: 10px;}&lt;/style>

Nothing is too complex here. .menu is for the highlight menu. menu:after is for the little triangle (arrow) in the bottom center of the menu.

这里没有什么太复杂的。 .menu用于突出显示菜单。 menu:aftermenu:after底部中心的小三角形(箭头)。

One important thing to note here is that .menu has an absolute position. We need this to position it above the selected text.

这里要注意的重要一件事是.menu具有absolute位置。 我们需要将其放置在所选文本上方。

Finally, let's move to the <script> section.

最后,让我们进入<scri pt>部分。

Let's start with the data.

让我们从data开始。

export default {  data () {    return {      x: 0,      y: 0,      showMenu: false,      selectedText: ''    }  }}
  • x and y are for positioning the menu.

    xy用于放置菜单。

  • showMenu to show/hide the menu.

    showMenu显示/隐藏菜单。

  • selectedText will contain the actual content of the selected text.

    selectedText将包含所选文本的实际内容。

Now, let's move to computed.

现在,让我们开始计算

computed: {  highlightableEl () {    return this.$slots.default[0].elm  }}

We only have a single computed property that returns the element used in the slot section of Highlightable. In our example, it would be the <;p> tag between <highlightable></highlightable>.

我们只有一个计算属性,该属性返回Highlightable的插槽部分中使用的元素。 在我们的示例中,将是tween <highlightable>< / highlightable>之间的< ; p>标记。

Then, let's add mounted and beforeDestroy hook functions.

然后,让我们添加mountedbeforeDestroy挂钩函数。

mounted () {  window.addEventListener('mouseup', this.onMouseup)},beforeDestroy () {  window.removeEventListener('mouseup', this.onMouseup)}

We use these to listen for mouseup event, which we handle inside onMouseup method.

我们使用它们来监听mouseup事件,该事件在onMouseup方法内部处理。

Now, let's create onMouseup method.

现在,让我们创建onMouseup方法。

methods: {  onMouseup () {    const selection = window.getSelection()    const selectionRange = selection.getRangeAt(0)    // startNode is the element that the selection starts in    const startNode = selectionRange.startContainer.parentNode    // endNode is the element that the selection ends in    const endNode = selectionRange.endContainer.parentNode    // if the selected text is not part of the highlightableEl (i.e. <p>)    // OR    // if startNode !== endNode (i.e. the user selected multiple paragraphs)    // Then    // Don't show the menu (this selection is invalid)    if (!startNode.isSameNode(this.highlightableEl) || !startNode.isSameNode(endNode)) {      this.showMenu = false      return    }    // Get the x, y, and width of the selection    const { x, y, width } = selectionRange.getBoundingClientRect()    // If width === 0 (i.e. no selection)    // Then, hide the menu    if (!width) {      this.showMenu = false      return    }    // Finally, if the selection is valid,    // set the position of the menu element,    // set selectedText to content of the selection    // then, show the menu    this.x = x + (width / 2)    this.y = y + window.scrollY - 10    this.selectedText = selection.toString()    this.showMenu = true  }}

Now let's update the template of Highlightable.vue to reflect the new changes.

现在,让我们更新Highlightable.vue的模板以反映新的更改。

<template>  <div>    <div      v-show="showMenu"      class="menu"      :style="{        left: `${x}px`,        top: `${y}px`      }"      @mousedown.prevent=""    >      <span        class="item"        @mousedown.prevent="handleAction('share')"      >        Share      </span>      <span        class="item"        @mousedown.prevent="handleAction('highlight')"      >        Highlight      </span>      <!-- You can add more buttons here -->    </div>    <!-- The insterted text should be displayed here -->    <slot/>  </div></template>

The changes are:

更改为:

  • Applied the positions to the menu element.

    将位置应用于菜单元素。
  • Added @mousedown.prevent="" to the menu element to prevent the menu from closing when clicking inside it.

    在菜单元素中添加了@mousedown.prevent="" ,以防止在内部单击时关闭菜单。

  • Added @mousedown.prevent="handleAction('share')" on share button to handle the clicked action. The same is for the highlight action.

    在共享按钮上添加了@mousedown.prevent="handleAction('share')"来处理单击的操作。 高亮操作也是如此。

Note that we're using mousedown event instead of click to prevent the text from getting unselected — which would cause the menu to close.

请注意,我们使用mousedown事件而不是click事件来防止未选中文本-这将导致菜单关闭。

The last thing we have to do is add the handleAction method.

我们要做的最后一件事是添加handleAction方法。

handleAction (action) {  this.$emit(action, this.selectedText)}

This method emits the action event and passes the selected text along with it. (We used this event in App.vue, remember?)

此方法发出action事件,并将所选文本与之一起传递。 (我们在App.vue中使用了此事件,还记得吗?)

With that, we're done! Now you have a reusable component that you can use to show a highlight menu for the selected text, just like Medium does.

这样,我们就完成了! 现在,您有了一个可重用的组件,可以像Medium一样使用它来显示所选文本的突出显示菜单。

Thanks for reading! By the way, I’m writing a book on how to build a complete single-page application from scratch using Vue. Check out the book’s landing page if you’re interested in learning more about what the book will cover:

谢谢阅读! 顺便说一句,我正在写一本关于如何使用Vue从头构建完整的单页应用程序的书。 如果您有兴趣了解有关该书涵盖内容的更多信息,请查看该书的登录页面:

翻译自: https://www.freecodecamp.org/news/how-to-create-a-medium-like-highlight-menu-in-vue-dc515f2dddef/

vue 递归创建菜单

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

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

相关文章

leetcode 376. 摆动序列(dp)

如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为摆动序列。第一个差&#xff08;如果存在的话&#xff09;可能是正数或负数。少于两个元素的序列也是摆动序列。 例如&#xff0c; [1,7,4,9,2,5] 是一个摆动序列&#xff0c;因为差值 (6,-3,5,-7,3…

在ASP.NET Atlas中调用Web Service——创建Mashup调用远端Web Service(基础知识以及简单示例)...

作者&#xff1a;Dflying Chen &#xff08;http://dflying.cnblogs.com/&#xff09; 注&#xff1a;Atlas中的Mashup极其复杂&#xff0c;其中涉及众多的对象与架构&#xff0c;为了写这篇文章&#xff0c;我花了不少时间学习研究。同时&#xff0c;关于这方面资源的匮乏简直…

java弹框形式输入_java中点击一个按钮弹出两个输入文本框的源代码

展开全部写了一个很简单的案例,可以参考和修改import java.awt.BorderLayout;import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JFrame;import…

sap wm内向交货步骤_内向型人在数据科学中成功的五个有效步骤

sap wm内向交货步骤Just like most attributes of humans, including both the bright and dark sides, being an introvert is no exception. This article was not written to inspire you as most articles about data science or engineering do. What we want is that by …

C# 学习之路--百度网盘爬虫设计与实现(一)

百度网盘爬虫 现在市面上出现了很多网盘搜索引擎&#xff0c;写这系列博文及爬虫程序的初衷&#xff1a; 更方面的查找资源学习C#学习爬虫的设计与实现记录学习历程自我监督 能力有限&#xff0c;如有不妥之处&#xff0c;还请各位看官点评。同在学习的网友~与君共勉。工具/库选…

实习生对企业的认识_如何成为您认识的超级明星实习生

实习生对企业的认识by Maple Ong由Maple Ong 如何成为您认识的超级明星实习生 (How to be The Superstar Intern You Know You Are) 遏制冒名顶替综合症&#xff0c;为即将到来的软件工程实习做准备 (Curb the Impostor Syndrome and get prepared for your upcoming Software…

7时过2小时是几时_2017最北师大版二年级下册数学第七单元《时、分、秒》过关检测卷...

二年级数学下册时分秒测试卷一、填一填。(每空1分&#xff0c;共36分)1.钟面上有()大格&#xff0c;()个小格&#xff0c;时针走1个大格是()时&#xff0c;分针走一个大格是()分。2.1分()秒()分1时1分15秒()秒3.1小时20分()分90分()小时()分 70秒()分()秒4.用时、分、秒填空a)我…

在没人相信的时候,你的坚持才真正可贵

2018 世界 VR 产业大会在南昌开幕&#xff0c;阿里巴巴创始人马云在演讲中说&#xff1a; “在人人都相信一个产业的时候&#xff0c;其实你已经没有机会了。在没有人相信的时候&#xff0c;你的坚持才是真正的珍贵。很多人是因为看见而相信&#xff0c;只有很少数的人是因为相…

leetcode 49. 字母异位词分组(排序+hash)

给定一个字符串数组&#xff0c;将字母异位词组合在一起。字母异位词指字母相同&#xff0c;但排列不同的字符串。 示例: 输入: [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 输出: [ [“ate”,“eat”,“tea”], [“nat”,“tan”], [“bat”] ] 代码 class S…

数据库备份策略 分布式_管理优秀的分布式数据团队的4种基本策略

数据库备份策略 分布式COVID-19 has forced nearly every organization to adapt to a new workforce reality: distributed teams. We share four key tactics for turning your remote data team into a force multiplier for your entire company.COVID-19迫使几乎每个组织都…

如何使用阿里云云解析API实现动态域名解析,搭建私有服务器

原文地址&#xff1a;http://www.yxxrui.cn/article/116.shtml 未经许可请勿转载&#xff0c;如有疑问&#xff0c;请联系作者&#xff1a;yxxrui163.com 公司的网络没有固定的公网IP地址&#xff0c;但是能够保证的是&#xff0c;每次动态分配的IP地址均为独立的公网IP&#x…

新手指南:dvwa_如何构建基本的Slackbot:新手指南

新手指南:dvwaBy Vishwa ShahVishwa Shah着 Update: code and tutorial updated on June 28 to reflect Slack API changes.更新&#xff1a;代码和教程已于6月28日更新&#xff0c;以反映Slack API的更改 。 Slackbots&#xff1a;为什么要使用它们&#xff1f; (Slackbots:…

java 加载class文件路径_动手实现MVC: 1. Java 扫描并加载包路径下class文件

背景用过spring框架之后&#xff0c;有个指定扫描包路径&#xff0c;然后自动实例化一些bean&#xff0c;这个过程还是比较有意思的&#xff0c;抽象一下&#xff0c;即下面三个点如何扫描包路径下所有的class文件如何扫描jar包中对应包路径下所有的class文件如何加载class文件…

leetcode 738. 单调递增的数字(贪心算法)

给定一个非负整数 N&#xff0c;找出小于或等于 N 的最大的整数&#xff0c;同时这个整数需要满足其各个位数上的数字是单调递增。 &#xff08;当且仅当每个相邻位数上的数字 x 和 y 满足 x < y 时&#xff0c;我们称这个整数是单调递增的。&#xff09; 示例 1: 输入: …

python+[:]+切片_我从C ++到Python的方式:概念上的改变

python[:]切片by asya f由asya f 我从C 到Python的方式&#xff1a;概念上的改变 (How I went from C to Python: a conceptual change) 介绍 (Introduction) People say that coding in Python is so easy that even a 6 year old can do it. This was the thought that I ha…

深度学习 免费课程_2020年排名前三的免费深度学习课程

深度学习 免费课程&#xff03;1 Fastai面向程序员的实用深度学习2020 (#1 Fastai Practical Deep Learning for Coders 2020) On 21 of August 2020, fastai released the new version of the fastai library and of their Deep Learning course!2020年8月21日&#xff0c;fas…

mysql复制主从集群搭建

近期搭了个主从复制。中间出了点小问题&#xff0c;排查搞定&#xff0c;记录下来1环境&#xff1a;虚拟机&#xff1a;OS:centos6.5Linux host2 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 x86_64 x86_64 GNU/LinuxserverIP192.168.18.66192.168.18.6…

java jolt tuxedo_java通过jolt调用tuxedo服务.xls

java通过jolt调用tuxedo服务.xls还剩20页未读&#xff0c;继续阅读下载文档到电脑&#xff0c;马上远离加班熬夜&#xff01;亲&#xff0c;喜欢就下载吧&#xff0c;价低环保&#xff01;内容要点&#xff1a;?private bea.jolt.pool.servlet.ServletSessionPoolManager bool…

你的周末时光是什么样的?

周末是一个特殊的假日&#xff0c;隔三差五就会有&#xff0c;来的容易去得也容易&#xff0c;即便如此&#xff0c;我们还是应该好好珍惜&#xff0c;周末可以做的事太多了&#xff0c;既可以用来减压&#xff0c;也可以为下一周的学习和工作充电&#xff0c;不管做什么&#…

leetcode 290. 单词规律(hash)

给定一种规律 pattern 和一个字符串 str &#xff0c;判断 str 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 str 中的每个非空单词之间存在着双向连接的对应规律。 示例1: 输入: pattern “abba”, str “dog…