首先来思考一个问题:是否有一种方法可以从子组件填充父组件的插槽?

最近一位同事问我这个问题,答案很简单:可以的。但我的解决方案可能和你想的完全不一样,这是涉及一个棘手的Vue架构问题,但也是一个非常有趣的问题。

为什么会有这个问题

在我们的应用程序中,我们有一个顶部栏,其中包含不同的按钮、搜索栏和其他一些控件。根据每个人所在的页面,它可能略有不同,因此我们需要一种基于每个页面配置它的方法。

为此,我们希望每个页面都能够配置操作栏。看起来很简单,但这里有个问题

这个顶部栏(我们称之为ActionBar)实际上是我们的主布局的一部分,结构如下:

根据你所在的页面/路线动态注入App的位置。

我们可以使用ActionBar上的一些插槽来配置它。但是,我们如何从App组件中控制这些插槽?

定义问题

首先,最好是尽可能清楚地知道我们要解决的问题。

我们来看一个具有一个子组件和一个插槽的组件:

我们可以这样填充Parent的插槽:

这里没什么特别的。。。

填充子组件的插槽很容易,这也是使用插槽的最常见方式。

但是,有没有一种方法可以控制从Child组件内部进入Parent组件slot的内容呢?

换种说法:我们可以让子组件填充父组件的插槽吗?来看看我想到的第一个解决方案。

向下使用 props,向上使用 event

数据流经组件树的唯一途径是使用props。而向上通信的方法是使用事件。这意味着,如果要让子组件与父组件进行通信,我们需要使用事件来实现。

因此,我们将使用事件来将内容传递到ActionBars槽中

我们将要放入插槽中的所有内容打包到SlotContent组件中。一旦创建了应用程序组件,我们就会发出slot-content事件,并传递我们要使用的组件。

我们的组件结构如下:

监听该事件,并将slotContent设置为我们的App组件发送给我们的任何内容。然后,使用内置的Component,就可以动态地渲染该组件。

但是,通过事件传递组件感觉很奇怪,并非是主流的做法。幸运的是,还有一种方法可以完全避免使用事件。

使用 $options

由于Vue组件只是 JS 对象,因此我们可以向它们添加所需的任何属性。无需使用事件传递插槽内容,我们只需将其作为字段添加到组件中即可:

在主页中通过 App.slotContent 获取对应的组件

这更像是静态配置,更美观、更简洁,但这仍然是不对的。

理想情况下,我们不会在代码中混合使用范式,所有操作应该都是以声明方式完成。

但是在这里,我们没有将我们的组件组合在一起,而是将它们作为 JS 对象传递。如果我们能以正常的Vue方式把我们想要的写在插槽里就好了。

考虑 Portal(传送门)

Vue 中的 Portal 技术 在 Vue 项目中,我们使用模板来声明 dom

嵌套关系,然而有时候一些组件需要脱离固定的层级关系,不再受制与层叠上下文,比如说 Modal 和 Dialog这种组件就希望能够脱离当前模板所在的层叠上下文。

在 Vue 中有两种方式来实现这种效果,一种是使用指令,操作真实 dom,使用熟知的 dom 操作方法将指令所在的元素 append到另外一个 dom 节点上去。另一种方式就是定义一套组件,将组件内的 vnode 转移到另外一个组件中去,然后各自渲染。

它们的工作方式和你想象的完全一样。你可以把任何东西从一个地方传送到另一个地方。在我们的例子中,我们将元素从DOM中的一个位置“传送”到另一个位置。

无论组件树如何显示,我们都可以控制组件在DOM中的显示位置。

例如,假设我们想要填充一个modal。但是我们的modal必须在根页面处渲染,这样我们才能正确地覆盖它。首先,我们要在modal中指定我们想要的:

然后,在我们的modal组件中,我们将拥有另一个将内容渲染出来的 portal:

这是一项改进,因为现在我们实际上是在编写HTML,而不仅仅是传递对象。它更具声明性,更容易查看应用程序中发生的事情。

由于 portal 在背后执行一些操作以在不同位置渲染元素,因此它完全打破了DOM渲染在Vue中工作方式的模型。看起来您正在正常渲染元素,但根本无法正常工作,这可能会引起很多混乱和沮丧。

还有一个很大的问题,稍后我们会讲到。

提升状态

“提升状态”是指将状态从子组件移动到父组件或祖父组件,将它向上移动到组件树中。

这可能对应用程序的体系结构产生较大的影响。对于我们的目的,这会是更简单的解决方案。

这里的“状态”是我们试图传递到ActionBar组件插槽中的内容。但是该状态包含在Page组件中,我们不能真正将 page 特定的逻辑移到layout组件中。我们的状态必须保留在我们正在动态渲染的Page组件内。

因此,我们必须提升整个Page组件才能提升状态。当前,我们的Page组件是Layout组件的子组件:

解除它需要我们将其翻转,并使Layout组件成为Page组件的子组件。我们的Page组件看起来像这样:

现在,我们的Layout组件将看起来像这样,我们可以在其中使用插槽插入页面内容:

但这还不能让我们自定义任何内容。我们必须在Layout组件中添加一些命名的插槽,以便我们可以传递应放置在ActionBar中的内容。

最简单的方法是使用一个插槽来完全替代ActionBar组件:

这样,如果你不指定“actionbar”插槽,默认使用ActionBar组件。但我们可以使用自己的自定义ActionBar配置覆盖此插槽:

对我来说,这是一种理想的处理方式,但是它确实需要我们重构页面的布局方式。对于界面复杂点的,这可能是一项艰巨的任务。

简化一下

当我们第一次定义问题时:

我们可以让子组件填充父组件的插槽吗?

但实际上,这个问题与props没有任何关系。更简单地说,它是关于使子组件控制在其自己的子树之外渲染的内容。

我们可以这样表述问题

组件控制在其子组件之外渲染的内容的最佳方法是什么?

通过这个镜头检查我们提出的每个解决方案,都会为我们提供一个有趣的新视角。

向父组件发出事件

数据流经组件树的唯一途径是使用 props。而向上通信的方法是使用事件。这意味着,如果要让子组件与父组件进行通信,我们需要使用事件来实现。

静态配置

只是将必要的信息提供给其他组件,而不是主动地要求另一个组件做事情。

传送门

组件无法控制其子树之外的内容。这里的每个方法都是让另一个组件执行我们的命令并控制我们真正感兴趣的元素不同的方式。

在这方面,使用 portal 更好的原因是它们允许我们将所有这些通信逻辑封装到单独的组件中。

提升状态

提升状态是一种比我们前面看到的3种更简单、更强大的技术,这里我们的主要限制是我们想要控制的内容在子组件之外。

最简单的解决方法是:

提升状态以及操纵该状态的逻辑,使我们可以拥有更大范围的组件,并将目标元素包含在该组件中。如果可以这样做,这是解决此特定问题以及所有相关问题的最简单方法。

请记住,这并不一定意味着要提升整个组件。你也可以重构你的应用程序,以将逻辑移到组件树中更高的组件中。

依赖注入

如果熟悉软件工程设计模式的人可能已经注意到,我们在这里所做的是依赖注入,这是我们在软件工程中已经使用了几十年的技术。

它的用途之一是编写易于配置的代码。在我们的例子中,,我们在使用的每个Page中以不同的方式配置Layout组件。

当调换Page和Layout组件时,我们正在执行所谓的控件反转。

在基于组件的框架中,父组件控制子组件的操作,因此我们选择让Page来控制Layout组件,而不是由Layout组件控制Page。

为了做到这一点,我们使用插槽为Layout组件提供完成任务所需的内容。

正如我们所看到的,使用依赖注入可以使我们的代码更加模块化和易于配置。

总结

我们讨论了解决这个问题的4种不同方法,展示了每种方法的优缺点。然后我们更进一步,将问题转化为一个更一般的问题,即控制组件子树之外的内容。

、提升状态和依赖项注入是两个非常有用的模式。它们是我们武器库中最好的工具,因为它们可以应用于无数的软件开发问题。

但最重要的是,希望你还能学会:

通过使用一些常见的软件模式,将一个丑陋解决方案的问题转变成一个非常优雅的问题。许多其他的问题都可以用这种方法解决,即把一个丑陋的、复杂的问题转化成一个更简单、更容易解决的问题。


原文:https://dev.to/michaelthiessen/advanced-vue-controlling-parent-slots-case-study-c3k/comments作者:Michael Thiessen 译者:前端小智 来源:dev

vue dialog控制右上角关闭按钮事件_高级 Vue 技巧:控制父类的 slot相关推荐

  1. Python定义点击右上角关闭按钮事件

    文章来自:https://www.cnblogs.com/iAmSoScArEd/p/11200029.html 爬虫.转载请注明出处. Python定义点击右上角关闭按钮事件 import tkin ...

  2. 初始化触发点击事件_【Vue原理】Event - 源码版 之 自定义事件

    专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本[2.5.17] Vue 的自定义事件很简单,就是使用 观察者模 ...

  3. vue在日历表上面创建事件_如何在R中创建颜色编码的日历

    vue在日历表上面创建事件 用颜色编码的日历可以快速简便地查看您是否实现了日常目标. 您是否符合销售或社交媒体帖子等日常业务指标? 或者,您如何实现个人目标,例如每天锻炼? 乍一看,您可以了解自己的工 ...

  4. vue aplayer 进度条无法拖动_为 Vue 的惰性加载加一个进度条

    // 每日前端夜话 第412篇// 正文共:1800 字// 预计阅读时间:8 分钟 简介 通常用 Vue.js 编写单页应用(SPA)时,当加载页面时,所有必需的资源(如 JavaScript 和 ...

  5. vue代码怎么变成小程序_使用vue编写h5公众号跳转小程序的实现代码

    前言:我使用vue编写的h5公众号,实现点击小程序入口,打开小程序,微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_App ...

  6. vue设置cookie的domain无效_【Vue.js入门到实战教程】16Tailwind 与 Bootstrap 的区别和使用入门...

    来源 | https://xueyuanjun.com/post/22065我们知道,从 Laravel 8 开始,自带前端脚手架代码默认兼容 Tailwind CSS 框架,取代了之前的 Boots ...

  7. vue 2个方法先后执行_浅析Vue的2个版本

    一.@vue/cli用法 安装 npm npm install -g @vue/cli yarn yarn global add @vue/cli 安装完成后可以使用 vue create 来创建一个 ...

  8. vue 前台文本修改触发事件_利用VBA代码禁用触发事件及对工作薄修改的保存方案...

    分享成果,随喜真能量.大家好,今日内容仍是和大家分享VBA编程中常用的简单"积木"过程代码,这些内容多是取至我的"VBA代码解决方案"教程中内容.NO.143- ...

  9. 调用某个按钮事件_高级UI晋升之触摸事件分发机制(一)

    更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 0. 前言 鉴于安卓分发机制较为复杂,故分为多个层次进行讲解,分别为基础篇.实践 ...

  10. vue实现上下滑动翻页_基于vue实现上下滑动翻页效果

    18年年底的时候,一直在做年度报告的H5页面,因为项目需要,需要实现上下滑动翻页,并且上滑的页面比正常页面的比例要缩小一定比例. 效果类似于http://www.17sucai.com/pins/de ...

最新文章

  1. Mac vscode 调试打印有问题 输出缓冲区 “\r\n“
  2. 公司新来的阿里p8,看了我做的APP和接口测试,甩给了我这份文档
  3. python做数据库管理系统_python+Django+mysql+bootstrap前端,数据库一次搞定)从头教你毕设实现一个简易好看的仓储物资管理之类系统...
  4. CF思维联系– Codeforces-989C C. A Mist of Florescence
  5. DiQuick Web UI 框架 V1.3 正式版发布
  6. [jzoj 4528] [GDOI2019模拟2019.3.26] 要换换名字 (最大权闭合子图)
  7. 谷歌浏览器xp32位_如何正确的配置系统的浏览器系列篇(五)——合同管理系统...
  8. 学软件测试必须要会Java吗_软件测试需要学什么?
  9. 【一起学习输入法】华宇拼音输入法开源版本解析(5)
  10. Dmoz中文目录收录的中文博客
  11. 2022-2027年(新版)中国石油化工行业发展建议及投资前景展望报告
  12. 单片机外部中断详解及程序
  13. Python 关键字(keyword)
  14. 银行理财产品的十个坑
  15. python中add方法_python中add函数怎么用
  16. 想知道北京的公交线路图吗?用python给你画出来
  17. 画出一阶系统单位阶跃响应、单位脉冲响应、单位斜坡响应曲线
  18. 设计模式:建造模式(组装电脑)
  19. libvirt Java 实现远程管理虚拟机
  20. 在本地安装使用-LTP

热门文章

  1. java多线程--容器类和其他工具类
  2. python+opencv中最近出现的一些变化( OpenCV 官方的 Python tutorial目前好像还没有改过来?) 记一次全景图像的拼接...
  3. Es6 类class的关键 super、static、constructor、new.target
  4. 书信用语“商祺”是的意思
  5. 【Spring-IOC】bean扫描器ClassPathBeanDefinitionScanner详解
  6. easyui刷新当前选项卡tabs
  7. 树和森林(Tree and Forest)
  8. dubbo如何利用spring扩展点完成初始化
  9. EF Code First学习笔记 初识Code First
  10. Insert Node in Sorted Linked List