Real dry goods, walk heart to share!

How to be a good time manager? LZX tells us that by sleeping fewer hours each night, you’ll have more time to exercise.

For programmers, if they spend less time each day doing business, they will have more time to do shui.

Today we are talking about how Vue can double efficiency by packaging business components more flexibly. Because Ctrl + C + Ctrl + V is not enough for us, and we have to change a lot of things. What can I do? Is there a faster career than CV engineer?

The answer is yes! We call them configuration engineers, simple and brainless!

Vue component encapsulation techniques

The core idea of this approach is encapsulation. But the packaging method is different, the use is also very different. How to achieve a flexible and easy-to-use package is the main goal of this article.

$attrs

What is the simplest encapsulation? The idea is to put another layer on top of the original component while retaining all the functionality of the full component. Then extend your capabilities.

The real case

Let’s say we have a component, X-Button, which unfortunately does not support load state! So what? For the user experience, we need to put a load state on it. So we wrap a Y-button around it:

<template>
  <x-button>
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
Copy the code
export default {
  name: 'YButton'.props: {
    loading: {
      type: Boolean.default: false}}};Copy the code

In this way, our Y-button supports loading! But wait, what if we wanted to pass attributes to the old X-Button? Simple!

<template>
  <x-button :size="size">
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
Copy the code
export default {
  props: {
    loading: {
      type: Boolean.default: false,},size: {
      type: String.default: undefined}}};Copy the code

Yes, it’s that simple, the original component properties, one plus one! So tired!! We can’t do this. It’s not elegant. Fortunately, Vue provides $attrs to solve this problem.

$attrs = $attrs = $attrs

$attrs contains attribute bindings (except class and style) that are not recognized (and retrieved) as prop in the parent scope

Which is basically what I don’t want. You get it. So let’s rewrite this.

<template>
  <x-button v-bind="$attrs">
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
Copy the code
export default {
  props: {
    loading: {
      type: Boolean.default: false}}};Copy the code

In this way, when we pass attributes to y-button, all attributes pass transparently to X-button except loading. That’s what $attrs does.

Configuration + Template

This is the key step in this article, and also the most efficient step. Think about how you feel when you write out the configuration step by step from the prototype and the page is ready.

The real case

The most common component we use on a daily basis: tables + pages! Seriously, spreadsheets are everywhere!

There are a lot of great table components, but they are really complex to write and riddled with repetitive code. It’s time to wrap it up! We use el-Table as the base component.

ElTable Original operation

First, el-table is used like this:

<template>
  <el-table :data="tableData">
    <el-table-column prop="date" label="Date" width="180"> </el-table-column>
    <el-table-column prop="name" label="Name" width="180"> </el-table-column>
    <el-table-column prop="address" label="Address"> </el-table-column>
  </el-table>
</template>
Copy the code
export default {
  data() {
    return {
      tableData: [{date: "2016-05-02".name: "Wang Xiaohu".address: Lane 1518, Jinshajiang Road, Putuo District, Shanghai}}; }};Copy the code

Configuration of columns

Now let’s transform this component to encapsulate an F-table! So the first thing we’re going to do is get rid of all of these El-table-columns.

<template>
  <div>
    <el-table>
      <el-table-column v-for="(col, i) in cols" :key="i" v-bind="col"> </el-table-column>
    </el-table>
  </div>
</template>
Copy the code
export default {
  props: {
    cols: {
      type: Array.default: (a)= >[]}}};Copy the code

This is how we use it:

<template>
  <div>
    <f-table cols=""></f-table>
  </div>
</template>
Copy the code
export default {
  data() {
    return {
      cols: [{prop: "date".label: "Date".width: "180".formatter: dateFormatter } ] }; }};Copy the code

Data acquisition method

We know from the original call that el-table is passed

<el-table :data="tableData">
Copy the code

Data property to pass data. We could just pass through the array, but we’re not going to do that, because we can do a lot more here. Instead of passing in data directly, we pass in methods to get it.

<template>
  <div>
    <el-table :data="tableData">
      <! -... -->
    </el-table>
  </div>
</template>
Copy the code
export default {
  props: {
    // ...
    fetch: {
      type: Function.default: (a)= > Promise.resolve({ rows: [] })
    }
  },
  data() {
    return {
      loading: false.tableData: []}; }, created() {this.fetchData()
  },
  methods: {
    async fetchData() {
      this.loading = true;
      try {
        const { rows } = await this.fetch();
        this.tableData = rows;
      } catch (error) {
        console.error(error);
      } finally {
        this.loading = false; }}} instead! };Copy the code

You can see that we can set the loading state of the table while fetching data and handle errors. We can also integrate paging in here, but we’ll talk about that later. This could save us a lot of work!

Let’s look at the component call code again:

<template>
  <div>
    <f-table :cols="cols" :fetch="fetchUsers"></f-table>
  </div>
</template>
Copy the code
export default {
  data() {
    return {
      cols: [{prop: "date".label: "Date".width: "180"}}; },methods: {
    fetchUsers() {
      return {
        rows: [{ name: "xxx".date: "xx"}}; }}};Copy the code

We just have to worry about how to get the data, what data to show. Didn’t!

paging

OK! Now we’re going to solve the paging problem in passing, and we’re going to use el-Pagination.

ElPagination primitive operation

<template>
  <div>
    <el-pagination :current-page.sync="currentPage" :total="total"> </el-pagination>
  </div>
</template>
Copy the code
export default {
  data() {
    return {
      currentPage: 1.total: 0}; }};Copy the code

Integrated into FTable

<template>
  <div>
    <el-table :data="tableData">
      <! -- -->
    </el-table>
    <el-pagination @current-change="fetchData" :current-page.sync="currentPage" :total="total">
    </el-pagination>
  </div>
</template>
Copy the code
export default {
  // ...
  data() {
    return {
      // ...
      currentPage: 1.total: 0
    };
  },
  methods: {
    async fetchData() {
      // ...
      const { rows, total } = await this.fetch(this.currentPage);
      this.tableData = rows;
      this.total = total; }}};Copy the code

Let’s see what we’ve added:

  • infetchTime to return moretotalIndicates total data to facilitate pagination
  • infetchIs passed the current page number to the function
  • Retrieve the data when the page number changes

Our component call code, on the other hand, only adds a few lines:

<f-table :cols="cols" :fetch="fetchUsers"></f-table>
Copy the code
methods: {
  async fetchUsers(currentPage) {
    const query = {
      page: currentPage
    };
    const { rows, total } = await api.getUsers(query);
    return{ rows, total }; }}Copy the code

This wraps up a table component with automatic pagination and is simple to use.

Of course it’s not all you need I know. Let’s say you want to use the original el-table-column of the table, add a button to the table column, add an input field or something.

A named slot.

When customizing content, slot is most appropriate. But how to add it to our F-table?

Remember that we used COLs to configure el-table-column. We just need to indicate that a col is a slot.

<template>
  <div>
    <el-table :data="tableData">
      <template v-for="(col, i) in cols">
        <slot v-if="col.slot" :name="col.slot" />
        <el-table-column v-else :key="i" v-bind="col"> </el-table-column>
      </template>
    </el-table>
  </div>
</template>
Copy the code

Usage:

<template>
  <div>
    <f-table :cols="cols" :fetch="fetchUsers">
      <template slot="action">
        <el-table-column>Use the native ElTableColumn usage</el-table-column>
      </template>
    </f-table>
  </div>
</template>
Copy the code
export default {
  data() {
    return {
      cols: [{slot: 'operation'
        },
        {
          prop: "date".label: "Date".width: "180"}}; }}Copy the code

summary

Once you get used to this method and the various formatters, writing pages is really mindless, all it takes is drag and drop (if you smell anything)!

Writing is not easy, we implore you to move to show a focus of praise!

Original text – My little station