vue.js插槽_Vue.js中的无渲染行为插槽

vue.js插槽

Let’s go over the renderless slot pattern in Vue and see the problems that it can help solve.

让我们看一下Vue中的非渲染插槽模式,看看它可以帮助解决的问题。

Introduced with Vue.js 2.3.0, scoped slots have considerably improved component reusability. For example, the renderless component pattern emerged and solved the problem of providing reusable behavior and pluggable presentation.

在Vue.js 2.3.0中引入的作用域插槽显着提高了组件的可重用性。 例如,无渲染组件模式应运而生,解决了提供可重用行为和可插入表示的问题。

Here we’ll see how to solve the opposite problem: providing reusable presentation and pluggable behavior.

在这里,我们将看到如何解决相反的问题:提供可重用的演示文稿和可插入的行为。

无渲染组件 (Renderless Components)

This pattern applies for components that implement complex behavior and have customizable presentation.

此模式适用于实现复杂行为并具有可自定义表示的组件。

To do so:

为此:

  1. The component implements all the behavior

    该组件实现所有行为
  2. Scoped slots are responsible for the rendering

    作用域的插槽负责渲染
  3. Fallback content ensures that the component can be used out-of-the-box.

    备用内容可确保组件可以直接使用。

Let’s take an example: a component performing an Ajax request and having a slot to display the result. The component handles the Ajax request and the loading state while the default slot provides the presentation.

让我们举个例子:一个执行Ajax请求并具有显示结果的插槽的组件。 组件处理Ajax请求和加载状态,而默认插槽提供演示。

Here a simplified implementation:

这里是一个简化的实现:

<template>
  <div>
    <slot v-if="loading" name="loading">
        <div>Loading ...</div>
    </slot>
    <slot v-else v-bind={data}>
    </slot>
  </div>
</template>

<script>
export default {
  props: ["url"],
  data: () => ({
    loading: true,
    data: null
  }),
  async created() {
    this.data = await fetch(this.url);
    this.loading = false;
  }
};
</script>

Usage:

用法:

<lazy-loading url="https://server/api/data">
  <template #default="{ data }">
    <div>{{ data }}</div>
  </template>
</lazy-loading>

For the original post about this pattern, check here.

有关此模式的原始帖子, 请点击此处

一个不同的问题 (A different problem)

What if the problem is the contrary: imagine the main feature of a component is its presentation. On the other hand, behaviors should be customizable.

如果问题相反,该怎么办:想象一个组件的主要特征是它的表示形式。 另一方面,行为应可自定义。

Imagine you are creating a tree component based on SVG, like this one:

想象一下,您正在基于SVG创建一个树组件,如下所示:

You want to provide the SVG display and behavior such as retracting node and text highlighting on click.

您想要提供SVG显示和行为,例如缩回节点和单击时突出显示文本。

A problem arises when you decide to not hard-code these behaviors and let the user of the component free to override them.

当您决定不对这些行为进行硬编码并让组件的用户自由覆盖它们时,就会出现问题。

A simple solution to expose these behaviors would be to add methods and events to the component.

暴露这些行为的简单解决方案是向组件添加方法和事件。

You’ll end up with something like:

您将得到类似以下内容的结果:

<script>
export default {
  mounted() {
    // pseudo code
    nodes.on('click',(node) => this.$emit('click', node));
  },
  methods: {
    expandNode(node) {
      //...
    },
    retractNode(node) {
      //...
    },
    highlightText(node) {
      //...
    },
  }
};
</script>

To add behavior to the component, the consumer of the component will need to use a ref in a parent component, something like:

要向组件添加行为,组件的使用者将需要在父组件中使用ref,例如:

<template>
  <tree ref="tree" @click="onClick"></tree>
</template>

<script>
export default {
  methods: {
    onClick(node) {
      this.$refs.tree.retractNode(node);
    }
  }
};
</script>

This approach has several drawbacks:

这种方法有几个缺点:

  1. It’s not possible to provide a default behavior anymore

    无法再提供默认行为
  2. Behaviors end up as a cookbook that you need to duplicate

    行为最终成为您需要复制的食谱
  3. Behaviors are not reusable

    行为不可重用

Let’s see how renderless slots can solve these issues.

让我们看看无渲染插槽如何解决这些问题。

无渲染插槽 (Renderless Slots)

A behavior consists basically of proving a reaction to an event. So let’s create a slot that receives access to events and component methods:

行为基本上包括证明对事件的React。 因此,让我们创建一个插槽来接收对事件和组件方法的访问:

<template>
  <div>
    <slot name="behavior" :on="on" :actions="actions">
    </slot>
  </div>
</template>

<script>
export default {
  methods: {
    expandNode(node) { },
    retractNode(node) { },
   //...
  },
  computed:{
    actions() {
      const {expandNode, retractNode} = this;
      return {expandNode, retractNode};
    },
    on() {
      return this.$on.bind(this);
    }
  }
};
</script>

The on attribute is the $on method of the parent component, so it’s possible to listen to all events.

on属性是父组件的$on方法,因此可以侦听所有事件。

Implementing a behavior can be done as a renderless component. Let’s write the expand-on-click component:

可以将行为实现为无渲染组件。 让我们编写单击扩展组件:

export default {
  props: ['on','action']

  render: () => null,

  created() {
    this.on("click", (node) => {
      this.actions.expandNode(node);
    });
  }
};

Usage:

用法:

<tree>
  <template #behavior="{ on, actions }">
    <expand-on-click v-bind="{ on, actions }"/>
  </template>
</tree>

The main advantages of this solution are:

该解决方案的主要优点是:

  • The possibility to provide a default behavior by providing a fallback content:

    通过提供后备内容提供默认行为的可能性:

For example, by declaring the graph component as:

例如,通过将图形组件声明为:

<template>
  <div>
    <slot name="behavior" :on="on" :actions="actions">
      <expand-on-click v-bind="{ on, actions }"/>
    </slot>
  </div>
</template>
  • The possibility to create a reusable component that implements standard behavior that the component’s user can cherry pick

    创建实现标准行为的可重用组件的可能性,组件用户可以选择

Let’s consider a highlight-on-hover component:

让我们考虑一个悬停突出显示组件:

export default {
  props: ['on','action']

  render: () => null,

  created() {
    this.on("hover", (node) => {
      this.actions.highlight(node);
    });
  }
};

Overriding standard behavior:

覆盖标准行为:

<tree>
  <template #behavior="{ on, actions }">
    <highlight-on-hover v-bind="{ on, actions }"/>
  </template>
</tree>
  • Behavior slot are composable

    行为插槽是可组合的

Let’s add two pre-defined behaviors:

让我们添加两个预定义的行为:

<tree>
  <template #behavior="{ on, actions }">
    <expand-on-click v-bind="{ on, actions }"/>
    <highlight-on-hover v-bind="{ on, actions }"/>
  </template>
</tree>
  • Readability of the solution

    解决方案的可读性

Component as behavior are self-explanatory.

作为行为的组成部分是不言自明的。

  • Extensibility

    可扩展性

The on attribute gives access to all the component events. New events are by default available for the slot.

on属性提供对所有组件事件的访问。 默认情况下,该插槽可使用新事件。

结语 (Wrapping Up)

Renderless slots present an interesting alternative to expose method and events in a component. They provide more readable and reusable code.

无渲染插槽提供了一种有趣的替代方案,可以在组件中公开方法和事件。 它们提供了更具可读性和可重用性的代码。

The code of the tree component implementing this pattern is available on github: Vue.D3.tree

实现此模式的树组件的代码可在github上找到: Vue.D3.tree

翻译自: https://www.digitalocean.com/community/tutorials/vuejs-renderless-behavior-slots

vue.js插槽

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值