[Express+Vue 搭建電商網站] 18 套用 Element UI 到頁面上

18 使用 Element UI

使用 Element UI

先前我們已經把電商的基本功能完成了,只是畫面有點差強人意。
在這一節中我們使用 Element UI 來讓畫面更加美觀,Element UI 是一套 Vue 2.0 的組件庫,提供了許多模板。
在很多時候可以減少我們重造輪子的麻煩

附註:Vue3 並不支援這個組件庫

安裝 Element UI

有三方法可以進行

  1. 使用 npm 套件管理安裝,這也是官方推薦的作法
npm i element-ui -S
  1. 使用 CDN 安裝
    在 index.html 中加入 CDN 連結
<!-- 引入样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>

若是使用 CDN 版本作法,建議加入版本號避免因為 Element UI 升級而受到影響
3. 使用 vue-ui
鑑於 vue/cli 3.0 的釋出,也提供了從 vue-cli 中安裝的套件
官方說明

導入套件

打開主目錄中的 src/main.js 我們要把剛剛安裝的套件導入到專案中註冊依賴

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI);
new Vue({
 router,
 store,
 render: h => h(App)
}).$mount('#app')

除了導入 element-ui 組件庫外,還需要單獨把 CSS 樣式也導入,並且聲明 Vue.use(ElementUI); 來註冊組件庫,接著就是快樂的開始使用組件庫了

重構選單列

打開 src/App.vue 愉快的使用 element-ui 改成酷炫的樣子

<template>
 <div id="app">
 <el-menu
 class="menu"
 :default-active="activeIndex2"
 mode="horizontal"
 @select="handleSelect"
 background-color="#545c64"
 text-color="#fff"
 active-text-color="#ffd04b">
 <el-menu-item index="1"><router-link to="/" tag="div">首頁</router-link></el-menu-item>
 <el-submenu index="2">
 <template slot="title">控制台</template>
 <el-menu-item index="2-1"><router-link to="/admin" tag="div">產品列表</router-link></el-menu-item>
 <el-menu-item index="2-2"><router-link to="/admin/new" tag="div">新增商品</router-link></el-menu-item>
 <el-menu-item index="2-3"><router-link to="/admin/manufacturers" tag="div">製造商列表</router-link></el-menu-item>
 <el-menu-item index="2-4"><router-link to="/admin/manufacturers/new" tag="div">新增製造商</router-link></el-menu-item>
 </el-submenu> 
 <el-menu-item index="3"><router-link to="/cart" tag="div">購物車</router-link></el-menu-item>
 </el-menu>
 <router-view/>
 </div>
</template>
<script>
export default {
 name: 'App',
 data() {
 return {
 activeIndex: '1',
 activeIndex2: '1'
 };
 },
 methods: {
 handleSelect(key, keyPath) {
 console.log(key, keyPath);
 }
 }
};
</script>
<style>
#app {
 font-family: Avenir, Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
 margin-top: 60px;
}
</style>

先不要在意 data 屬性以及 handleSelect 方法,暫時不會碰到。首先看到 <el-menu> 這個標籤,其中的 el-menu-item 帶有幾個屬性。其中 tag 屬性代表將這個內容用 <div> 這個標籤渲染,如果沒設定則預設是 <a> 連結並帶有底線,所以這邊設定為 div 就是為了避免出現底線。

重構商品列表

接著要重構 ProductItem 同時因為子組件被修改,所以 ProductList 也需要修改

ProductList

打開 src/components/products/ProductList.vue<template> 部分修改為

<template>
 <div>
 <div class="products">
 <div class="container">This is ProductList</div>
 <!-- <template v-for="product in products"> -->
 <product-item :products="products"></product-item>
 <!-- </template> -->
 </div>
 </div>
</template>

可以藉由註解了解到,原本是分別將產品傳入子組件再進行渲染。但現在變成了傳入全部商品。至於為什麼?就讓我們看下去

ProductItem

打開 src/components/products/ProductItem.vue 修改成以下內容

<template>
 <div class="products">
 <el-table class="table" :data="products" max-height="250">
 <el-table-column prop="name" label="產品名稱" width="180"></el-table-column>
 <el-table-column prop="description" label="介紹" width="180"></el-table-column>
 <el-table-column prop="price" label="售價" width="180"></el-table-column>
 <el-table-column prop="manufacturer.name" label="製造商" width="180"></el-table-column>
 <!-- <el-table-column
 label="圖片""
 width="200">
 <img :src="image" alt="" class="product__image">
 </el-table-column>-->
 <el-table-column label="操作" width="180">
 <template slot-scope="scope">
 <product-button :id="scope.row._id"></product-button>
 </template>
 </el-table-column>
 </el-table>
 </div>
</template>
<style>
.product {
 border-bottom: 1px solid black;
}
.product__image {
 width: 100px;
 height: 100px;
}
</style>
<script>
import ProductButton from "./ProductButton";
export default {
 name: "product-item",
 props: ["products"],
 components: {
 "product-button": ProductButton
 }
};
</script>

第一,針對傳入值改成 props: ["products"], 因為在父組件做了改變,但是為什麼呢?
再往回看 <template> 中,原來是因為 <el-table> 這個表格組件要傳入一個陣列作為 data 屬性。而最後一個 el-table-column 作為按鈕,所以沒有定義 prop 屬性。為了作為按鈕操作,使用了 scope.row 取得指定物件的 id 作為值傳給了子組件 ProductButton 來操作。

透過 slot-scope 可以取得 row, column, $index 和 store(table 内部的狀態管理)資料

ProductButton

接著就是修改 src/components/products/ProductButton.vue 組件

<template>
 <div>
 <el-button v-if="isAdding" @click="addToCart" type="text" size="small">加入購物車</el-button>
 <el-button v-else @click="removeFromCart(id)" type="text" size="small">從購物車移除</el-button>
 </div>
</template>
<script>
export default {
 props: ["id"],
 computed: {
 product() {
 let product = this.$store.getters.allProducts.find(
 product => product._id === this.id
 );
 return product;
 },
 isAdding() {
 let isAdding = true;
 this.cart.map(product => {
 if (product._id === this.product._id) {
 isAdding = false;
 }
 });
 return isAdding;
 },
 cart() {
 return this.$store.state.cart;
 }
 },
 methods: {
 addToCart() {
 this.$store.commit("ADD_TO_CART", {
 product: this.product
 });
 },
 removeFromCart(productId) {
 this.$store.commit("REMOVE_FROM_CART", {
 productId
 });
 }
 }
};
</script>

使用 element-ui 組件庫提供的按鈕組件 el-button 替換先前普通的按鈕,並且改變了對應的按鈕方法。將父組件傳來的 product 物件換成了單純的 id
因為在 ProductItem 組件中傳入的是指定物件的 id,所以定義了一個 computed product,來取得指定 id 的產品物件。
到這邊我們先看看運行的結果

refactor-product-list.png

上方的功能列已經變成比較好看的樣式了,產品列表也用表單的形式,看起來整齊多了

留言