For example, custom controls such as drop-down lists, time pickers, or auto-fill properties are very complex and require a lot of edge complexity to consider. While there are many libraries that do a good job of addressing this complexity, they also come with the undesirable disadvantage of not being able to customize the style of such components.

For example, take off the label input control:

This component has some interesting features:

  • You are not allowed to add duplicate tags
  • Empty labels are not allowed
  • Automatically removes the space around the label content
  • Press Enter to save the label
  • Click the X character to remove the label

If you need to use such a component in your project, introducing this as a library and stripping out the logic can certainly save a lot of time and effort.

But what if you need a different presentation at this point?

The following component has the same behavior as the above component, but the layout is significantly different:

By combining CSS and configuration options, you can try to support all of these layouts in one component, but obviously this is not a good approach, in case one day you need another layout and you have to change that component, breaking the closure of the component and causing other problems.

In view of the above situation, let’s introduce the most important knowledge point of this article.

Scoped Slots

In vue.js, slots is a placeholder element in the component that is replaced by content passed in from the parent component/consumer.

Scoped slots

While regular slots is like passing HTML text to a component, Scoped Slots is like passing a callback function to a component that receives data and returns HTML.

Pass the parameter to the parent component by adding props to the slot element in the child component. The parent component obtains these parameters by destructuring the property data received within the Destructuring slot-scope.

There is a LinksList component that exposes the Scoped Slot attribute for each list element and passes each item’s data back to the parent element via: Link Prop.

:link
slot-scope

The type of the slot property

You can pass any type to slot, but I find it most useful to use one of the following three types of data.

Data

The simplest slot prop types are data types: Strings,numbers, Boolean values, Arrays, Objects, etc.

In our links-list component example, link is an example of a data Prop type, which is an object with some properties.

Actions

An action property is a function provided by a child component that the parent can call to trigger some behavior in the child.

For example, we can pass a bookmark method to the parent component that bookmarks a given link.

Bindings

Bindings are a set of attributes or listener events that can be bound to specific elements by using v-bind or V-ON.

These are useful when you want to encapsulate details about how to interact with a given element.

For example, we provide the bookmarkButtonAttrs and bookmarkButtonEvents bindings to move these details to the component itself, rather than leaving the consumer component to handle the button logic added to the bookmark via the V-show directive and @click.

Renderless Components

Renderless Components I prefer to call functional Components (see react).

A functional component is a component that does not render any HTML text.

Instead, it manages only state and behavior, exposing a scope slot to the parent or consuming component so that they can control the content of the rendering themselves.

A functional component can render exactly what you pass into it, without any other elements.

Separate layer appearance and behavior

Because functional components only deal with state and behavior, they do not make any design and layout decisions.

That means that if you can figure out a way to separate interesting behavior like our tag input functionality from the UI component, you can reuse this functional component to implement the layout of any tag input component.

The following are all label input components, but this time supported by a functional component.

The basic structure of functional components

Functional components simply expose a scoped slot in which consumers can provide the entire module they want to render.

The skeleton of a basic functional component looks like this:

Render function

Any parent component/consumer can use exampleProp in its own template by deconstructing the exampleProp in slot-scope.

An actual use case column

Let’s build a functional version of the label input control from scratch.

We’ll start by creating a blank, non-render component with no slots,

And a static, non-interactive parent component, which is then passed into a slot for the child component,

slot-scope

The tag list

First, we replace the static list with the dynamic list.

The tag input component is a custom form control. As in the original example, the tags should be in the parent component and bound to the component via the V-Model.

We first add a value attribute to the functional component and pass it to a slot called Tags.

v-model
slot-scope
With v - for

Remove the label

Next, when clicking the X button, delete a label.

In the functional component, we will add a removeTag method and pass it as a slot attribute to the parent element.

@click
removeTag

Click Enter to add the label

Adding new tags is a bit more complicated than the previous two examples.

To understand why, let’s take a look at how traditional components are implemented.

v-model

Once the user hits Enter, as long as the label is valid, we add it to the List array and then clear the input input.

The problem here is how we pass the V-model binding via scoped-slot.

Well, if you’ve read up on Vue, you know that the V-Model is really just a syntactic sugar that binds the Value feature to a prop named Value and throws new values via a custom input event when its input event is fired.

  • Component to add onenewTagData attributes
  • Returns a binding to:valuethenewTagBinding property of
  • Returns a binding@keydown.enterUsed to add labels and bindings@inputUsed to update the tag’s event binding properties

Explicitly add a new label

In our current layout, the user adds a new label by typing in the input element and hitting the Enter key. But it’s also easy to imagine that some users would like to be able to add labels by clicking the Add button.

To do this, we simply pass a reference to the slot Scope’s addTag method.

Consumers just need to deconstruct the attributes they actually need, so there’s no cost to them if you provide them with attributes they probably won’t need.

Run the Demo

Here are the functional components we have created so far:

Change the layout

Now that we have a functional component for the tag input control, we can easily write any Html we want and apply the provided slot properties in the right place to easily implement the alternative layout.

Here is the stacked layout we implemented from scratch with our new functional components.

Create your own wrapped components

Seeing so many examples, you might think, “Wow, I need to write so much HTML every time I need another form of tag component,” and yes, you’re right.

Whenever you need a tag input component, you really need to write a lot.

There is an easy solution: create your own wrapped component!

<tags-input>

And even crazier

Once you realize that a component can provide data without rendering anything, there are no limits to what you can do with component modeling.

As an example, here is a fetch-data component that uses a URL as a property to fetch JSON data from the URL and pass the response data to the parent component:

conclusion

Splitting a component into a view component and a functional component is a very useful pattern to make code reuse easier, but it’s not always worth it.

Consider using this pattern if:

  • You want to build a library, and you want users to be able to customize the look of components
  • There are many components in your project that have similar functions but different layouts

If you’re working on a component that looks similar in any case, don’t go down this road. In this case it may be better and simpler to write everything you need in one component.


In addition, the view code and business logic separation is a kind of to reduce the code coupling, which further increases the robustness of a code, its deep is component should conform to the thought of high cohesion and low coupling, other means to conform to this kind of thought and as inversion of control (IOC), issued a subscription model and so on, I think more and write more code should cultivate the awareness, Otherwise, simply writing business code to fulfill requirements and write code will be slow to improve.

The translation of the article is not exactly in accordance with the original text, I added some of my own understanding in order to better understand, if you like my article, please give a thumblike to express encouragement or share with your friends.

A link to the

Demo source code (Vue single file component form)

The original link

IOC inversion of control