之前的文章我們說了一下 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 屬性值,這樣就將指定的內容輸出,結果如下:
完美解決我們的問題。