Django + React 電商專案練習 [15] - 產品輪播圖

輪播顯示高評價的產品

Posted by Young on 2022-12-05
Estimated Reading Time 3 Minutes
Words 685 In Total

後端

view(篩選+排序高評分產品)

  • gte: greater than or equal to,只抓取評分 >= 4 的產品
  • 排序方式為 rating 由高到低,只取前 5 個產品
1
2
3
4
5
6
# product_views.py
@api_view(['GET'])
def getTopProducts(request):
products = Product.objects.filter(rating__gte=4).order_by('-rating')[:5]
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)

url

1
2
# urls.py
path('top-rated/', views.getTopProducts,name="top_rated_products"),

此時去訪問 /api/products/top-rated/,應能看到以下回傳:

drf_ranked

前端

Constants

1
2
3
4
// productConstants.js
export const PRODUCT_TOP_RATED_REQUEST = "PRODUCT_TOP_RATED_REQUEST";
export const PRODUCT_TOP_RATED_SUCCESS = "PRODUCT_TOP_RATED_SUCCESS";
export const PRODUCT_TOP_RATED_FAIL = "PRODUCT_TOP_RATED_FAIL";

Reducers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// productReducers.js
// 取得評分高的產品
export const productTopRatedReducer = (state = { products: [] }, action) => {
switch (action.type) {
case PRODUCT_TOP_RATED_REQUEST:
return { loading: true };
case PRODUCT_TOP_RATED_SUCCESS:
return { loading: false, products: action.payload };
case PRODUCT_TOP_RATED_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};

新增到 store.js,一樣例行公事,先回 Redux DevTools 確認新增有新增成功:

redux_tools_check

Actions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 取得評分高的產品
export const listTopRatedProducts = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_TOP_RATED_REQUEST });
const { data } = await axios.get(`/api/products/top-rated/`);
dispatch({
type: PRODUCT_TOP_RATED_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: PRODUCT_TOP_RATED_FAIL,
payload: error.response && error.response.data.message ? error.response.data.message : error.message,
});
}
};

<Carousel> 即為 Bootstrap 的輪播主體元件,<Carousel.Item> 為輪播的每個項目,<Image> 為顯示圖片的元件,而 <Carousel.Caption> 為顯示文字的元件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import React, { useEffect } from "react";
import { Carousel, Image } from "react-bootstrap";
import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
// 載入元件
import Loader from "./Loader";
import Message from "./Message";
// 載入 action
import { listTopRatedProducts } from "../actions/productActions";

const ProductCarousel = () => {
const dispatch = useDispatch();

const { loading, error, products } = useSelector((state) => state.productTopRated);

useEffect(() => {
dispatch(listTopRatedProducts());
}, [dispatch]);

return loading ? (
<Loader />
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<Carousel pause='hover' className='product-carousel'>
{products.map((product) => (
<Carousel.Item key={product.id} className='carousel-item'>
<Link to={`/product/${product.id}`}>
<div className='image-container'>
<Image src={product.image} alt={product.name} className='carousel-image' />
</div>
<Carousel.Caption className='carousel-caption'>
<h2>
{product.name} <span>${product.price}</span>
</h2>
</Carousel.Caption>
</Link>
</Carousel.Item>
))}
</Carousel>
);
};

export default ProductCarousel;

加到 HomePage.js後,為了確保用戶在進行關鍵字搜尋的情況下,不顯示 Carousel 輪播,判斷無 keyword 時才顯示 Carousel:

1
2
3
4
5
6
7
8
// HomePage.js
return (
<div>
...
{!keyword && <ProductCarousel />}
...
</div>
);

最後自己寫 CSS 簡單調整一下 Carousel 的樣式,

  1. 固定圖片大小,並添加陰影效果及圓邊
  2. 讓產品及產品價格於 Carousel 相對位置的中間顯示
  3. Hover時能有放大產品效果

得到以下結果:

carousel_done


若您覺得這篇文章對您有幫助,歡迎分享出去讓更多人看到⊂◉‿◉つ~


留言版