Vue3 作用域插槽

Vue3 作用域插槽

在封装组件的过程中,可以为预留的 <slot> 插槽绑定 props 数据,这种带有 props 数据的叫做作用域插槽。通过作用域插槽,把组件数据返回给,组件调用方。

MyTest组件

<template>
  <div>
    <h3>这是 TEST 组件</h3>
    <slot :info="infomation" :msg="message"></slot>
  </div>
</template>

<script>
export default {
  name'MyTest',
  data() {
    return {
      // 信息数据
      infomation: {
        phone'138xxxx6666',
        address'中国北京',
      },
      message'abc'
    }
  },
}
</script>

组件调用者

<template>
  <div>
    <h1>App 根组件</h1>
    <hr />

    <!-- 使用自定义组件 -->
    <my-test>
      <!-- 直接解构组件MyTest 返回的数据-->
      <template #default="{ msg, info }">
        <p>{{ msg }}</p>
        <p>{{ info.address }}</p>
      </template>
    </my-test>
    <hr />

    <my-table>
      <template #default="{ user }">
        <td>{{ user.id }}</td>
        <td>{{ user.name }}</td>
        <td>
          <input type="checkbox" :checked="user.state" />
        </td>
      </template>
    </my-table>
  </div>
</template>

<script>
// 导入组件
import MyTest from './MyTest.vue'

export default {
  name'MyApp',
  // 注册组件
  components: {
    MyTest,
  },
}
</script>

MyTable组件

通过<slot :user="item"></slot>作用域插槽返回用户数据给组件调用者,进行自定义渲染。

<template>
  <table class="table table-bordered table-striped table-dark table-hover">
    <!-- 表头区域 -->
    <thead>
      <tr>
        <th>Id</th>
        <th>Name</th>
        <th>State</th>
      </tr>
    </thead>
    <!-- 表格主体区域 -->
    <tbody>
      <!-- 循环渲染表格数据 -->
      <tr v-for="item in list" :key="item.id">
        <slot :user="item"></slot>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  name'MyTable',
  data() {
    return {
      // 列表的数据
      list: [
        { id1name'张三'statetrue },
        { id2name'李四'statefalse },
        { id3name'赵六'statefalse },
      ],
    }
  },
}
</script>

组件调用者

<template>
  <div>
    <h1>App 根组件</h1>
    <hr />
    <!-- 使用自定义组件 -->
    <my-table>
      <template #default="{ user }">
        <td>{{ user.id }}</td>
        <td>{{ user.name }}</td>
        <td>
          <input type="checkbox" :checked="user.state" />
        </td>
      </template>
    </my-table>
  </div>
</template>

<script>
// 导入组件
import MyTable from './MyTable.vue'

export default {
  name'MyApp',
  // 注册组件
  components: {
    MyTable,
  },
}
</script>

封装 MyTable

  1. 用户通过名为 data 的prop属性,为 MyTable.vue 组件指定数据源
  2. 在 MyTable.vue 组件中,预留名称为 header 的具名插槽
  3. 在 MyTable.vue 组件中,预留名称为 body 的作用域插槽

MyTable.vue组件

<template>
  <table class="table table-bordered table-striped">
    <!-- 标题区域 -->
    <thead>
      <tr>
        <slot name="header"></slot>
      </tr>
    </thead>
    <!-- 内容主体区域 -->
    <tbody>
      <tr v-for="(item, index) in data" :key="item.id">
         <!-- 作用域插槽返回 row index -->
        <slot name="body" :row="item" :index="index"></slot>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  name'MyTable',
  props: {
    data: {
      typeArray,
      requiredtrue,
      default: []
    }
  }
}
</script>

<style lang="less" scoped></style>

根组件

<template>
  <div>
    <h1>App 根组件</h1>
    <hr />

    <my-table :data="goodslist">
      <template v-slot:header>
        <th>序号</th>
        <th>商品名称</th>
        <th>价格</th>
        <th>标签</th>
        <th>操作</th>
      </template>
  
    <!-- 接收作用域插槽返回的 row index ,自定义渲染-->
      <template v-slot:body="{ row, index }">
        <td>{{ index + 1 }}</td>
        <td>{{ row.goods_name }}</td>
        <td>¥{{ row.goods_price }}</td>
        <td>
          <input
            type="text"
            class="form-control form-control-sm form-ipt"
            v-if="row.inputVisible"
            v-focus
            v-model.trim="row.inputValue"
            @blur="onInputConfirm(row)"
            @keyup.enter="onInputConfirm(row)"
            @keyup.esc="row.inputValue = ''"
          />

          <button type="button" class="btn btn-primary btn-sm" v-else @click="row.inputVisible = true">+Tag</button>
          <!-- 循环渲染标签信息 -->
          <span class="badge badge-warning ml-2" v-for="item in row.tags" :key="item">{{ item }}</span>
        </td>
        <td>
          <button type="button" class="btn btn-danger btn-sm" @click="onRemove(row.id)">删除</button>
        </td>
      </template>
    </my-table>
  </div>
</template>

<script>
import MyTable from './components/my-table/MyTable.vue'

export default {
  name'MyApp',
  data() {
    return {
      // 商品列表的数据
      goodslist: [],
    }
  },
  created() {
    // 发起请求
    this.getGoodsList()
  },
  methods: {
    // 请求商品列表的数据
    async getGoodsList() {
      const { data: res } = await this.$http.get('/api/goods')
      if (res.status !== 0return console.log('获取商品列表数据失败!')
      this.goodslist = res.data
    },
    // 根据 Id 删除商品
    onRemove(id) {
      this.goodslist = this.goodslist.filter(x => x.id !== id)
    },
    onInputConfirm(row) {
      const val = row.inputValue
      row.inputValue = ''
      row.inputVisible = false

      if (!val || row.tags.indexOf(val) !== -1return
      row.tags.push(val)
    },
  },
  directives: {
    focus(el) {
      el.focus()
    },
  },
  components: {
    MyTable,
  },
}
</script>

<style lang="less" scoped>
.form-ipt {
  width80px;
  display: inline;
}
</style>

————————————————

版权声明:本文为CSDN博主「DevCsdner」的原创文章

原文链接:https://blog.csdn.net/smartboy_01/article/details/126943969


原文始发于微信公众号(前端24):Vue3 作用域插槽

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/253945.html

(0)
Java朝阳的头像Java朝阳

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!