处理这个高阶组件的最惯用的 Vue 方法是什么?

What's the most idomatic Vue way of handling this higher-order component?

我有一个 VueJS 组织和架构问题。我有一堆页面用作系统中各个对象的 CRUD 页面。他们共享很多代码。我已经在一个共享组件中抽象了它,但我不喜欢我所做的,我正在寻找有关执行此操作的惯用 Vue 方法的建议。

我正在尝试创建一个接受两个参数的高阶组件:

  1. 一个编辑组件,它是每个对象的可编辑视图。因此,您可以将其视为具有 v 模型的文本输入的替代品,接受它有大量不同的输入。

  2. 一个列表组件,显示系统中该类型的所有对象的列表。它控制导航以编辑该对象。

通常这只是我使用插槽并在每个 CRUD 对象的视图页面中调用此组件的地方。所以基本上我会有这样的东西:

<!-- this file is src/views/DogsCRUDPage.vue -->
<template>
  <general-crud-component
    name="dogs"
    backendurl="/dogs/"
  >
    <template slot="list">
      <dogs-list-component />
    </template>
    <template slot="edit">
      <dogs-edit-field v-model="... oops .." />
    </template>
 </general-crud-component>
</template>
<script>
export default {
  name: "DogCRUDPage",
  components: {
    GeneralCrudComponent,
    DogListComponent,
    DogEditField,
  },  
}
</script>

这很好,因为它符合我所有其他 VueJS 页面的一般语法以及我如何将道具和东西传递给共享代码。然而,问题在于 GeneralCRUDComponent 处理所有检查对象是否被编辑的机制,并因此隐藏或取消隐藏保存按钮等。因此它在其数据中具有可编辑对象,它将成为 DogsEditField 的 v-model 或任何其他传递给它的。所以它需要给这个组件传递一个 prop。所以我做了什么:

// This file is src/utils/crud.js

import Vue from "vue"

const crudView = (listComponent, editComponent) => {
  return Vue.component('CrudView', {
    template: `
  <v-row>
    <list-component />
    <v-form>
      <edit-component v-model="obj" />
    </v-form>
  </v-row>
    `,
    components: {
      ListComponent: listComponent,
      EditComponent: editComponent,
    },
    data() {
      return {
        obj: {},
      }
    },
  })
}

export default crudView

此文件有大量未显示的共享代码,这些代码正在执行编辑、撤消、保存等具体操作。

然后在我的 src/router/index.js

//import DogCRUDPage from "@/views/libs/DogCRUDPage"
import crudView from "@/utils/crud"
import DogListComponent from "@/components/DogListComponent"
import DogEditField from "@/components/design/DogEditField"

const DogCRUDPage = crudView(DesignBasisList, DesignBasis)

Vue.use(VueRouter);

export default new VueRouter({
  routes: [
    {
      path: "/dog",
      name: "dog",
      component: DogCRUDPage,
    },
})

这是有效的,但有一些我不喜欢的问题。首先,我需要为我的项目启用 runtimecompiler,这会增加浏览器的负载大小。我需要将列表和编辑组件导入到我的路由器,而不仅仅是我有一个页面的每个对象的页面。这个新共享组件的语法与所有其他页面使用的模板语法完全不同。它将我创建的所有页面放入 router/index.js 文件,而不是像我在 Vue.

中习惯的 src/views 中的文件一样布局

完成此任务的惯用方法是什么?我走在正确的轨道上吗?我很高兴这样做,它正在工作,如果这真的是我们在 Vue 中这样做的方式。但如果 Vue 社区做一些不同的事情,我很乐意探索替代方案。我想我主要是在寻找惯用的 Vue 方法来完成这个。非常感谢。

这个怎么样:

DogsPage.vue

<template>
    <CrudView 
        :editComponent="DogsEdit" 
        :listComponent="DogsList"
    ></CrudView>
</template>

<script>
import DogsEdit from '@/components/DogsEdit.vue'
import DogsList from '@/components/DogsList.vue'
import CrudView from '@/components/CrudView.vue'

export default {
    components: { CrudView },

    data() {
        return { DogsEdit, DogsList }
    }
}
</script>

CrudView.vue

<template>
  <div>
      <component :is="listComponent"></component>
      <component :is="editComponent" v-model="obj"></component>
  </div>
</template>

<script>
export default {
    props: {
        editComponent: Object,
        listComponent: Object
    },

    data() {
        return {
            obj: {}
        }
    }
}
</script>