如何避免创建数百个 files.vue
How do I avoid creating hundreds of files.vue
我正在建立一个包含很多项目的网站。
所以路径是这样的:
example.com/catalog/indoor/fireplace/awesome-one
目前我正在创建成百上千的 Vue
个实例:
AwesomeOne.vue
AnotherOne.vue
YetAnotherThing.vue
...
AhundredthThing.vue
它们内部只有一个过滤数组,并将一个 prop 传递给使用 Vuex
存储中的数据的可重用组件。
所以我在想,有没有办法避免创建这么多 Vue
文件?我有点用 Nuxt.js
对问题进行了排序,但它只会自动生成使开发稍微容易一些的路由。但是我仍然需要创建很多内部代码几乎相同的文件(实际上只有 3 个字的区别:计算的名称 属性、过滤器选项和道具的名称)。
我正在考虑一些计算 属性,它会使用来自 Vuex.state
的数据动态分配一个 URL。但是我不能把东西放在一起。
根据要求发布代码:
Catalog.vue
<template>
<v-main>
<v-row>
<v-col
v-for="category in categories"
:key="category.i"
>
<v-card
router
:to="category.link"
>
<v-img
height="250"
width="250"
:src="category.img"
/>
<v-card-title>
{{ category.name }}
</v-card-title>
</v-card>
</v-col>
</v-row>
</v-main>
</template>
<script>
export default {
computed: {
categories () {
return this.$store.state.categories
}
}
}
</script>
CatalogCategories.vue(有 5 个)
<template>
<v-sheet>
<h1>Изделия для дома</h1>
<v-row>
<v-col
v-for="indoorItem in indoorItems"
:key="indoorItem.i"
>
<a :href="indoorItem.link">{{ indoorItem.name }}</a>
</v-col>
</v-row>
</v-sheet>
</template>
<script>
export default {
computed: {
subCategories () {
return this.$store.state.subCategories
},
indoorItems () {
return this.subCategories.filter((category) => category.type === "indoor" || category.type === "bothdoor");
},
}
}
</script>
Banquet.vue(类别之一,超过20个)
<template>
<v-sheet>
<h1>Банкетки</h1>
<item-view :items="this.banquet" />
</v-sheet>
</template>
<script>
import ItemView from "../../../components/ItemView.vue"
export default {
components: { ItemView },
computed: {
items () {
return this.$store.state.items
},
banquet () {
return this.items.filter((item) => item.type === "banquet");
},
}
}
</script>
ItemView.Vue(可重用组件)
<template>
<v-sheet>
<v-row>
<v-col
v-for="item in items"
:key="item.i"
>
<v-card
route
:to="item.path"
>
<v-img
width="250"
height="250"
:src="item.img"
/>
<v-card-title> {{ item.name }} </v-card-title>
<v-card-subtitle> Цена: {{ item.price }} грамм конфет му-му </v-card-subtitle>
</v-card>
</v-col>
</v-row>
</v-sheet>
</template>
<script>
export default {
props: {
items: {
type: Array,
required: true,
},
},
}
</script>
IndividualItem.vue(我必须创建超过 100 个)
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.obossana" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from '../../../../components/IndividualItemView.vue'
export default {
components: { IndividualItemView },
computed: {
items () {
return this.$store.state.items
},
obossana () {
return this.items.filter((item) => item.title === "obossana");
},
}
}
</script>
<style>
</style>
IndividualItemView.vue(可重用组件)
<template>
<v-sheet>
<v-card
v-for="item in items"
:key="item.i"
>
<v-card-title> {{ item.name }} </v-card-title>
<expandable-image
class="image"
close-on-background-click
:src="item.img"
/>
<v-card-subtitle> Цена: {{ item.price }} раз послать тебя ко всем чертям </v-card-subtitle>
<v-card-text> {{ item.description }} </v-card-text>
</v-card>
</v-sheet>
</template>
<script>
export default {
mounted() {
const viewportMeta = document.createElement('meta');
viewportMeta.name = 'viewport';
viewportMeta.content = 'width=device-width, initial-scale=1';
document.head.appendChild(viewportMeta);
},
props: {
items: {
type: Array,
required: true,
},
},
}
</script>
<style scoped>
.image {
width: 400px;
max-width: 100%;
}
</style>
还有来自 Vuex 商店的小片段:
{
name: "Обоссаная банкетка",
title: "obossana",
type: "banquet",
path: "/catalog/indoor/banquet/obossana",
price: "215361",
img:
"https://b2.3ddd.ru/media/cache/tuk_model_custom_filter_ru/model_images/0000/0000/0079/79546.53239b3804d0a.jpeg",
description: "blah blah blah",
},
你已经很接近了,有几种不同的方法可以解决这个问题。我将展示最简单的 IMO 方法,即继续使用 props 并将您拥有的硬编码数据推送到组件层次结构的更上一层楼。
我将使用 IndividualItem.vue
作为示例,因为它是迄今为止最明显的应用方法:
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.items" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from "../../../../components/IndividualItemView.vue";
export default {
components: { IndividualItemView },
// Add a prop for the title
props: {
title: {
type: String,
required: true,
},
},
// Filter only store items with that title
computed: {
items() {
return this.$store.state.items.filter(
(item) => item.title === this.title
);
},
},
};
</script>
要使用它,您只需执行以下操作:
<IndividualItem title="obossana" />
以这种方式使用道具实际上允许您创建和使用可重用的组件。还有各种不同的策略,你可以申请传递道具。
例如,您可以传递 items
,而不是传递 title
,这将使 IndividualItem
组件的用户更好地控制他们想要的项目显示。
这里也有一个快速演示:
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.items" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from "../../../../components/IndividualItemView.vue";
export default {
components: { IndividualItemView },
// Any items may be passed in, allowing the user to group
// different items together however they need.
props: {
items: {
type: Array,
default: () => [],
},
},
};
</script>
然后,组件的用户可能会这样做(注意:您可以创建 obossanaItems
完全相同的方式,只是在父组件范围内):
<IndividualItem :items="obossanaItems" />
作为最后一条结束建议,这可能是您遗漏的一条,几乎所有硬编码数据(如 title: obossana
)都应该直接来自您的页面组件,或者您的 API,这最终允许您创建可重用的组件。
例如,负责呈现页面的页面组件 example.com/catalog/indoor/fireplace/awesome-one
应该负责为其所有子组件提供呈现正确数据所需的信息。
这不是唯一的方法,但绝对是最容易上手的方法,也是我推荐的方法,而不是为每个类别、子类别等创建特定的组件。
正如我在本文开头提到的post,你已经很接近了,你只需要继续将具体的数据项抽象到父组件。 Vue 和 Nuxt 的其他功能,如 Vuex getters,也可以帮助使特定的过滤调用也可重用,但这将进入另一个主题。
好的,我明白了。
_view.vue
单个项目视图:
<script>
export default {
async asyncData() {
const items = await fetch(
'API URL here'
).then((res) => res.json())
return { items }
},
data() {
return {
params: this.$route.params.view,
title: '',
}
},
computed: {
filteredItems() {
return this.items.filter((item) => item.title === this.$route.params.view)
},
},
}
</script>
事实证明这很容易。我所要做的就是获取硬编码数据(我决定使用 API 因为将来我将不得不添加更多项目,我相信如果我使用 API 会更容易)并过滤 item.title
匹配路由 $route.params.view
在 template
标签(_view.vue
文件)内我有:
<template>
<v-main>
<h1>API: items</h1>
<h2>'/catalog/_subcategory/_individualitem/_view.vue' here</h2>
<h3>params.view: {{ params }}</h3>
<v-card v-for="item in filteredItems" :key="item.i">
<v-avatar size="200">
<img :src="item.img" alt="картинка предмета" />
</v-avatar>
<v-card-title>
{{ item.name }} and item.title: {{ item.title }}
</v-card-title>
<v-card-subtitle>Цена: {{ item.price }} сантиметров</v-card-subtitle>
<v-card-text> {{ item.description }} </v-card-text>
</v-card>
</v-main>
</template>
h1
、h2
、h3
标签帮助我找出(通过显示)变量的值。
文件树是(根是目录本身):
├── index.vue
├── _subcategory
│ ├── _individualitem
│ │ └── _view.vue
│ └── _items.vue
└── _type.vue
还有一点点 api.json
:
{
"title": "stremnaya-arka",
"path": "/catalog/outdoor/arcs/stremnaya-arka",
"name": "Стрёмная арка",
"type": "arcs",
}
文件名可能有点混乱,但我希望不会。
我希望它能帮助其他和我一样挣扎的新手 ;)
我正在建立一个包含很多项目的网站。 所以路径是这样的:
example.com/catalog/indoor/fireplace/awesome-one
目前我正在创建成百上千的 Vue
个实例:
AwesomeOne.vue
AnotherOne.vue
YetAnotherThing.vue
...
AhundredthThing.vue
它们内部只有一个过滤数组,并将一个 prop 传递给使用 Vuex
存储中的数据的可重用组件。
所以我在想,有没有办法避免创建这么多 Vue
文件?我有点用 Nuxt.js
对问题进行了排序,但它只会自动生成使开发稍微容易一些的路由。但是我仍然需要创建很多内部代码几乎相同的文件(实际上只有 3 个字的区别:计算的名称 属性、过滤器选项和道具的名称)。
我正在考虑一些计算 属性,它会使用来自 Vuex.state
的数据动态分配一个 URL。但是我不能把东西放在一起。
根据要求发布代码: Catalog.vue
<template>
<v-main>
<v-row>
<v-col
v-for="category in categories"
:key="category.i"
>
<v-card
router
:to="category.link"
>
<v-img
height="250"
width="250"
:src="category.img"
/>
<v-card-title>
{{ category.name }}
</v-card-title>
</v-card>
</v-col>
</v-row>
</v-main>
</template>
<script>
export default {
computed: {
categories () {
return this.$store.state.categories
}
}
}
</script>
CatalogCategories.vue(有 5 个)
<template>
<v-sheet>
<h1>Изделия для дома</h1>
<v-row>
<v-col
v-for="indoorItem in indoorItems"
:key="indoorItem.i"
>
<a :href="indoorItem.link">{{ indoorItem.name }}</a>
</v-col>
</v-row>
</v-sheet>
</template>
<script>
export default {
computed: {
subCategories () {
return this.$store.state.subCategories
},
indoorItems () {
return this.subCategories.filter((category) => category.type === "indoor" || category.type === "bothdoor");
},
}
}
</script>
Banquet.vue(类别之一,超过20个)
<template>
<v-sheet>
<h1>Банкетки</h1>
<item-view :items="this.banquet" />
</v-sheet>
</template>
<script>
import ItemView from "../../../components/ItemView.vue"
export default {
components: { ItemView },
computed: {
items () {
return this.$store.state.items
},
banquet () {
return this.items.filter((item) => item.type === "banquet");
},
}
}
</script>
ItemView.Vue(可重用组件)
<template>
<v-sheet>
<v-row>
<v-col
v-for="item in items"
:key="item.i"
>
<v-card
route
:to="item.path"
>
<v-img
width="250"
height="250"
:src="item.img"
/>
<v-card-title> {{ item.name }} </v-card-title>
<v-card-subtitle> Цена: {{ item.price }} грамм конфет му-му </v-card-subtitle>
</v-card>
</v-col>
</v-row>
</v-sheet>
</template>
<script>
export default {
props: {
items: {
type: Array,
required: true,
},
},
}
</script>
IndividualItem.vue(我必须创建超过 100 个)
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.obossana" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from '../../../../components/IndividualItemView.vue'
export default {
components: { IndividualItemView },
computed: {
items () {
return this.$store.state.items
},
obossana () {
return this.items.filter((item) => item.title === "obossana");
},
}
}
</script>
<style>
</style>
IndividualItemView.vue(可重用组件)
<template>
<v-sheet>
<v-card
v-for="item in items"
:key="item.i"
>
<v-card-title> {{ item.name }} </v-card-title>
<expandable-image
class="image"
close-on-background-click
:src="item.img"
/>
<v-card-subtitle> Цена: {{ item.price }} раз послать тебя ко всем чертям </v-card-subtitle>
<v-card-text> {{ item.description }} </v-card-text>
</v-card>
</v-sheet>
</template>
<script>
export default {
mounted() {
const viewportMeta = document.createElement('meta');
viewportMeta.name = 'viewport';
viewportMeta.content = 'width=device-width, initial-scale=1';
document.head.appendChild(viewportMeta);
},
props: {
items: {
type: Array,
required: true,
},
},
}
</script>
<style scoped>
.image {
width: 400px;
max-width: 100%;
}
</style>
还有来自 Vuex 商店的小片段:
{
name: "Обоссаная банкетка",
title: "obossana",
type: "banquet",
path: "/catalog/indoor/banquet/obossana",
price: "215361",
img:
"https://b2.3ddd.ru/media/cache/tuk_model_custom_filter_ru/model_images/0000/0000/0079/79546.53239b3804d0a.jpeg",
description: "blah blah blah",
},
你已经很接近了,有几种不同的方法可以解决这个问题。我将展示最简单的 IMO 方法,即继续使用 props 并将您拥有的硬编码数据推送到组件层次结构的更上一层楼。
我将使用 IndividualItem.vue
作为示例,因为它是迄今为止最明显的应用方法:
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.items" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from "../../../../components/IndividualItemView.vue";
export default {
components: { IndividualItemView },
// Add a prop for the title
props: {
title: {
type: String,
required: true,
},
},
// Filter only store items with that title
computed: {
items() {
return this.$store.state.items.filter(
(item) => item.title === this.title
);
},
},
};
</script>
要使用它,您只需执行以下操作:
<IndividualItem title="obossana" />
以这种方式使用道具实际上允许您创建和使用可重用的组件。还有各种不同的策略,你可以申请传递道具。
例如,您可以传递 items
,而不是传递 title
,这将使 IndividualItem
组件的用户更好地控制他们想要的项目显示。
这里也有一个快速演示:
<template>
<v-sheet>
<v-card>
<individual-item-view :items="this.items" />
<v-card />
</v-card>
</v-sheet>
</template>
<script>
import IndividualItemView from "../../../../components/IndividualItemView.vue";
export default {
components: { IndividualItemView },
// Any items may be passed in, allowing the user to group
// different items together however they need.
props: {
items: {
type: Array,
default: () => [],
},
},
};
</script>
然后,组件的用户可能会这样做(注意:您可以创建 obossanaItems
完全相同的方式,只是在父组件范围内):
<IndividualItem :items="obossanaItems" />
作为最后一条结束建议,这可能是您遗漏的一条,几乎所有硬编码数据(如 title: obossana
)都应该直接来自您的页面组件,或者您的 API,这最终允许您创建可重用的组件。
例如,负责呈现页面的页面组件 example.com/catalog/indoor/fireplace/awesome-one
应该负责为其所有子组件提供呈现正确数据所需的信息。
这不是唯一的方法,但绝对是最容易上手的方法,也是我推荐的方法,而不是为每个类别、子类别等创建特定的组件。
正如我在本文开头提到的post,你已经很接近了,你只需要继续将具体的数据项抽象到父组件。 Vue 和 Nuxt 的其他功能,如 Vuex getters,也可以帮助使特定的过滤调用也可重用,但这将进入另一个主题。
好的,我明白了。
_view.vue
单个项目视图:
<script>
export default {
async asyncData() {
const items = await fetch(
'API URL here'
).then((res) => res.json())
return { items }
},
data() {
return {
params: this.$route.params.view,
title: '',
}
},
computed: {
filteredItems() {
return this.items.filter((item) => item.title === this.$route.params.view)
},
},
}
</script>
事实证明这很容易。我所要做的就是获取硬编码数据(我决定使用 API 因为将来我将不得不添加更多项目,我相信如果我使用 API 会更容易)并过滤 item.title
匹配路由 $route.params.view
在 template
标签(_view.vue
文件)内我有:
<template>
<v-main>
<h1>API: items</h1>
<h2>'/catalog/_subcategory/_individualitem/_view.vue' here</h2>
<h3>params.view: {{ params }}</h3>
<v-card v-for="item in filteredItems" :key="item.i">
<v-avatar size="200">
<img :src="item.img" alt="картинка предмета" />
</v-avatar>
<v-card-title>
{{ item.name }} and item.title: {{ item.title }}
</v-card-title>
<v-card-subtitle>Цена: {{ item.price }} сантиметров</v-card-subtitle>
<v-card-text> {{ item.description }} </v-card-text>
</v-card>
</v-main>
</template>
h1
、h2
、h3
标签帮助我找出(通过显示)变量的值。
文件树是(根是目录本身):
├── index.vue
├── _subcategory
│ ├── _individualitem
│ │ └── _view.vue
│ └── _items.vue
└── _type.vue
还有一点点 api.json
:
{
"title": "stremnaya-arka",
"path": "/catalog/outdoor/arcs/stremnaya-arka",
"name": "Стрёмная арка",
"type": "arcs",
}
文件名可能有点混乱,但我希望不会。
我希望它能帮助其他和我一样挣扎的新手 ;)