什么是插槽
slot是HTML <slot>
元素 , 是 Web 组件内的一个占位符。该占位符可以在后期使用自己的标记语言填充,这样您就可以创建单独的 DOM 树,并将它与其它的组件组合在一起。这个是官方解释看起来很晦涩,用人话说的意思是“Slot插槽是个占位符(就是一个占位置的),它可以和其它组件一起合用,就是他是可以复用,比如一个模态框组件我在底部按钮那里加了个插槽,如果别人引用那个组件,不修改那底部按钮就按组件里设置的使用,如果加上slot的name就是启用插槽对底部按钮进行修改,你可以去掉按钮或者修改按钮的个数都全凭君意”。
template是什么?
各位是不是很奇怪我们说插槽为什么讲template,是不是要说埃尔斯在挂羊头卖狗肉,各位稍安勿躁,听我娓娓道来。在HTML中solt一般与template合用,做成一个个可以复用的组件。
1、<template>
标记用作容纳页面加载时对用户隐藏的 HTML 内容的容器。如果您有一些需要重复使用的 HTML 代码,则可以使用 <template>
标记。也就是说<template>
包裹的内容是隐藏的在浏览器中不会渲染出来
2、<template>
中的内容可以稍后使用 JavaScript 呈现。也就是说让<template>
包裹的内容在浏览器中渲染需要使用js去创造一个dom节点去挂载到HTML中任意一处dom下就能看得到<template>
里的内容了。
一个完整的是slot组件是怎样的?
代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<template id="element-details-template">
<style>
details {font-family: "Open Sans Light", Helvetica, Arial, sans-serif }
.name {font-weight: bold; color: #217ac0; font-size: 120% }
h4 {
margin: 10px 0 -8px 0;
background: #217ac0;
color: white;
padding: 2px 6px;
border: 1px solid #cee9f9;
border-radius: 4px;
}
.attributes { margin-left: 22px; font-size: 90% }
.attributes p { margin-left: 16px; font-style: italic }
</style>
<details>
<summary>
<code class="name"><<slot name="element-name">NEED NAME</slot>></code>
<i class="desc"><slot name="description">NEED DESCRIPTION</slot></i>
</summary>
<div class="attributes">
<h4>Attributes</h4>
<slot name="attributes"><p>None</p></slot>
</div>
</details>
<hr>
</template>
<element-details>
<!-- 下面没有加slot的内容p标签在浏览器中渲染不出来 -->
<p>默认模板----</p>
</element-details>
<element-details>
<!-- 下面没有加slot的内容在浏览器中渲染不出来 -->
<p>wdfwerwer</p>修改传递下来数据---
<a slot="attributes"><p>wwwe334ee</p></a>
</element-details>
</body>
<script>
customElements.define('element-details',
class extends HTMLElement {
constructor() {
super();
var template = document
.getElementById('element-details-template')
.content;
const shadowRoot = this.attachShadow({mode: 'open'})
.appendChild(template.cloneNode(true));
}
})
</script>
</html>
运行结果如下所示:
第一个是默认的模板组件显示,没有任何改变渲染出来。
第二个是改了attributes的slot内容,显示了我修改的内容。
在引用的时候组件里包裹的没有加slot属性的内容没有被渲染出来,如我在代码的注释里所描述的一样。
现在说完执行完的结果我们来聊聊组件里<template>
里的事,这里面到底干了啥?
1)<template>
里的内容没有被js创造成element-details组件前是没有渲染的,不然就会生成三块内容,而不是两块。
2)<template>
里有<h4>``<i>
等标签和<slot>
标签,进行混用,也就是说<slot>
标签可以和其他标签混用生成业务组件。
3)<template>
]用<slot>
标签和<slot>
标签的属性生成一个 命名的槽 (named slots):
<slot name="element-name">
<slot name="description">
<slot name="attributes">
<template>
包裹 命名的槽 (named slots) 在<element-details>
元素中。
4)我们要引用组件和修改插槽里的数据,只要在标签中将相应的插槽名赋值slot属性就行了如上面代码所示的,将attributes赋值给slot
<element-details>
<!-- 下面没有加slot的内容在浏览器中渲染不出来 -->
<p>wdfwerwer</p>修改传递下来数据---
<!-- 下面将插槽名赋值给slot的属性内容在浏览器中能渲染出来 -->
<a slot="attributes"><p>wwwe334ee</p></a>
</element-details>
在vue中插槽是怎么使用的?
在vue中使用插槽有两种半方式。
1、直接像web component里一样使用<slot>
标签包裹。
建立一个<FancyButton>
的组件,它的模板代码如下:
<button class="fancy-btn">
<slot></slot> <!-- 插槽插口 -->
</button>
这个和web component里一样,有一个<slot>
标签,这里<slot>
元素是一个插槽的插口,标示了父元素提供的插槽内容将在哪里被渲染。
这里要引用这个FancyButton组件实现这个插槽作用的代码如下所示:
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
这段代码作用如下图所示:
最终渲染出的 DOM 是这样:
<button class="fancy-btn">
Click me!
</button>
插槽内容还可以是任意合法的模板内容。例如我们可以传入多个元素,甚至是组件,就是我们想插什么内容都可以。
1.5 具名插槽。
表现形式代码如下:
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
这里的name=“header”,name="footer"就是具名的slot.
使用 JavaScript 函数可能更有助于你来理解具名插槽:
// 传入不同的内容给不同名字的插槽
BaseLayout({
header: `...`,
default: `...`,
footer: `...`
})
// <BaseLayout> 渲染插槽内容到对应位置
function BaseLayout(slots) {
return (
`<div class="container">
<header>${slots.header}</header>
<main>${slots.default}</main>
<footer>${slots.footer}</footer>
</div>`
)
}
2、v-slot实现插槽功能,它的缩写为#。表示具名插槽或准备接收 prop 的插槽。
代码如下:
<!-- 具名插槽 -->
<BaseLayout>
<template v-slot:header>
Header content
</template>
<template v-slot:default>
Default slot content
</template>
<template v-slot:footer>
Footer content
</template>
</BaseLayout>
<!-- 接收 prop 的具名插槽 -->
<InfiniteScroll>
<template v-slot:item="slotProps">
<div class="item">
{{ slotProps.item.text }}
</div>
</template>
</InfiniteScroll>
<!-- 接收 prop 的默认插槽,并解构 -->
<Mouse v-slot="{ x, y }">
Mouse position: {{ x }}, {{ y }}
</Mouse>
在React中插槽是怎么使用的?
在普通web组件中和vue中的使用都已介绍,在React中呢,又该怎么样呢?
在我们React中组件里直接包裹一些html标签,html标签里的内容会不会显示呢?来我们来上代码:
import React, { Component } from 'react'
export default class MySlot extends Component {
render() {
return (
<div>
<div>MySlot--Parent</div>
<Child>
<p>111111</p>
</Child>
</div>
)
}
}
class Child extends Component {
render() {
return (
<div>Child</div>
)
}
}
上面代码运行结果如下图所示:
由此可见<p>111111</p>
并没有渲染出来。那么我们要使它渲染出来,得怎么修改呢?欲知后事如何请听下回。。。别急,我现在道来。组件中props有一个固定的children属性去在Child组件中占一个位,做成插槽。代码如下所示:
import React, { Component } from 'react'
export default class MySlot extends Component {
render() {
return (
<div>
<div>MySlot--Parent</div>
<Child>
<p>111111</p>
</Child>
</div>
)
}
}
class Child extends Component {
render() {
return (
<div>
<div>Child</div>
{/* vue中有slot这个标签去表示插槽,React中是props属性中固定的children属性表示 */}
<div>{this.props.children}</div>
</div>
)
}
}
运行结果:
由此11111给渲染出来了。
那如果父组件中传递的html比较多呢又会有什么样的效果呢,上代码:
import React, { Component } from 'react'
export default class MySlot extends Component {
render() {
return (
<div>
<div>MySlot--Parent</div>
<Child>
<div><p>111111</p> </div>
<div><h2>222222</h2> </div>
<div><i>333333</i> </div>
</Child>
</div>
)
}
}
class Child extends Component {
render() {
console.log('this.props.children',this.props.children)
return (
<div>
<div>Child</div>
{/* vue中有slot这个标签去表示插槽,React中是props属性中固定的children属性表示 */}
<h1>this.props.children获取的是一个父组件传递过来的全部dom</h1>
<div>{this.props.children}</div>
<h1>类似于vue中的具名插槽显示</h1>
<div>{this.props.children[0]}</div>
<div>{this.props.children[2]}</div>
<div>{this.props.children[2]}</div>
<div>{this.props.children[1]}</div>
</div>
)
}
}
上述代码渲染结果如下所示:
由上图结果可知:
1)this.props.children 获取的是父组件传递过来的整个dom生成的数组,并每个并列的html元素是其的一个元素,上面代码是传递了3个div包裹的元素,所以this.props.children生成了也length为3的数组。
2)在页面中的展示顺序是和Child中this.props.children的数组下标有关和父组件传递过来的顺序没关。
至此插槽的相关知识也总结的七七八八了,我就抛砖引玉了,欢迎各位大佬莅临指导。