You can begin to build the product listing page and implement the categories menu as depicted in this diagram by following these next steps:
- Create the folder /src/components/market.
- Implement the CategoryMenyItem component:
- Create the file /src/components/market/CategoryMenuItem.vue
- Write the following code:
<template>
<div class="container" @click="onSelected" :class="{selected: checked}">
<span>{{ categoryName }}</span>
</div>
</template>
<script>
export default {
name: 'CategoryMenuItem',
props: {
categoryName: String,
checked: Boolean,
},
methods: {
onSelected: function() {
this.$emit('selected', this.categoryName);
},
},
}
</script>
<style scoped>
.container {
display: inline;
padding: 5px 3px 5px 3px;
border: 1px solid black;
padding: 2px 5px 2px 5px;
cursor: pointer;
}
.container:hover {
background-color: lightgray;
}
.selected {
background-color: bisque;
}
</style>
This code is an example of a specialized binding in Vue, the class binding :class="{…}".
This is a useful feature because toggling elements' class names according to state is often needed. In this case, the div element is set with a selected class name when the component's prop checked is true; otherwise, selected is removed.
- Implement the CategoryMenu component:
- Create the file /src/components/market/CategoryMenu.vue
- Write the following code:
<template>
<ul>
<li v-for="c in categories" :key="c.name">
<CategoryMenuItem
:categoryName="c.name"
:checked="c.name === selectedCategoryName"
@selected="onCategorySelected"
>
</CategoryMenuItem >
</li>
</ul>
</template>
<script>
import CategoryMenuItem from './CategoryMenuItem.vue';
export default {
name: 'CategoryMenu',
components: {
CategoryMenuItem,
},
props: {
categories: Array,
},
data: () => ({
selectedCategoryName: String,
}),
methods: {
onCategorySelected: function(categoryName) {
const cat = this.categories.find(c => c.name === categoryName);
this.selectedCategoryName = cat.name;
this.$emit('category-changed', cat);
},
},
}
</script>
<style scoped>
ul, li {
list-style: none;
padding: 0;
margin: 0;
display: inline;
}
</style>
Here, the component renders the child menu items using the v-for directive.
This is related to list rendering and is described later, after the category menu feature implementation steps.
- Implement a service for retrieving categories and products:
- Create file /src/services/marketService.js
- Write the following code:
const baseUrl = 'http://localhost:55564/api/';
function loadCategories() {
return fetch(`${baseUrl}products/categories`)
.then(r => r.json());
}
function loadProducts(categoryName) {
return fetch(`${baseUrl}products/searchcategory/${categoryName}`)
.then(r => r.json());
}
export default {
loadCategories,
loadProducts,
};
You can read more about plugins and provide/inject here:
Additionally, there's a popular library that serves as an http client in Vue-based apps that you can consider using as well: https://github.com/pagekit/vue-resource.
- Implement the ProductsPage component:
- Create the file /src/components/market/ProductsPage.vue
- Write the following code:
<template>
<div>
<CategoryMenu
:categories="categories"
@category-changed="onCategoryChanged"
/>
</div>
</template>
<script>
import MarketService from '../../services/marketService';
import CategoryMenu from './CategoryMenu.vue';
export default {
name: 'ProductsPage',
components: {
CategoryMenu,
},
data: () => ({
categories: [],
}),
async created() {
this.categories = await MarketService.loadCategories();
},
methods: {
onCategoryChanged: async function(category) {
console.log(category); //eslint-disable-line
},
},
}
</script>
https://vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks.
- Modify the App component:
- Import and render the ProductsPage component
- Add the relevant CSS, as shown in the following example:
<template>
<div>
<Header />
<div class="main-area">
<ProductsPage />
</div>
</div>
</template>
<script>
import Header from './components/common/Header.vue';
import ProductsPage from './components/market/ProductsPage.vue';
export default {
name: 'app',
components: {
Header,
ProductsPage,
}
}
</script>
<style>
.main-area {
margin: 10px;
}
</style>
Great! You can now the run the app and see the category menu in place. It should look similar to this: