doclist 阅读(257) 评论(0)

之前的文章我们说了一下 vue 中组件的原生事件绑定,本章我们来所以下 vue 中的插槽使用。

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child title="<p>你好 世界</p>"></child>
11 </div>
12 <script>
13     Vue.component("child", {
14         props: ['title'],
15         template: `
16             <div>
17                 {{title}}
18                 <p>hello world</p>
19             </div>
20        `
21     });
22     var app = new Vue({
23         el: '#app',
24     })
25 </script>
26 </body>
27 </html>

上面的代码中,我们通过 title="" 形式通过父组件向子组件 child 传递了一个 "<p>你好世界</p>" 的带标签的内容,然后我们在子组件中输出,结果如下:

显示结果是按字符串展示的,但我们想要的是不带标签的输出结果,在之前的文章中我们说过可以通过 v-html 来进行转义,代码如下:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child title="<p>你好 世界</p>"></child>
11 </div>
12 <script>
13     Vue.component("child", {
14         props: ['title'],
15         template: `
16             <div>
17                 <div v-html="title"></div>
18                 <p>hello world</p>
19             </div>
20        `
21     });
22     var app = new Vue({
23         el: '#app',
24     })
25 </script>
26 </body>
27 </html>

我们把 template 中的 {{title}} 改成了 v-html 的形式输出,结果如下:

输出结果没问题,但是当我们看控制台的 HTML 代码时发现外层多加了一个 <div> 标签,这显然不友好,,这时可能有人会想到模板标签 <template v-html="title"> 这样写,但是这样的话在页面上是不会输出内容的。而且如果 <child> 标签内的 title 属性里面的内容并不只是一个 <p> 标签,还有很多其他的内容,例如 "<p>你好 世界<p><p>你好 世界<p><p>你好 世界<p><p>你好 世界<p><p>你好 世界<p><p>你好 世界<p>" 这么长的内容,在代码里也不好看。

如何解决上面的问题,Vue 官方为我们提供插槽 slot,我们可以将代码改成如下:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child>
11         <p>你好 世界</p>
12     </child>
13 </div>
14 <script>
15     Vue.component("child", {
16         template: `
17             <div>
18                 <slot></slot>
19                 <p>hello world</p>
20             </div>
21        `
22     });
23     var app = new Vue({
24         el: '#app',
25     })
26 </script>
27 </body>
28 </html>

我们将 p 标签想要输出的内容直接放在了 <child> 标签内,然后在 template 中添加标签 <slot>,意思就是将 <child> 内的内容通过 slot 插槽插入子组件,结果如下:

完美解决了我们的问题,而且 <slot> 标签内还可以自定义我们想要输出的内容,如果 <child> 标签内没有内容的话以自定义的内容输出,如下:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child></child>
11 </div>
12 <script>
13     Vue.component("child", {
14         template: `
15             <div>
16                 <slot>插槽自定义内容</slot>
17                 <p>hello world</p>
18             </div>
19        `
20     });
21     var app = new Vue({
22         el: '#app',
23     })
24 </script>
25 </body>
26 </html>

我们在 <child> 标签内没有内容,在 slot 标签内插入了一些内容,在页面显示如下:

上面的 "插槽自定义内容" 在 <child> 内没有内容时输出,如果有内容则输出 <child> 标签内的内容。

上面的插槽形式我们可以称之为无名插槽,还有一种插槽叫具名插槽,看以下代码:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child>
11         <header>我是 header</header>
12         <footer>我是 footer</footer>
13     </child>
14 </div>
15 <script>
16     Vue.component("child", {
17         template: `
18             <div>
19                 <slot></slot>
20                 <p>hello world</p>
21                 <slot></slot>
22             </div>
23        `
24     });
25     var app = new Vue({
26         el: '#app',
27     })
28 </script>
29 </body>
30 </html>

我们想要一种效果,就是自定义插槽的内容位置,假设上的代码中 <header> 标签内的内容为头部信息,<footer> 标签内的内容为底部信息,我们想让它们分别输出在 template 模板中 p 标签的上下,结果如下:

输出内容显然不是我们想要的结果,我们每用一次 <slot> 标签就会在页面输出一次,那该如何解决这个问题呢,我们可以使用具名插槽来为我们的插槽定义名称,如下:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>vue</title>
 6     <script src="https://cdn.jsdelivr.net/npm/vue"></script>
 7 </head>
 8 <body>
 9 <div id="app">
10     <child>
11         <header slot="header">我是 header</header>
12         <footer slot="footer">我是 footer</footer>
13     </child>
14 </div>
15 <script>
16     Vue.component("child", {
17         template: `
18             <div>
19                 <slot name="header"></slot>
20                 <p>hello world</p>
21                 <slot name="footer"></slot>
22             </div>
23        `
24     });
25     var app = new Vue({
26         el: '#app',
27     })
28 </script>
29 </body>
30 </html>

在上面的代码中,我们分别为 <header> <footer> 标签添加 slot 属性,然后在 template 中的 <slot> 标签内以 name 属性来分别对应标签 <header> <footer> 内的 slot 属性值,这样就将指定的内容输出,结果如下:

完美解决我们的问题。