记录-VueJs中如何使用Teleport组件
Posted 林恒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录-VueJs中如何使用Teleport组件相关的知识,希望对你有一定的参考价值。
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
在DOM
结构相对比较复杂,层级嵌套比较深的组件内,需要根据相对应的模块业务处理一些逻辑,该逻辑属于当前组件
但是从整个页面应用的视图上看,它在DOM
中应该被渲染在整个vue
应用外部的其他地方,不能影响组件的结构
比较常见的应用场景:就是全屏的模态框,控制元素的位置,也是可以处理的,但是比较麻烦
在理想情况下,我们希望在具体的组件中,给元素绑定的事件,与具体要控制的DOM
元素结构在同一个组件中,具体的位置处,保持一定的相关联性
而不用特意的把一些DOM
结构给分离出去,然而,在同一组件中,触发模态框的按钮和模态框本身在同一组件中
因为他们都与组件的开关状态有相关联,模态框与按钮一起渲染在应用DOM
结构很深的地方,会导致模态框的css布局位置非常难控制
鉴于这样的场景和困难,Vue
官方提供了一个Teleport
组件,很好的可以解决这个问题,让开发者不需要顾虑DOM
结构的问题
01-组件套组件层次结构很深时
比如:现在有两个组件,父组件,子组件,在后代组件内,添加一个按钮,弹出一个模态框,让它在页面垂直水平居中显示
如下所示,父组件如下所示App.vue
<template> <div class="App"> 我是父组件 <Child /> </div> </template> <script setup> import Child from "./Child.vue" </script> <style> .App width: 400px; height: 400px; background:red; </style>
如下是Child
组件,示例代码如下所示Child.vue
,我们需要在孙(后代)组件,添加一个按钮,点击按钮,弹出一个弹框,水平垂直居中显示在页面中央
<template> <div class="child"> <p>我是子组件</p> <button @click="isModel=true">打开模态框</button> <div class="mask-dialog" v-if="isModel"> <div class="box"> <h2>我是标题</h2> <div>我是弹框内容</div> <div> <button @click="isModel=false">关闭</button> </div> </div> </div> </div> </template> <script setup> import ref from "vue"; let isModel = ref(false); </script> <style> .child width: 300px; height:300px; background:green; /**灰色遮罩层 */ .mask-dialog width: 100%; height:100%; position:absolute; left:0; top:0; background:rgba(0,0,0,0.5) .box width: 200px; height:200px; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); background:pink; text-align:center; </style>
上面的子组件中有一个button
按钮来触发打开当前组件的模态框,里面存在着控制弹框的显示和隐藏的逻辑,当嵌套的组件比较深,复杂时
如果父级元素存在定位,那在控制子元素的位置时,用css
的transform
或者position:absolute
,参照对象的变更,会破坏布局结构,会出现一些css
样式
控制的问题,解决起来会非常的痛苦
那这个Teleport
组件就是为了解决这类问题,可以将指定的DOM
结构片段,独立于到组件外面去,不受当前组件布局结构的影响
经过Teleport
的修改后
<template> <div class="child"> <p>我是子组件</p> <button @click="isModel=true">打开模态框</button> <Teleport to="body"> <div class="mask-dialog" v-if="isModel"> <div class="box"> <h2>我是标题1</h2> <div>我是弹框内容</div> <div> <button @click="isModel=false">关闭</button> </div> </div> </div> </Teleport> </div> </template> <script setup> import ref from "vue"; let isModel = ref(false); </script> <style> .child width: 300px; height:300px; background:green; /**灰色遮罩层 */ .mask-dialog width: 100%; height:100%; position:absolute; left:0; top:0; background:rgba(0,0,0,0.5) .box width: 200px; height:200px; position:absolute; left:50%; top:50%; transform:translate(-50%,-50%); background:pink; text-align:center; </style>
<Teleport>
接收一个 to prop
来指定传送的目标。to
的值可以是一个 CSS
选择器字符串,或id
,也可以是一个 DOM
元素对象。这段代码的作用就是告诉 Vue
把以下模板片段传送到 body
标签下
<Teleport to="#some-id">html结构代码</Teleport> <Teleport to=".some-class">html结构代码</Teleport> <Teleport to="body">html结构代码</Teleport> <Teleport to="html">html结构代码</Teleport>
02-Teleport组件
它是Vue
官方提供的一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM
结构外层的位置去 也就是一种能够将我们的组件html
结构移动到指定位置的技术
<teleport to="移动到指定的位置,可以是html,body,或id,class"> 里面是Html结构模板内容 </teleport>
注意
<Teleport>
挂载时,传送的 to
目标必须已经存在于DOM
中。理想情况下,这应该是整个 Vue
应用 DOM
树外部的一个元素。如果目标元素也是由 Vue
渲染的,你需要确保在挂载 <Teleport>
之前先挂载该元素
这个teleport
将指定的模板html
,放置到页面当中指定的位置处,它是有条件的,不是可以任意传送的
在安装组件之前,目标元素必须存在,即,目标不能由组件本身呈现,理想情况下应该位于整个Vue
组件树之外。
如下代码是不行的
<template> <div class="header"> <Teleport to=".content"> <div>我是头部的内容</div> </Teleport> </div> <div class="footer"> 底部内容 <div class="content"></div> </div> </template> <script setup> </script> <style lang="less"> h1 color: red; </style>
03-需要知道的
teleport
只是改变了渲染的 DOM
结构,它不会影响组件间的逻辑关系。也就是说,如果 <Teleport>
包含了一个组件,那么该组件始终和这个使用了 <teleport>
的组件保持逻辑上的父子关系。传入的 props
和触发的事件也会照常工作。
这也意味着来自父组件的注入也会按预期工作,子组件将在 Vue Devtools
中嵌套在父级组件下面,而不是放在实际内容移动到的地方
位置移动了,提现在结构模板上,但是数据逻辑依旧存在关联的
04-如何禁用 Teleport
在某些场景下可能需要视情况禁用 <Teleport>
。举例来说,我们想要在桌面端将一个组件当做浮层来渲染,但在移动端则当作行内组件。我们可以通过对 <Teleport>
动态地传入一个 disabled prop
来处理这两种不同情况
<Teleport :disabled="isMobile"> ... </Teleport>
05-多个 Teleport 共享目标时
一个可重用的模态框组件可能同时存在多个实例。对于此类场景,多个 <Teleport>
组件可以将其内容挂载在同一个目标元素上,而顺序就是简单的顺次追加,后挂载的将排在目标元素下更后面的位置上
比如下面这样的用例
<Teleport to=".content"> <div>A</div> </Teleport> <Teleport to=".content"> <div>B</div> </Teleport>
渲染的结果为
<div class="content"> <div>A</div> <div>B</div> </div>
总结
这个teleport
组件在实际开发中还是很实用的,能够解决当组件嵌套层级很深,而后代组件中的模板,想要脱离当前组件结构,解决css
布局层面的干扰,那就可以用这个teleport
组件
本文转载于:
https://juejin.cn/post/7217731723509547069
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
在 VueJS 中调度后如何发出事件?
【中文标题】在 VueJS 中调度后如何发出事件?【英文标题】:How do I emit an event after dispatch in VueJS? 【发布时间】:2017-12-25 14:14:19 【问题描述】:我有一个带有行网格的父组件,我正在使用 vuex 来传递数据,当我添加一条新记录时,我想在模式窗口中打开新添加的记录。我正在发出一个事件并使用第一条记录(索引 = 0)打开模式。问题在于,由于它是使用 vuex“操作”添加记录的 ajax 调用,因此发出发生在添加记录之前。如何等到记录添加事件?或者有更好的方法吗?
下面是代码:
<!-- Grid Component -->
<grid>
<addrow @newrecordadded="openNewlyAddedRecord"></addrow>
<gridrow v-for="row in rows" :key="row._id"></gridrow>
</grid>
computed:
rows()
return this.$store.state.rows;
,
methods:
openNewlyAddedRecord()
this.openmodal(this.rows[0])
我的商店.js
state:
rows : []
所以在addrow
组件中,一旦用户点击提交表单,它就会分派到 vuex
methods:
onsubmit()
this.$store.dispatch('addrow',this.newrow);
this.$emit("newrecordadded");
actions.js
addrow( commit,state , payload)
var url = "/add";
Axios.post(url,payload)
.then(function(response)
commit('addnewrow',response.data);
);
mutations.js
addnewrow(state,payload)
state.rows.unshift(payload);
或者我们可以传递一个回调函数来调度吗?
【问题讨论】:
【参考方案1】:您可以让 addrow 操作返回一个承诺,如下所示:
addrow( commit,state , payload)
var url = "/add";
return Axios.post(url,payload)
.then(function(response)
commit('addnewrow',response.data);
);
您现在可以在组件的 onsubmit 方法中执行以下操作:
this.$store.dispatch('addrow',this.newrow).then(() => this.$emit("newrecordadded");)
【讨论】:
不需要包装承诺。return Axios.post(...).then(...)
可以。以上是关于记录-VueJs中如何使用Teleport组件的主要内容,如果未能解决你的问题,请参考以下文章