// 購物網站專案的完整資料夾架構與檔案結構如下:

資料夾架構

shopping-website/
├── frontend/             # 前端 (Vue CLI 專案)
│   ├── public/           # 公共靜態資源
│   ├── src/              # 源代碼
│   │   ├── assets/       # 靜態資源 (圖片、CSS 等)
│   │   ├── components/   # Vue 組件
│   │   ├── router/       # 路由配置
│   │   ├── views/        # 頁面文件
│   │   ├── App.vue       # Vue 主組件
│   │   └── main.js       # Vue 入口文件
│   └── package.json      # 前端依賴與腳本配置
├── backend/              # 後端 (PHP + MySQL)
│   ├── api/              # API 文件
│   │   ├── db.php        # 資料庫連接設置
│   │   ├── products.php  # 商品相關 API
│   │   ├── users.php     # 使用者相關 API
│   ├── config/           # 配置文件
│   │   └── config.php    # 資料庫配置
│   └── index.php         # 後端入口文件
├── database/             # MySQL 資料庫腳本
│   └── schema.sql        # 資料庫結構
├── README.md             # 專案說明文件
└── .gitignore            # Git 忽略文件

前端 (Vue CLI)

安裝 Vue CLI 專案

  1. 使用 vue create my-project 創建專案。
  2. src 資料夾中:
    • assets/ 用於存放靜態資源如圖片與樣式表。
    • components/ 存放可複用的 Vue 組件。
    • router/ 中新增 index.js 並設置路由。
    • views/ 創建對應的頁面組件,如 Home.vueProduct.vue

範例代碼

main.js

// 引入 Vue 核心模塊
import { createApp } from 'vue';
// 引入主組件 App.vue
import App from './App.vue';
// 引入路由配置
import router from './router';

// 創建 Vue 應用實例,掛載路由,並綁定到 id 為 #app 的 DOM 元素
createApp(App).use(router).mount('#app');

router/index.js

// 引入 Vue 路由模塊
import { createRouter, createWebHistory } from 'vue-router';
// 引入首頁組件
import Home from '../views/Home.vue';
// 引入商品頁組件
import Product from '../views/Product.vue';

// 定義路由配置
const routes = [
  { path: '/', name: 'Home', component: Home }, // 根路徑對應 Home 組件
  { path: '/product', name: 'Product', component: Product }, // 商品頁對應 Product 組件
];

// 創建路由實例,並設置為 HTML5 模式
const router = createRouter({
  history: createWebHistory(),
  routes, // 加載路由配置
});

// 導出路由實例
export default router;

App.vue

<template>
  <!-- 主模板,router-view 用於顯示當前路由對應的頁面組件 -->
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: 'App', // 組件名稱
};
</script>

<style>
/* 引入 Bootstrap 樣式表 */
@import 'https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css';
</style>

App.vue - router-view補充

App.vue 中插入 <router-view></router-view> 的作用是為了讓 Vue Router 能夠根據當前路由顯示對應的頁面內容。以下是主要用意的詳細解釋:

  1. 路由占位符:
    <router-view>是 Vue Router 提供的一個內建組件,它會動態渲染根據路由匹配到的組件或頁面。當用戶訪問不同的 URL 時,對應的頁面會自動加載並顯示在這個位置。

  2. 動態頁面內容:
    使用 <router-view>,可以讓單頁應用程序(SPA)實現不同路由對應的內容切換,而無需重新加載整個網頁。例如:

    • 當路由為 / 時,顯示首頁。
    • 當路由為 /product 時,顯示商品列表頁。
  3. 結合導航列使用:
    App.vue 中,導航列(<Navbar />)通常是固定的,位於頁面頂部,而 <router-view> 是頁面的主要內容區域,會隨著用戶的路由切換而改變。

  4. 可擴展性:
    如果未來需要添加更多頁面(例如購物車頁面或用戶中心),只需在路由配置中新增對應的路由,而 <router-view> 能自動呈現新頁面,這讓應用的擴展變得更加簡單和高效。

簡單來說,<router-view> 是 Vue Router 中的「內容渲染區域」,它的作用是根據路由動態顯示不同的頁面內容,實現頁面間的無縫切換。

views/Home.vue

<template>
  <div class="home">
    <!-- 歡迎標題 -->
    <h1>歡迎來到購物網站</h1>
    <!-- 跳轉到商品頁的按鈕 -->
    <a href="/product" class="btn btn-primary">查看商品</a>
  </div>
</template>

<script>
export default {
  name: 'Home', // 組件名稱
};
</script>

<style scoped>
/* 設置首頁樣式,置中並調整間距 */
.home {
  text-align: center;
  margin-top: 50px;
}
</style>

views/Product.vue

<template>
  <div class="product">
    <!-- 商品列表標題 -->
    <h1>商品列表</h1>
    <!-- 使用 v-for 渲染商品數據 -->
    <ul>
      <li v-for="product in products" :key="product.id">
        <!-- 顯示商品圖片 -->
        <img :src="product.image" alt="商品圖片" width="100" />
        <!-- 顯示商品名稱與價格 -->
        {{ product.name }} - {{ product.price }} 元
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: 'Product', // 組件名稱
  data() {
    return {
      // 商品數據列表
      products: [
        { id: 1, name: '商品A', price: 100, image: 'https://picsum.photos/100?random=1' }, // 商品 A
        { id: 2, name: '商品B', price: 200, image: 'https://picsum.photos/100?random=2' }, // 商品 B
      ],
    };
  },
};
</script>

<style scoped>
/* 商品頁樣式設置,增加內邊距 */
.product {
  padding: 20px;
}
</style>

組件拆分建議與範例

商品卡片組件 (ProductCard)

使用原因:

商品列表中的每個商品都有圖片、名稱和價格,這部分結構類似,適合作為一個可重複使用的組件。

ProductCard.vue

<template>
  <div class="product-card">
    <img :src="image" alt="商品圖片" width="100" />
    <h3>{{ name }}</h3>
    <p>{{ price }}</p>
  </div>
</template>

<script>
export default {
  name: 'ProductCard',
  props: {
    name: String,
    price: Number,
    image: String,
  },
};
</script>

<style scoped>
.product-card {
  border: 1px solid #ddd;
  padding: 10px;
  text-align: center;
  margin-bottom: 10px;
}
</style>

Product.vue

<template>
  <div class="product">
    <h1>商品列表</h1>
    <div class="product-list">
      <ProductCard
        v-for="product in products"
        :key="product.id"
        :name="product.name"
        :price="product.price"
        :image="product.image"
      />
    </div>
  </div>
</template>

<script>
import ProductCard from '../components/ProductCard.vue';

export default {
  name: 'Product',
  components: {
    ProductCard,
  },
  data() {
    return {
      products: [
        { id: 1, name: '商品A', price: 100, image: 'https://picsum.photos/100?random=1' },
        { id: 2, name: '商品B', price: 200, image: 'https://picsum.photos/100?random=2' },
      ],
    };
  },
};
</script>

導航列組件 (Navbar)

使用原因:

導航列可以作為一個全局的組件,放在網站的頂部,包含網站名稱和導覽連結。

<template>
  <nav class="navbar">
    <h1>購物網站</h1>
    <ul>
      <li><router-link to="/">首頁</router-link></li>
      <li><router-link to="/product">商品列表</router-link></li>
    </ul>
  </nav>
</template>

<script>
export default {
  name: 'Navbar',
};
</script>

<style scoped>
.navbar {
  background-color: #333;
  color: white;
  padding: 10px;
}
.navbar ul {
  list-style: none;
  padding: 0;
  display: flex;
  gap: 15px;
}
.navbar a {
  color: white;
  text-decoration: none;
}
</style>

App.vue

<template>
  <div id="app">
    <Navbar />
    <router-view></router-view>
  </div>
</template>

<script>
import Navbar from './components/Navbar.vue';

export default {
  name: 'App',
  components: {
    Navbar,
  },
};
</script>

頁面標題組件 (PageTitle)

使用原因:

每個頁面都有標題,例如「歡迎來到購物網站」或「商品列表」,這可以抽象成一個簡單的標題組件,避免重複定義標題樣式。

PageTitle.vue

<template>
  <h1 class="page-title">{{ title }}</h1>
</template>

<script>
export default {
  name: 'PageTitle',
  props: {
    title: String,
  },
};
</script>

<style scoped>
.page-title {
  text-align: center;
  margin-top: 20px;
  color: #333;
}
</style>

Home.vue 使用範例

<template>
  <div class="home">
    <PageTitle title="歡迎來到購物網站" />
    <a href="/product" class="btn btn-primary">查看商品</a>
  </div>
</template>

<script>
import PageTitle from '../components/PageTitle.vue';

export default {
  name: 'Home',
  components: {
    PageTitle,
  },
};
</script>

按鈕組件 (Button)

使用原因:

「查看商品」按鈕和其他按鈕可以共用樣式和行為,這部分可以拆成一個按鈕組件。

Button.vue

<template>
  <button :class="buttonClass" @click="onClick">{{ label }}</button>
</template>

<script>
export default {
  name: 'Button',
  props: {
    label: String,
    buttonClass: String,
    onClick: Function,
  },
};
</script>

<style scoped>
button {
  padding: 10px 20px;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
</style>

Home.vue 使用範例

<template>
  <div class="home">
    <PageTitle title="歡迎來到購物網站" />
    <Button label="查看商品" :onClick="navigateToProduct" buttonClass="btn btn-primary" />
  </div>
</template>

<script>
import PageTitle from '../components/PageTitle.vue';
import Button from '../components/Button.vue';

export default {
  name: 'Home',
  components: {
    PageTitle,
    Button,
  },
  methods: {
    navigateToProduct() {
      this.$router.push('/product');
    },
  },
};
</script>

後端 (PHP + MySQL)

設置資料庫

  1. 使用 schema.sql 創建資料表。
  2. 配置 config/config.php 文件來設置資料庫連接。

範例代碼

backend/config/config.php

<?php
$host = 'localhost';
$dbname = 'shopping';
$username = 'root';
$password = '';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    die("資料庫連接失敗: " . $e->getMessage());
}

backend/api/db.php

<?php
require_once '../config/config.php';

backend/api/products.php

<?php
require_once 'db.php';

$query = $pdo->query("SELECT * FROM products");
$products = $query->fetchAll(PDO::FETCH_ASSOC);

echo json_encode($products);

database/schema.sql

CREATE DATABASE shopping;

USE shopping;

CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) NOT NULL
);

INSERT INTO products (name, price) VALUES
('商品A', 100),
('商品B', 200);

個人補充筆記

一、views 與 components 區別

在 Vue CLI 專案中,views 資料夾通常用來存放「頁面級別」的組件,也就是對應不同路由的檔案。這些檔案代表應用程式中不同的畫面(或頁面),例如首頁、商品列表頁、購物車頁等。

二、App.vue補充

  1. App.vue 主要作用
    App.vue 是 Vue 項目中的根組件,負責組織和顯示整個應用的基礎結構。通常會包括應用的框架,如頁面布局、通用樣式以及引入其他組件。

  2. router-view 的作用
    如果你使用了 Vue Router(路由套件),你會在 App.vue<template> 部分加入 <router-view></router-view>。這個標籤是用來顯示當前路由匹配的組件內容,根據路由的切換會動態渲染對應的頁面或組件。

  3. 自定義導覽列的使用
    如果你有自定義的導航列(例如:Navbar.vue 組件),需要在 App.vue 中引入並在 <template> 中使用。具體做法是:

    • App.vue<script> 部分進行引入:
      ​​​​​import Navbar from './components/Navbar.vue';
      
    • 然後在 <template> 中使用這個組件:
      ​​​​​<template>
      ​​​​​  <div>
      ​​​​​    <Navbar />
      ​​​​​    <router-view></router-view>
      ​​​​​  </div>
      ​​​​​</template>
      

這樣,App.vue 就會顯示你的導航列並且根據不同的路由渲染相對應的組件。

三、Views補充

四、Router/index.js補充

當新增一個畫面(頁面級別的組件)時,需要在 router/index.js 中配置該畫面的路由,並引入相對應的頁面組件,這樣 Vue Router 才能知道如何將指定的 URL 路徑對應到該畫面。

// 引入 Vue 路由模塊 import { createRouter, createWebHistory } from 'vue-router'; // 引入首頁組件 import Home from '../views/Home.vue'; // 引入商品頁組件 import Product from '../views/Product.vue'; // 定義路由配置 const routes = [ { path: '/', name: 'Home', component: Home }, // 根路徑對應 Home 畫面 { path: '/product', name: 'Product', component: Product }, // 商品頁對應 Product 畫面 ]; // 創建路由實例,並設置為 HTML5 模式 const router = createRouter({ history: createWebHistory(), routes, // 加載路由配置 }); // 導出路由實例 export default router;

五、src/main.js補充

如果有要安裝套件至 VueCli 需要在 Node.js 終端輸入 npm install bootstrap

六、VueCli引入Jquery

七、同畫面跳轉

要在methods使用this.$router.push();的方式並在上方使用:onClick