经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
解决父子组件通信的三种Vue插槽
来源:jb51  时间:2021/11/23 17:58:45  对本文有异议

前言

插槽可以说是 Vue 中非常重要的一部分吧,在我学习和练习的过程中,当组件搭配着插槽一起使用的时候,会发挥的更好一些。更多时候也会更加方便。

今天介绍Vue中三种插槽吧:默认插槽、具名插槽、作用域插槽。

环境准备

先搭个初始环境给大家看看哈。一步一步讲完这个插槽。

就是写了一个类别组件,分别渲染这三种数据。

image-20211120150949138

Category组件

  1. <template>
  2. <div class="category">
  3. <h1>{{title}}</h1>
  4. <ul>
  5. <li
  6. v-for="(item,index) in listData"
  7. :key="index">{{item}}</li>
  8. </ul>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. props: {
  14. listData:Array,
  15. title: String
  16. }
  17. }
  18. </script>
  19. <style scoped>
  20. .category{
  21. width: 200px;
  22. height: 300px;
  23. background-color:pink;
  24. }
  25. </style>

App组件

  1. <template>
  2. <div id="app">
  3. <Category :listData="games" :title="'Games'" />
  4. <Category :listData="movies" :title="'Movies'" />
  5. <Category :listData="foods" :title="'Foods'" />
  6. </div>
  7. </template>
  8. <script>
  9. import Category from './components/Category.vue'
  10. export default {
  11. name: 'App',
  12. components: {
  13. Category
  14. },
  15. data () {
  16. return {
  17. games:['穿越火线','qq飞车','洛克王国'],
  18. movies:['你好,李焕英','青春派','匆匆那年'],
  19. foods:['邵阳米粉','长沙茶颜','重庆火锅']
  20. }
  21. }
  22. }
  23. </script>
  24. <style>
  25. #app {
  26. font-family: Avenir, Helvetica, Arial, sans-serif;
  27. -webkit-font-smoothing: antialiased;
  28. -moz-osx-font-smoothing: grayscale;
  29. text-align: center;
  30. color: #2c3e50;
  31. margin-top: 60px;
  32. display: flex;
  33. justify-content: space-between;
  34. }
  35. </style>

最开始就是如上图一样的需求,但是现在业务需求更改了,电影变成了只宣传其中一个,其他的不进行宣传,吃的也变成只宣传一个拉。

如下图:

image-20211120151432264

我们怎么改合适呢?

是在Category组件中加if一个个进行判断吗?还是有更好的方法勒???

一个个判断是不行的,那样子代码会变得十分繁杂,不易阅读,万一以后又要更改业务需求,代码都不好动。

接下来就到默认插槽的出现拉。

一、默认插槽

我们在子组件中不用再用props 接收数据,也不做渲染,而是定义一个插槽。

  1. <template>
  2. <div class="category">
  3. <!-- 定义插槽,插槽默认内容 -->
  4. <slot>如果当父组件不传值过来,即显示此默认</slot>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. props: {
  10. }
  11. }
  12. </script>

App组件也作出更改

  1. <template>
  2. <div id="app">
  3. <Category>
  4. <h1>Games</h1>
  5. <!-- <ul>
  6. <li v-for="(item, index) in games" :key="index">{{ item }}</li>
  7. </ul> -->
  8. <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e">
  9. </Category>
  10. <Category>
  11. <h1>Movies</h1>
  12. <img class="movies" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13236694597%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931502&t=f89c2197bda9bb129d9404d3c4b30f2f">
  13. <!-- <ul> -->
  14. <!-- <li v-for="(item, index) in movies" :key="index">{{ item }}</li> -->
  15. <!-- </ul> -->
  16. </Category>
  17. <Category>
  18. <h1>Foods</h1>
  19. <ul>
  20. <li v-for="(item, index) in foods" :key="index">{{ item }}</li>
  21. </ul>
  22. </Category>
  23. <!-- 当我们什么都没有写的时候,看展示什么 -->
  24. <Category>
  25. </Category>
  26. </div>
  27. </template>
  28. <script>
  29. import Category from './components/Category.vue'
  30. export default {
  31. name: 'App',
  32. components: {
  33. Category
  34. },
  35. data () {
  36. return {
  37. games:['穿越火线','qq飞车','洛克王国'],
  38. movies:['你好,李焕英','青春派','匆匆那年'],
  39. foods:['邵阳米粉','长沙茶颜','重庆火锅']
  40. }
  41. }
  42. }
  43. </script>

显示效果:

image-20211120152024922

解释:

我们在子组件写了一个<slot>如果当父组件不传值过来,即显示此默认</slot> 标签,此处就相当于占了一个位置。

我们在父组件中,也不再像之前一样<Category/>写自闭和标签,而是写了非自闭和标签<Category> 内容 </Category>。这样做,Vue就会默认的将写在组件标签中的内容渲染完,然后再放回子组件中的 <slot></slot> 占好位置的地方去。

注意:CSS样式写在父组件或者子组件中都是可以的,因为它是渲染完后才放回子组件中的。写在子组件中,就是在放回子组件中时渲染。

写完这里,客户突然觉得你们这么厉害,不满足啦,又开始给你们整幺蛾子。

image-20211120152906020

接下来就又到具名插槽登场啦哈。

二、具名插槽

竟然我们能够想到用一个插槽啦,那么为什么不能想着用两个插槽来试一试勒?

改造子组件

  1. <template>
  2. <div class="category">
  3. <!-- 必须加上名称 在父组件中才能指定要放入那个插槽 这也是为什么叫做具名插槽的原因--->
  4. <slot name="slot1">如果当父组件不传值过来,即显示此默认</slot>
  5. <slot name="slot2"></slot>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. props: {
  11. }
  12. }
  13. </script>

父组件

  1. <template>
  2. <div id="app">
  3. <Category>
  4. <template slot="slot1">
  5. <h1>Games</h1>
  6. <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle%2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e"
  7. />
  8. </template>
  9. <template slot="slot2">
  10. <button > qq登录</button>
  11. <button > 微信登录</button>
  12. </template>
  13. </Category>
  14. <Category>
  15. <template slot="slot1">
  16. <h1>Movies</h1>
  17. <img
  18. class="movies"
  19. src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13236694597%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931502&t=f89c2197bda9bb129d9404d3c4b30f2f"
  20. />
  21. </template>
  22. <template slot="slot2">
  23. <button > 点击购票</button>
  24. </template>
  25. </Category>
  26. <Category>
  27. <template slot="slot1">
  28. <h1>Foods</h1>
  29. <ul>
  30. <li v-for="(item, index) in foods" :key="index">{{ item }}</li>
  31. </ul>
  32. </template>
  33. </Category>
  34. <!-- 当我们什么都没有写的时候,看展示什么 -->
  35. <Category> </Category>
  36. </div>
  37. </template>
  38. <script>
  39. import Category from './components/Category.vue'
  40. export default {
  41. name: 'App',
  42. components: {
  43. Category
  44. },
  45. data () {
  46. return {
  47. games:['穿越火线','qq飞车','洛克王国'],
  48. movies:['你好,李焕英','青春派','匆匆那年'],
  49. foods:['邵阳米粉','长沙茶颜','重庆火锅']
  50. }
  51. }
  52. }
  53. </script>

效果展示

image-20211120153500451

解释:

我们可以在组件中放多个slot,但是多个的时候必须要给他们命名,另外父组件中也要进行指定,这样才不会放不进去。

三、作用域插槽

作用域插槽和前面稍稍有点不同,之前都是数据在父组件中,而作用域插槽是数据在子组件中,反过来传递给父组件,让父组件定义结构进行渲染。

改造的子组件

  1. <template>
  2. <div class="category">
  3. <slot name="slot1">如果当父组件不传值过来,即显示此默认</slot>
  4. <slot name="slot2" :foods="foods">如果当父组件不传值过来,即显示此默认</slot>
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. data () {
  10. return{
  11. foods:['邵阳米粉','长沙茶颜','重庆火锅']
  12. }
  13. }
  14. }
  15. </script>

父组件

  1. <template>
  2. <div id="app">
  3. <Category>
  4. <template slot="slot1">
  5. <h1>Foods</h1>
  6. </template>
  7. <template slot="slot2" scope="listData">
  8. <!--如果不知道的 咱们可以输出看看这是什么· {{listData}} -->
  9. <ul>
  10. <li v-for="(item, index) in listData.foods" :key="index">
  11. {{ item }}
  12. </li>
  13. </ul>
  14. </template>
  15. </Category>
  16. <Category>
  17. <template slot="slot1">
  18. <h1>Foods</h1>
  19. </template>
  20. <template slot="slot2" scope="listData">
  21. <ol>
  22. <li v-for="(item, index) in listData.foods" :key="index">
  23. {{ item }}
  24. </li>
  25. </ol>
  26. </template>
  27. </Category>
  28. <Category>
  29. <template slot="slot1">
  30. <h1>Foods</h1>
  31. </template>
  32. <template slot="slot2" scope="listData">
  33. <h4 v-for="(item, index) in listData.foods" :key="index">
  34. {{ item }}
  35. </h4>
  36. </template>
  37. </Category>
  38. <Category>
  39. <template slot="slot1" scope="listData">
  40. {{listData}}
  41. </template>
  42. </Category>
  43. </div>
  44. </template>
  45. <script>
  46. import Category from './components/Category.vue'
  47. export default {
  48. name: 'App',
  49. components: {
  50. Category
  51. }
  52. }
  53. </script>

效果图

image-20211120154438477

这种我在学习及练习过程中,并没有想到哪些使用场景,但是在官网上有案例,我想它必定是有存在的理由,只是我的见识太少,而未能利用到而已。

解释:

子组件中通过:变量名="定义的数据" 向父组件传值,父组件用 <template slot="slot2" scope="不用和子组件传递过来的名称相同"> 接收,因为还要. 一层,才到

  1. <template slot="slot2" scope="listData">
  2. <!--如果不知道的 咱们可以输出看看这是什么· {{listData}} -->
  3. <ul>
  4. <li v-for="(item, index) in listData.foods" :key="index">
  5. {{ item }}
  6. </li>
  7. </ul>
  8. </template>

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注w3xue的更多内容!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号