在 Vue 中,Mixins 可以包含任意组件的选项。这使得用 Mixins 能很方便的抽象多个组件间的公共部分,但也会带来一些问题:
- 命名冲突导致的运行结果的不确定性。组件 和 引入的 Mixins,引入的多个 Mixins 之间,都会出现数据名,方法名的命名冲突。出现命名冲突时,同名的数据或方法会被覆盖,对应的业务也就出错了。
- 隐式依赖导致的高耦合。组件 和 引入的 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>
