Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

this.$set(this.$slotsData, name, slotFunc) or this.$setSlotsData(name, slotFunc) #195

Open
jiankafei opened this issue Jul 30, 2020 · 0 comments

Comments

@jiankafei
Copy link

jiankafei commented Jul 30, 2020

What problem does this feature solve?

It can solve the problem that JSX or H functions are needed to build complex components, which is as flexible as react.

The slot component can respond to external $slots (similar to props, not modifiable), and can also respond to the dynamically set $slots in the component, just like setting data (let's call it $slotsdata, although all $slots actually come from the outside, in essence, it provides a means to dynamically set $slots).

What does the proposed API look like?

<!-- MyComp -->
<template>
  <div>
    <!-- render aaa slot -->
    <slot name="aaa"></slot>
    <div v-for="(row, rowIndex) of daat" :key="rowIndex">
      <div v-for="(col, colIndex) of columns" :key="colIndex">
        <!-- render `label` slot -->
        <!-- In fact, the 'label' slot component renders the slots passed to the MyCompItem component -->
        <slot :name="col.label" :row="row" :rowIndex="rowIndex" :colIndex="colIndex">{{row[col.prop]}}</slot>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: 'MyComp',
  props: {
    daat: Array,
  },
  data() {
    return {
      columns: [],
    };
  },
  created() {
    // Get default slot vnode
    // It is actually the vnode of MyCompItem
    const MyCompItemVNode = this.$slots.default();
    this.columns = MyCompItemVNode.map((vnode) => {
      const componentProps = vnode.componentProps;
      const propsData = componentProps.propsData;
      // --------------- key point ------------------------
      // Slots should be mounted in` vnode.componentProps.$slots',
      // there's no need to hang it in` vnode.componentInstance.$slots',
      // because it's just a function that generates slots.
      // Mounting to componentinstance also has hidden dangers,
      // because you must instantiate slots before you can get the $slots function inside slots.
      // The hidden danger is that if the internal slots need to pass parameters,
      // developers must track the actual parameters passed and pass the default values for the instantiated slots.
      // If you don't have to instantiate the slots function inside the vnode of the slots,
      // then developers only need to instantiate slots where they use the slots function to avoid this hidden danger.
      // slots.xxx  In fact, it is equivalent to an attribute, but classified as slots, not props.
      const $slots = componentProps.$slots;
      // --------------- key point ------------------------
      // Set up new slots for the MyComp component through the following API, similar to setting data
      // The slot component can respond to both the external incoming $slots and the dynamically added $slotsdata
      $slots.default && this.$set(this.$slotsData, propsData.label, $slots.default);
      // or
      // $slots.default && this.$setSlots(propsData.label, $slots.default);
      return propsData;
    });
  },
};
</script>

<!-- MyCompItem -->
<template>
  <div></div>
</template>
<script>
export default {
  name: 'MyCompItem',
  props: {
    label: String,
    prop: String,
  },
};
</script>

<!-- usage -->
<template>
  <div>
    <my-comp :daat="daat">
      <!-- Render to 'aaa' slot of MyComp -->
      <template #aaa>
        <div>AAAAAAAA</div>
      </template>
      <!-- my-comp-item is not actually rendered -->
      <my-comp-item label="名称" prop="name"></my-comp-item>
      <my-comp-item label="描述" prop="desc">
        <!-- It will actually render to the description slot of the MyComp component -->
        <template #default={ row, rowIndex, colIndex }>
          <div>{{row}}{{rowIndex}}{{colIndex}}</div>
        </template>
      </my-comp-item>
    </my-comp>
  </div>
</template>
<script>
import MyComp from './MyComp';
import MyCompItem from './MyCompItem';

export default {
  components: {
    MyComp,
    MyCompItem,
  },
  data() {
    return {
      daat: [
        {
          name: 'vue',
          desc: 'mvvm framework'
        }
        {
          name: 'react',
          desc: 'mvvm framework too'
        }
      ],
    };
  },
};
</script>
@jiankafei jiankafei changed the title 对 $slots 设计的一点建议:可以动态的从组件内部设置 $slots,让 $slots 更加灵活 $slots 设计的一点建议:可以动态的从组件内部设置 $slots,slot 组件可以响应动态添加的 $slots Jul 30, 2020
@jiankafei jiankafei changed the title $slots 设计的一点建议:可以动态的从组件内部设置 $slots,slot 组件可以响应动态添加的 $slots $slots 设计的一点建议:可以从组件内部动态设置 $slots,slot 组件可以响应动态添加的 $slots Jul 30, 2020
@jiankafei jiankafei changed the title $slots 设计的一点建议:可以从组件内部动态设置 $slots,slot 组件可以响应动态添加的 $slots A suggestion on the design of $slots: dynamically set $slots within the component, and the slot component can respond to the dynamically added $slots Aug 11, 2020
@jiankafei jiankafei changed the title A suggestion on the design of $slots: dynamically set $slots within the component, and the slot component can respond to the dynamically added $slots this.$set(this.$slotsData, name, slotFunc) or this.$setSlotsData(name, slotFunc) Aug 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant