第 008 期 用 Composition API 重構 Mixins 代碼

在 Vue 中,Mixins 可以包含任意組件的選項。這使得用 Mixins 能很方便的抽象多個組件間的公共部分,但也會帶來一些問題:

  1. 命名衝突導致的運行結果的不確定性。組件 和 引入的 Mixins,引入的多個 Mixins 之間,都會出現數據名,方法名的命名衝突。出現命名衝突時,同名的數據或方法會被覆蓋,對應的業務也就出錯了。
  2. 隱式依賴導致的高耦合。組件 和 引入的 Mixins 之間會出現互相依賴的情況,如果依賴的數據或方法重命名了,數據或方法就找不到了。

Composition API 可以很好的解決這些問題。組件可以用 Composition API 暴露出的可響應數據。組件和 Composition API 不能讀取和修改各自內部的數據和方法。

解決方案

我們來看個 Demo。做一個管理後臺的列表頁。列表頁支持篩選搜索,顯示列表,列表分頁的功能。

用 Mixins 實現

可以將需要的組件的引入;列表,搜索條件分頁數據;以及數據的交互放到 Mixins。如下:

import SearchForm from '@/components/search-form.vue'
import SearchItem from '@/components/search-item.vue'
import TableGrid from '@/components/search-item.vue'

export default {
  components: {
    SearchForm, // 搜索條件表單組件
    SearchItem, // 搜索條件組件
    TableGrid //表格組件
  },
  data() {
    return {
      list: [/* 列表數據 */], 
      searchQuery: {/* 搜索條件 */}, 
      pager: {/* 分頁 */}
    }
  },
  mounted () {
    this.fetchList();
  },
  watch: {
    searchQuery: {
      handler() {this.fetchList()},
      deep: true
    }
  }, 
  methods: {
    fetchList() {/* 獲取列表 */},
  }
}

列表頁這麼寫:

<template>
  <div>
    <!-- 搜索功能 -->
    <SearchForm @search="fetchList">
      <div>
        <SearchItem title="姓名">
          <input type="text" v-model="searchQuery.name">
        </SearchItem>
      </div>
    </SearchForm>
    <!-- 表格 -->
    <TableGrid :list="list" :pager="pager"/>
  </div>
</template>

<script>
import listMixins from './mixin'
export default {
  mixins: [listMixins],
}
</script>

用 Composition API 重構

我們用 Composition API 來重構上面的 Mixins。如下:

import { onMounted, reactive, watch, toRefs } from 'vue'
import SearchForm from '@/components/search-form.vue'
import SearchItem from '@/components/search-item.vue'
import TableGrid from '@/components/search-item.vue'

export default function useList() {
  const data = reactive({
    searchQuery: {},
    list: [],
    pager: {}
  })

  const fetchList = () => {/* 獲取列表 */}

  onMounted(fetchList)

  watch(() => data.searchQuery, fetchList, { deep: true })

  return {
    ...toRefs(data),
    fetchList,
    components: {
      SearchForm,
      SearchItem,
      TableGrid
    }
  }
}

列表頁這麼寫:

<template>
  <div>
    <!-- 搜索功能 -->
    <SearchForm @search="fetchList">
      <SearchItem title="姓名">
        <input type="text" v-model="searchQuery.name">
      </SearchItem>
    </SearchForm>
    <!-- 表格 -->
    <TableGrid :list="list" :pager="pager"/>
  </div>
</template>

<script setup>
import useList from './use-list'
const {
  components: {
    SearchForm,
    SearchItem,
    TableGrid
  },
  list,
  fetchList,
  searchQuery,
} = useList()
</script>

參考文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章