Vue3 作用域插槽

Vue3 作用域插槽

在封装组件的过程中,可以为预留的 插槽绑定 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>
      
      <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组件

通过作用域插槽返回用户数据给组件调用者,进行自定义渲染。

<template>
  <table class="table table-bordered table-striped table-dark table-hover">
    
    <thead>
      <tr>
        <th>Idth>
        <th>Nameth>
        <th>Stateth>
      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: [
        { id: 1, name: '张三', state: true },
        { id: 2, name: '李四', state: false },
        { id: 3, name: '赵六', state: false },
      ],
    }
  },
}
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. 用户通过名为 dataprop属性,为 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">
         
        <slot name="body" :row="item" :index="index">slot>
      tr>
    tbody>
  table>
template>

<script>
export default {
  name: 'MyTable',
  props: {
    data: {
      type: Array,
      required: true,
      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>
 	
 	  
      <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">+Tagbutton>
          
          <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 !== 0) return 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) !== -1) return
      row.tags.push(val)
    },
  },
  directives: {
    focus(el) {
      el.focus()
    },
  },
  components: {
    MyTable,
  },
}
script>

<style lang="less" scoped>
.form-ipt {
  width: 80px;
  display: inline;
}
style>

你可能感兴趣的