当前位置:   article > 正文

Vue 插槽

Vue 插槽

Vue插槽是一种特殊的语法,用于在组件中定义可复用的模板部分。它允许开发者在组件的标记中声明一个或多个插槽,然后在使用该组件时,可以根据自己的需求将内容插入到这些插槽中。

Vue插槽分为默认插槽和具名插槽两种。

默认插槽

语法

  1. 组件内需要自定义的结构部分,改用<slot></slot>占位
  2. 使用组件时,<MyDialog></MyDialog>标签内部,传入结构替换slot

案例

要在页面中显示一个对话框,封装成一个组件,组件内容能够自定义

MyDialog.vue

  1. <template>
  2. <div class="dialog">
  3. <div class="dialog-header">
  4. <h3>友情提示</h3>
  5. <span class="close">✖️</span>
  6. </div>
  7. <div class="dialog-content">
  8. <!-- 1. 在需要定制的位置,使用slot占位 -->
  9. <slot></slot>
  10. </div>
  11. <div class="dialog-footer">
  12. <button>取消</button>
  13. <button>确认</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. data () {
  20. return {
  21. }
  22. }
  23. }
  24. </script>
  25. <style scoped>
  26. * {
  27. margin: 0;
  28. padding: 0;
  29. }
  30. .dialog {
  31. width: 470px;
  32. height: 230px;
  33. padding: 0 25px;
  34. background-color: #ffffff;
  35. margin: 40px auto;
  36. border-radius: 5px;
  37. }
  38. .dialog-header {
  39. height: 70px;
  40. line-height: 70px;
  41. font-size: 20px;
  42. border-bottom: 1px solid #ccc;
  43. position: relative;
  44. }
  45. .dialog-header .close {
  46. position: absolute;
  47. right: 0px;
  48. top: 0px;
  49. cursor: pointer;
  50. }
  51. .dialog-content {
  52. height: 80px;
  53. font-size: 18px;
  54. padding: 15px 0;
  55. }
  56. .dialog-footer {
  57. display: flex;
  58. justify-content: flex-end;
  59. }
  60. .dialog-footer button {
  61. width: 65px;
  62. height: 35px;
  63. background-color: #ffffff;
  64. border: 1px solid #e1e3e9;
  65. cursor: pointer;
  66. outline: none;
  67. margin-left: 10px;
  68. border-radius: 3px;
  69. }
  70. .dialog-footer button:last-child {
  71. background-color: #007acc;
  72. color: #fff;
  73. }
  74. </style>

App.vue

  1. <template>
  2. <div>
  3. <!-- 2. 在使用组件时,组件标签内填入内容 -->
  4. <MyDialog>
  5. <div>你确认要删除么</div>
  6. </MyDialog>
  7. <MyDialog>
  8. <p>你确认要退出么</p>
  9. </MyDialog>
  10. </div>
  11. </template>
  12. <script>
  13. import MyDialog from './components/MyDialog.vue'
  14. export default {
  15. data () {
  16. return {
  17. }
  18. },
  19. components: {
  20. MyDialog
  21. }
  22. }
  23. </script>
  24. <style>
  25. body {
  26. background-color: #b3b3b3;
  27. }
  28. </style>

main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. Vue.config.productionTip = false
  4. new Vue({
  5. render: h => h(App),
  6. }).$mount('#app')

后备内容 (默认值)

设置插槽默认显示内容

语法

在<slot>标签内,放置内容,作为默认显示内容

外部使用组件时,不传内容,则会显示后备内容,否则后备内容被替换

案例

MyDialog.vue

  1. <template>
  2. <div class="dialog">
  3. <div class="dialog-header">
  4. <h3>友情提示</h3>
  5. <span class="close">✖️</span>
  6. </div>
  7. <div class="dialog-content">
  8. <!-- 往slot标签内部,编写内容,可以作为后备内容(默认值) -->
  9. <slot>
  10. 我是默认的文本内容
  11. </slot>
  12. </div>
  13. <div class="dialog-footer">
  14. <button>取消</button>
  15. <button>确认</button>
  16. </div>
  17. </div>
  18. </template>
  19. <script>
  20. export default {
  21. data () {
  22. return {
  23. }
  24. }
  25. }
  26. </script>
  27. <style scoped>
  28. * {
  29. margin: 0;
  30. padding: 0;
  31. }
  32. .dialog {
  33. width: 470px;
  34. height: 230px;
  35. padding: 0 25px;
  36. background-color: #ffffff;
  37. margin: 40px auto;
  38. border-radius: 5px;
  39. }
  40. .dialog-header {
  41. height: 70px;
  42. line-height: 70px;
  43. font-size: 20px;
  44. border-bottom: 1px solid #ccc;
  45. position: relative;
  46. }
  47. .dialog-header .close {
  48. position: absolute;
  49. right: 0px;
  50. top: 0px;
  51. cursor: pointer;
  52. }
  53. .dialog-content {
  54. height: 80px;
  55. font-size: 18px;
  56. padding: 15px 0;
  57. }
  58. .dialog-footer {
  59. display: flex;
  60. justify-content: flex-end;
  61. }
  62. .dialog-footer button {
  63. width: 65px;
  64. height: 35px;
  65. background-color: #ffffff;
  66. border: 1px solid #e1e3e9;
  67. cursor: pointer;
  68. outline: none;
  69. margin-left: 10px;
  70. border-radius: 3px;
  71. }
  72. .dialog-footer button:last-child {
  73. background-color: #007acc;
  74. color: #fff;
  75. }
  76. </style>

App.vue

  1. <template>
  2. <div>
  3. <MyDialog></MyDialog>
  4. <MyDialog>
  5. 你确认要退出么
  6. </MyDialog>
  7. </div>
  8. </template>
  9. <script>
  10. import MyDialog from './components/MyDialog.vue'
  11. export default {
  12. data () {
  13. return {
  14. }
  15. },
  16. components: {
  17. MyDialog
  18. }
  19. }
  20. </script>
  21. <style>
  22. body {
  23. background-color: #b3b3b3;
  24. }
  25. </style>

main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. Vue.config.productionTip = false
  4. new Vue({
  5. render: h => h(App),
  6. }).$mount('#app')

具名插槽

默认插槽只有一个定制位置

具名插槽支持多个定制位置

语法

  1. 多个<slot>标签使用name属性区分名字
  2. template配合v-slot:名字来分发对应标签
  3. v-slot:可以简化成#

案例

MyDialog.vue

  1. <template>
  2. <div class="dialog">
  3. <div class="dialog-header">
  4. <!-- 一旦插槽起了名字,就是具名插槽,只支持定向分发 -->
  5. <slot name="head"></slot>
  6. </div>
  7. <div class="dialog-content">
  8. <slot name="content"></slot>
  9. </div>
  10. <div class="dialog-footer">
  11. <slot name="footer"></slot>
  12. </div>
  13. </div>
  14. </template>
  15. <script>
  16. export default {
  17. data () {
  18. return {
  19. }
  20. }
  21. }
  22. </script>
  23. <style scoped>
  24. * {
  25. margin: 0;
  26. padding: 0;
  27. }
  28. .dialog {
  29. width: 470px;
  30. height: 230px;
  31. padding: 0 25px;
  32. background-color: #ffffff;
  33. margin: 40px auto;
  34. border-radius: 5px;
  35. }
  36. .dialog-header {
  37. height: 70px;
  38. line-height: 70px;
  39. font-size: 20px;
  40. border-bottom: 1px solid #ccc;
  41. position: relative;
  42. }
  43. .dialog-header .close {
  44. position: absolute;
  45. right: 0px;
  46. top: 0px;
  47. cursor: pointer;
  48. }
  49. .dialog-content {
  50. height: 80px;
  51. font-size: 18px;
  52. padding: 15px 0;
  53. }
  54. .dialog-footer {
  55. display: flex;
  56. justify-content: flex-end;
  57. }
  58. .dialog-footer button {
  59. width: 65px;
  60. height: 35px;
  61. background-color: #ffffff;
  62. border: 1px solid #e1e3e9;
  63. cursor: pointer;
  64. outline: none;
  65. margin-left: 10px;
  66. border-radius: 3px;
  67. }
  68. .dialog-footer button:last-child {
  69. background-color: #007acc;
  70. color: #fff;
  71. }
  72. </style>

App.vue

  1. <template>
  2. <div>
  3. <MyDialog>
  4. <!-- 需要通过template标签包裹需要分发的结构,包成一个整体 -->
  5. <template v-slot:head>
  6. <div>我是大标题</div>
  7. </template>
  8. <template v-slot:content>
  9. <div>我是内容</div>
  10. </template>
  11. <template #footer>
  12. <button>取消</button>
  13. <button>确认</button>
  14. </template>
  15. </MyDialog>
  16. </div>
  17. </template>
  18. <script>
  19. import MyDialog from './components/MyDialog.vue'
  20. export default {
  21. data () {
  22. return {
  23. }
  24. },
  25. components: {
  26. MyDialog
  27. }
  28. }
  29. </script>
  30. <style>
  31. body {
  32. background-color: #b3b3b3;
  33. }
  34. </style>

main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. Vue.config.productionTip = false
  4. new Vue({
  5. render: h => h(App),
  6. }).$mount('#app')

作用域插槽

给插槽绑定数据

案例

封装表格组件

  1. 父传子,动态渲染表格内容
  2. 利用默认插槽,定制操作列

MyTable.vue

  1. <template>
  2. <table class="my-table">
  3. <thead>
  4. <tr>
  5. <th>序号</th>
  6. <th>姓名</th>
  7. <th>年纪</th>
  8. <th>操作</th>
  9. </tr>
  10. </thead>
  11. <tbody>
  12. <tr v-for="(item, index) in data" :key="item.id">
  13. <td>{{ index + 1 }}</td>
  14. <td>{{ item.name }}</td>
  15. <td>{{ item.age }}</td>
  16. <td>
  17. <!-- 1. 给slot标签,添加属性的方式传值 -->
  18. <slot :row="item" msg="测试文本"></slot>
  19. <!-- 2. 将所有的属性,添加到一个对象中 -->
  20. <!--
  21. {
  22. row: { id: 2, name: '孙大明', age: 19 },
  23. msg: '测试文本'
  24. }
  25. -->
  26. </td>
  27. </tr>
  28. </tbody>
  29. </table>
  30. </template>
  31. <script>
  32. export default {
  33. props: {
  34. data: Array
  35. }
  36. }
  37. </script>
  38. <style scoped>
  39. .my-table {
  40. width: 450px;
  41. text-align: center;
  42. border: 1px solid #ccc;
  43. font-size: 24px;
  44. margin: 30px auto;
  45. }
  46. .my-table thead {
  47. background-color: #1f74ff;
  48. color: #fff;
  49. }
  50. .my-table thead th {
  51. font-weight: normal;
  52. }
  53. .my-table thead tr {
  54. line-height: 40px;
  55. }
  56. .my-table th,
  57. .my-table td {
  58. border-bottom: 1px solid #ccc;
  59. border-right: 1px solid #ccc;
  60. }
  61. .my-table td:last-child {
  62. border-right: none;
  63. }
  64. .my-table tr:last-child td {
  65. border-bottom: none;
  66. }
  67. .my-table button {
  68. width: 65px;
  69. height: 35px;
  70. font-size: 18px;
  71. border: 1px solid #ccc;
  72. outline: none;
  73. border-radius: 3px;
  74. cursor: pointer;
  75. background-color: #ffffff;
  76. margin-left: 5px;
  77. }
  78. </style>

 App.vue

  1. <template>
  2. <div>
  3. <MyTable :data="list">
  4. <!-- 3. 通过template #插槽名="变量名" 接收 -->
  5. <template #default="obj">
  6. <button @click="del(obj.row.id)">
  7. 删除
  8. </button>
  9. </template>
  10. </MyTable>
  11. <MyTable :data="list2">
  12. <template #default="{ row }">
  13. <button @click="show(row)">查看</button>
  14. </template>
  15. </MyTable>
  16. </div>
  17. </template>
  18. <script>
  19. import MyTable from './components/MyTable.vue'
  20. export default {
  21. data () {
  22. return {
  23. list: [
  24. { id: 1, name: '张小花', age: 18 },
  25. { id: 2, name: '孙大明', age: 19 },
  26. { id: 3, name: '刘德忠', age: 17 },
  27. ],
  28. list2: [
  29. { id: 1, name: '赵小云', age: 18 },
  30. { id: 2, name: '刘蓓蓓', age: 19 },
  31. { id: 3, name: '姜肖泰', age: 17 },
  32. ]
  33. }
  34. },
  35. methods: {
  36. del (id) {
  37. this.list = this.list.filter(item => item.id !== id)
  38. },
  39. show (row) {
  40. // console.log(row);
  41. alert(`姓名:${row.name}; 年纪:${row.age}`)
  42. }
  43. },
  44. components: {
  45. MyTable
  46. }
  47. }
  48. </script>

 main.js

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. Vue.config.productionTip = false
  4. new Vue({
  5. render: h => h(App),
  6. }).$mount('#app')
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/548502
推荐阅读
相关标签
  

闽ICP备14008679号