如何在10分鐘以內完成一個業務頁面 - Vue的封裝藝術

真實幹貨,走心分享!html

如何作一個優秀的時間管理者? lzx告訴咱們,天天少睡幾個小時,你就有更多的時間去作運動。程序員

對於程序員來講,天天少點時間寫業務,就有更多時間去作(hua)優(hua)化(shui)。api

咱們今天講的是Vue中如何更靈活的封裝業務組件,使效率翻倍。由於Ctrl + cCtrl + v都不足以知足咱們了,搬過來還要改一大堆東西。那怎麼辦嘛,還有比CV工程師更快的職業嗎?數組

答案是有的!咱們稱其爲配置工程師,簡單無腦!async

Vue組件封裝技巧

其實這個方法的核心思想就是封裝。可是封裝方式不一樣,使用起來也是天差地別。如何實現一個靈活易用的封裝,這就是咱們本篇文章的主要討論目標。函數

$attrs

最簡單的封裝是什麼?就是往原組件外再套一層,而且保留全組件的全部功能。而後擴展本身的功能。post

真實案例

假設咱們有一個組件x-button,很遺憾這個組件竟然不支持加載狀態!那咋辦,爲了用戶體驗,咱們得給它加上加載狀態才行。因此咱們在它的基礎上封裝一個y-buttonfetch

<template>
  <x-button>
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
複製代碼
export default {
  name: 'YButton',
  props: {
    loading: {
      type: Boolean,
      default: false,
    }
  }
};
複製代碼

這樣一來,咱們的y-button就支持loading了!可是等等,若是咱們要給原來的x-button傳遞屬性咋辦?簡單!ui

<template>
  <x-button :size="size">
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
複製代碼
export default {
  props: {
    loading: {
      type: Boolean,
      default: false,
    },
    size: {
      type: String,
      default: undefined,
    }
  }
};
複製代碼

對就是這麼簡單,原組件的屬性,有一個加一個! 好累啊!!!咱們不能這麼作,這太不優雅了。好在Vue提供了$attrs能夠解決這個問題。this

那麼$attrs是幹哈的啊?

$attrs 包含了父做用域中不做爲 prop 被識別 (且獲取) 的 attribute 綁定 (class 和 style 除外)

簡單點來講也就是我不要的,全丟給你。那咱們來改寫一下。

<template>
  <x-button v-bind="$attrs">
    <i v-if="loading" class="font-loading"></i>
    <slot></slot>
  </x-button>
</template>
複製代碼
export default {
  props: {
    loading: {
      type: Boolean,
      default: false,
    }
  }
};
複製代碼

這樣寫,當咱們傳遞屬性給y-button時,除了loading之外,其餘所有屬性都會透傳給x-button。這就是$attrs的做用。

配置+模板

這是本篇關鍵的一步,也是效率提高最多的一步。 想想,當你對着原型圖一步一步寫出頁面配置,頁面就搭好了是什麼感受。

真實案例

平常咱們用的最多,也是最多見的組件:表格+分頁!講真的,表格真的是無處不在!

優秀的表格組件有不少,但它們寫起來的確很複雜,並且充斥着大量重複代碼。是時候將它封裝一下了!咱們以el-table爲基礎組件。

ElTable原始操做

首先,el-table是這樣用的:

<template>
  <el-table :data="tableData">
    <el-table-column prop="date" label="日期" width="180"> </el-table-column>
    <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
    <el-table-column prop="address" label="地址"> </el-table-column>
  </el-table>
</template>
複製代碼
export default {
  data() {
    return {
      tableData: [
        {
          date: "2016-05-02",
          name: "王小虎",
          address: "上海市普陀區金沙江路 1518 弄"
        }
      ]
    };
  }
};
複製代碼

列的配置化

如今咱們開始改造這個組件,封裝一個f-table!首先咱們要將這些el-table-column都幹掉。

<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>
複製代碼
export default {
  props: {
    cols: {
      type: Array,
      default: () => []
    }
  }
};
複製代碼

這樣咱們在使用的時候就是這樣的:

<template>
  <div>
    <f-table cols=""></f-table>
  </div>
</template>
複製代碼
export default {
  data() {
    return {
      cols: [
        {
          prop: "date",
          label: "日期",
          width: "180",
	  formatter: dateFormatter
        }
      ]
    };
  }
};
複製代碼

數據獲取方式

咱們經過最原始的調用知道el-table是經過

<el-table :data="tableData">
複製代碼

data屬性來傳遞數據的。咱們只要直接透傳數據數組就行了,可是咱們不這樣作,由於這裏咱們能夠作更多。咱們不直接傳入數據,而是傳入獲取數據的方法

<template>
  <div>
    <el-table :data="tableData">
      <!-- ... -->
    </el-table>
  </div>
</template>
複製代碼
export default {
  props: {
    // ...
    fetch: {
      type: Function,
      default: () => 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;
      }
    }
  }!
};
複製代碼

你能夠看到咱們在獲取數據的時候能夠設置表格的加載狀態,處理錯誤。這裏咱們還能夠將分頁集成進去,不過這個後面再講。這能夠省去咱們不少工做!

咱們再來看看組件調用代碼:

<template>
  <div>
    <f-table :cols="cols" :fetch="fetchUsers"></f-table>
  </div>
</template>
複製代碼
export default {
  data() {
    return {
      cols: [
        {
          prop: "date",
          label: "日期",
          width: "180"
        }
      ]
    };
  },
  methods: {
    fetchUsers() {
      return {
        rows: [{ name: "xxx", date: "xx" }]
      };
    }
  }
};
複製代碼

咱們只須要關心怎麼獲取數據,要展現什麼數據。沒了!

分頁

OK!下面咱們順帶解決分頁問題,咱們使用的是el-pagination

ElPagination原始操做

<template>
  <div>
    <el-pagination :current-page.sync="currentPage" :total="total"> </el-pagination>
  </div>
</template>
複製代碼
export default {
  data() {
    return {
      currentPage: 1,
      total: 0
    };
  }
};
複製代碼

整合到FTable

<template>
  <div>
    <el-table :data="tableData">
      <!-- -->
    </el-table>
    <el-pagination @current-change="fetchData" :current-page.sync="currentPage" :total="total">
    </el-pagination>
  </div>
</template>
複製代碼
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;
    }
  }
};
複製代碼

咱們看一下咱們加了哪些東西:

  • fetch的時候多返回了total代表總數據,以便於分頁
  • fetch的時候向函數中傳入了當前頁碼
  • 在頁碼改變的時候從新獲取數據

而咱們的組件調用代碼,僅僅只增長了幾行:

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

這樣,一個帶有自動分頁的表格組件就封裝好了,使用起來十分簡單。

固然這並不能知足你的全部需求我知道。好比你想要使用表格最原始的el-table-column,給表格列加個按鈕,加個輸入框什麼的。

具名slot

要定製內容的時候,使用slot是最合適的。可是如何加在咱們的f-table裏面呢?

還記得咱們使用cols來配置el-table-column。咱們只須要代表某個col是某個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>
複製代碼

使用方法:

<template>
  <div>
    <f-table :cols="cols" :fetch="fetchUsers">
      <template slot="action">
        <el-table-column>使用原生ElTableColumn的用法</el-table-column>
      </template>
    </f-table>
  </div>
</template>
複製代碼
export default {
  data() {
    return {
      cols: [
        {
          slot: 'operation'
        },
        {
          prop: "date",
          label: "日期",
          width: "180"
        }
      ]
    };
  }
}
複製代碼

小結

一旦習慣這種方法,再配上各類formatter,寫頁面真的無腦,就差改爲拖拽了(有沒有嗅到什麼)!

寫做不易,懇求你們動動手指點個關注點個贊!

原文 - 個人小破站

相關文章
相關標籤/搜索