之前的文章我们说了一下 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 属性值,这样就将指定的内容输出,结果如下:
完美解决我们的问题。