如果我们试图创建一个没有根节点的vue模板,比如这样:
<template>
<div>Node 1</div>
<div>Node 2</div>
</template>
我们就会收到编译或运行时错误,因为模板必须具有单个根元素。
通常,我们通过在最外层包裹一层 div 来解决这个问题,但这个div元素一般没有啥使用,就是让模板符合单根需求。
<template>
<div><!--只是来包装一下-->
<div>Node 1</div>
<div>Node 2</div>
</div>
</template>
这样的方式通常问题不在,但是在某些情况下,拥有多根模板是必要的。在本文中,我们来探讨一下何时需要以及如何解决多根的问题。
某些情况下,可能需要组件渲染子节点数组以包含在父组件中。
例如,一些css特性需要非常特殊的元素层次结构才能正确工作,比如CSS grid或flex,不能在父元素和子元素之间使用包装器。
<template>
<div style="display:flex">
<!-- 如果子组件有多包裹一层那么 flex 不能正常工作-->
<FlexChildren/>
</div>
</template>
还有一个问题,在组件中添加包装元素可能会导致渲染无效的html。 例如,如果要构建table,则表行<tr>必须仅具有用于子项的表单元格<td>。
<template>
<table>
<tr>
<!--使用div包装器会使这个HTML无效-->
<TableCells/>
</tr>
</table>
</template>
简而言之,单根需求意味着在Vue中将无法返回子元素的组件的设计模式。
这个单根限制对于react也是一个问题,但是它在版本16中提供了一个称为fragments的功能。 要使用它,只需要将多根模板包装在特殊的React.Fragment元素中:
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
这将使子组件没有多余包装,还有一个简洁的短语法<>:
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
那么 Vue 是否也会引入 fragments?这可能不会很快,原因是虚拟dom差异算法依赖于具有单个根的组件。 根据Vue贡献者Linus Borg的说法:
“允许 fragments 需要对[diffing]算法进行重大更改...不仅要使其能够正常工作,而且还必须使其具有高性能。...这是一项非常繁重的任务”
函数组件没有单根限制,因为它们不需要像有状态组件那样在虚拟DOM中进行区分。这意味着,如果组件只需要返回静态HTML,那么拥有多个根节点也没什么问题。
还有一个警告:我们需要使用渲染功能,因为vue-loader当前不支持多根功能(尽管对此进行了讨论)。
export default {
functional: true,
render: h => [
h('tr', [
h('td', 'foo'),
h('td', 'bar'),
]),
h('tr', [
h('td', 'lorem'),
h('td', 'ipsum'),
])
];
});
-------------------------------------------
import TableRows from "TableRows";
new Vue({
el: '#app',
template: `<div id="app">
<table>
<table-rows></table-rows>
</table>
</div>`,
components: {
TableRows
}
});
还可以使用一种简单的方法来绕过单根限制。就是使用自定义指令,首先我们先所包裹的元素删除
之前的:
<parent>
<wrapper>
<child/>
<child/>
</wrapper>
</parent>
中间步骤:
<parent>
<wrapper/>
<child/>
<child/>
</parent>
最终:
<parent>
<!-- 删除 <wrapper/> -->
<child/>
<child/>
</parent>
要使它正常工作有点棘手,这里可以使用由Julien Barbay写的 vue-fragments 的插件。
vue-fragments可以作为一个插件安装到你的Vue项目中
import { Plugin } from "vue-fragments";
Vue.use(Plugin);
该插件注册了一个全局VFragment组件,将其用作组件模板中的包装器,类似于React片段的语法:
<template>
<v-fragment>
<div>Fragment 1</div>
<div>Fragment 2</div>
</v-fragment>
</template>
我不确定这个插件在所有的用例中有多健壮——它看起来可能是脆弱的——但在我做的实验中,它工作得很好。
作者:Anthony Gore
译者:前端小智
来源:vuejsdevelopers
在项目中往往会有这样的需求: 弹出框(或Popover)在 show 后,点击空白处可以将其 hide。 针对此需求,整理了三种实现方式,大家按实际情况选择。我们做项目肯定会用到 UI 框架,常见的 Element 中的组件提供了这样的方法
在javascript中提供了很多操作DOM文档的方法,当然也包括创建一个节点,下面我们来看一下JavaScript如何创建一个创建一个文本节点(text)。
在JavaScript中,nodeValue属性用于根据节点的类型设置或返回节点的值,该属性的值取决于节点的类型(nodeType)。下面本篇文章就来给大家介绍一下nodeValue属性,希望对大家有所帮助。
JavaScript中的所有节点类型都继承自Node类型,因此所有节点类型都共享相同的基本属性和方法。每个节点都有一个nodeType属性,用于表明节点的类型。
rootMargin设置不一定会有效,有效的几个情况如下:1.设置了overflow的父级节点+rootMargin,如下,2.如果不设置root,即想要交叉对象是窗口的时候,需要去除滚动的父级节点,将html、body的overflow也去除(也去除的意思是不要设置),如下
Vue3中的teleport API极大方便了在Vue3业务逻辑中操作移动Dom位置。当teleportToTarget 为#idTest时,节点会被传输到 #idTest 节点中,等同于
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!