Closed 1chooo closed 8 months ago
import React, {
useState, useEffect
} from 'react';
import {
MdExpandMore
} from "react-icons/md";
import postInitImage from "../../Assets/images/projects/react_vcard_portfolio.png";
import noAdsImage from "../../Assets/images/posts/no_ads.png";
import gitTipsImage from "../../Assets/images/posts/git_tips.png";
import nuphyUnboxingImage from "../../Assets/images/posts/nuphy_unboxing.png";
interface Post {
title: string;
category: string;
imageUrl: string;
date: string;
content: string;
link: string;
}
const postsData: Post[] = [
{
title: '忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!',
category: 'Unboxing',
imageUrl: require('../../Assets/images/posts/no_ads.png'),
date: 'Feb 11, 2024',
content:
'在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!',
link: 'https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a',
},
// 其他文章資料...
];
const Posts: React.FC = () => {
// element toggle function
const elementToggleFunc = (elem: HTMLElement) => {
elem.classList.toggle("active");
};
// custom select variables
const select: HTMLElement | null = document.querySelector("[data-select]");
const selectItems: NodeListOf<HTMLElement> = document.querySelectorAll("[data-select-item]");
const selectValue: HTMLElement | null = document.querySelector("[data-select-value]");
const filterBtn: NodeListOf<HTMLElement> = document.querySelectorAll("[data-filter-btn]");
if (select) {
select.addEventListener("click", function () {
elementToggleFunc(this);
});
}
// add event in all select items
for (let i = 0; i < selectItems.length; i++) {
selectItems[i].addEventListener("click", function () {
let selectedValue: string = this.innerText.toLowerCase();
if (selectValue) {
selectValue.innerText = this.innerText;
}
if (select) {
elementToggleFunc(select);
}
filterFunc(selectedValue);
});
}
// filter variables
const filterItems: NodeListOf<HTMLElement> = document.querySelectorAll("[data-filter-item]");
const filterFunc = (selectedValue: string) => {
for (let i = 0; i < filterItems.length; i++) {
if (selectedValue === "all") {
filterItems[i].classList.add("active");
} else if (selectedValue === filterItems[i].dataset.category) {
filterItems[i].classList.add("active");
} else {
filterItems[i].classList.remove("active");
}
}
};
// add event in all filter button items for large screen
let lastClickedBtn: HTMLElement | null = filterBtn[0];
for (let i = 0; i < filterBtn.length; i++) {
filterBtn[i].addEventListener("click", function () {
let selectedValue: string = this.innerText.toLowerCase();
if (selectValue) {
selectValue.innerText = this.innerText;
}
filterFunc(selectedValue);
if (lastClickedBtn) {
lastClickedBtn.classList.remove("active");
}
this.classList.add("active");
lastClickedBtn = this;
});
}
const [selectedValue, setSelectedValue] = useState('All');
const [isActive, setIsActive] = useState(true); // 如果需要 isActive 的話
useEffect(() => {
// 在這裡可以執行初始化的邏輯
// 例如:fetch 初始資料,或者設置預設的 selectedValue
// 這裡只是一個範例,實際上需要依據你的需求進行修改
// 這樣確保初始化時 'All' 有 'filter-btn active' 的樣式
handleItemClick('All');
}, []); // 空的 dependency array 確保只在初始化時執行
const handleItemClick = (value: string) => {
setIsActive(false);
setSelectedValue(value);
};
return (
<section className="blog-posts">
<ul className="filter-list">
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'All' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('All')}
>
All
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'DevOps' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('DevOps')}
>
DevOps
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'Projects' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('Projects')}
>
Projects
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'Teaching' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('Teaching')}
>
Teaching
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'Technology' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('Data')}
>
Technology
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'Interview' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('Data')}
>
Interview
</button>
</li>
<li className="filter-item">
<button
className={`filter-btn ${selectedValue === 'Unboxing' ? 'active' : ''}`}
data-filter-btn
onClick={() => handleItemClick('Data')}
>
Unboxing
</button>
</li>
</ul>
<div className="filter-select-box">
<button
className={`filter-select ${isActive ? 'active' : ''}`}
data-select
onClick={() => setIsActive(!isActive)}
>
<div className="select-value" data-select-value>
{selectedValue || 'Select category'}
</div>
<div className="select-icon">
<MdExpandMore />
</div>
</button>
<ul className="select-list">
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('All')}
>
All
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('DevOps')}
>
DevOps
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('Projects')}
>
Projects
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('Teaching')}
>
Teaching
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('Technology')}
>
Technology
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('Interview')}
>
Interview
</button>
</li>
<li className="select-item">
<button
data-select-item
onClick={() => handleItemClick('Unboxing')}
>
Unboxing
</button>
</li>
</ul>
</div>
<ul className="blog-posts-list">
<li className="blog-post-item active"
data-filter-item
data-category="unboxing"
>
<a
href="https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={noAdsImage}
alt="No ads"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Unboxing</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Feb 11, 2024</time>
</div>
<h3 className="h3 blog-item-title">
忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!
</h3>
<p className="blog-text">
在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="devops"
>
<a
href="https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={gitTipsImage}
alt="Git Tips Image"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">DevOps</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">
踏入 Git 的世界:使用 ssh 與 GitHub 連線 👨🏻💻
</h3>
<p className="blog-text">
兼顧安全及隱私,利用 ssh key,push 到 GitHub 再也不需要打密碼了🔑
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="unboxing"
>
<a
href="https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={nuphyUnboxingImage}
alt="Git Tips Image"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Unboxing</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">
兼具顏值手感的 Nuphy 鍵盤初體驗!!!
</h3>
<p className="blog-text">
對於機械鍵盤小白的我來說,每個軸體、手感、鍵帽等⋯⋯挑選鍵盤的考量對我來說都非常新奇,身為曾經買過一把機械鍵盤的我來說,正是個適合探索更多鍵盤的時機,於是決定購入觀望已久的鍵盤品牌 Nuphy — Halo 65。
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="interview"
>
<a href="#">
<figure className="blog-banner-box">
<img
src={postInitImage}
alt="Design digest #80"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Interview</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">Design digest #80</h3>
<p className="blog-text">
Excepteur sint occaecat cupidatat no proident, quis nostrum exercitationem ullam corporis
suscipit.
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="devops"
>
<a href="#">
<figure className="blog-banner-box">
<img
src={postInitImage}
alt="UI interactions of the week"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">DevOps</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">UI interactions of the week</h3>
<p className="blog-text">
Enim ad minim veniam, consectetur adipiscing elit, quis nostrud exercitation ullamco laboris
nisi.
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="teaching"
>
<a href="#">
<figure className="blog-banner-box">
<img
src={postInitImage}
alt="The forgotten art of spacing"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Teaching</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">The forgotten art of spacing</h3>
<p className="blog-text">
Maxime placeat, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="teaching"
>
<a href="#">
<figure className="blog-banner-box">
<img
src={postInitImage}
alt="Design digest #79"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Teaching</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">Design digest #79</h3>
<p className="blog-text">
Optio cumque nihil impedit uo minus quod maxime placeat, velit esse cillum.
</p>
</div>
</a>
</li>
</ul>
</section>
);
}
export default Posts;
可以幫我以這段程式碼幫我把 postData 完成嗎?
你希望我們使用 postsData
裡的資料去渲染博客文章列表嗎?如果是的話,我們可以這樣操作:
import React, { useState, useEffect } from 'react';
import { MdExpandMore } from "react-icons/md";
// 你的圖片 import
import postInitImage from "../../Assets/images/projects/react_vcard_portfolio.png";
import noAdsImage from "../../Assets/images/posts/no_ads.png";
import gitTipsImage from "../../Assets/images/posts/git_tips.png";
import nuphyUnboxingImage from "../../Assets/images/posts/nuphy_unboxing.png";
interface Post {
title: string;
category: string;
imageUrl: string;
date: string;
content: string;
link: string;
}
const postsData: Post[] = [
{
title: '忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!',
category: 'Unboxing',
imageUrl: noAdsImage,
date: 'Feb 11, 2024',
content: '在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!',
link: 'https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a',
},
{
title: '踏入 Git 的世界:使用 ssh 與 GitHub 連線 👨🏻💻',
category: 'DevOps',
imageUrl: gitTipsImage,
date: 'Fab 23, 2022',
content: '兼顧安全及隱私,利用 ssh key,push 到 GitHub 再也不需要打密碼了🔑',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
{
title: '兼具顏值手感的 Nuphy 鍵盤初體驗!!!',
category: 'Unboxing',
imageUrl: nuphyUnboxingImage,
date: 'Fab 23, 2022',
content: '對於機械鍵盤小白的我來說,每個軸體、手感、鍵帽等⋯⋯挑選鍵盤的考量對我來說都非常新奇,身為曾經買過一把機械鍵盤的我來說,正是個適合探索更多鍵盤的時機,於是決定購入觀望已久的鍵盤品牌 Nuphy — Halo 65。',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
// 其他文章資料...
];
const Posts: React.FC = () => {
// your component logic
};
export default Posts;
在這裡,我已經將 imageUrl
的屬性從 require
改為了直接使用變數的方式,因為 require
在 TypeScript 中並不是一個有效的模組導入方式。然後我們使用了相應的圖片變數來代替。這樣做應該會解決你的問題。
<li className="blog-post-item active"
data-filter-item
data-category="unboxing"
>
<a
href="https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={noAdsImage}
alt="No ads"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Unboxing</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Feb 11, 2024</time>
</div>
<h3 className="h3 blog-item-title">
忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!
</h3>
<p className="blog-text">
在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="devops"
>
<a
href="https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={gitTipsImage}
alt="Git Tips Image"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">DevOps</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">
踏入 Git 的世界:使用 ssh 與 GitHub 連線 👨🏻💻
</h3>
<p className="blog-text">
兼顧安全及隱私,利用 ssh key,push 到 GitHub 再也不需要打密碼了🔑
</p>
</div>
</a>
</li>
<li
className="blog-post-item active"
data-filter-item
data-category="unboxing"
>
<a
href="https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd"
target="_blank"
rel="noopener noreferrer"
>
<figure className="blog-banner-box">
<img
src={nuphyUnboxingImage}
alt="Git Tips Image"
loading="lazy"
/>
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">Unboxing</p>
<span className="dot"></span>
<time dateTime="2022-02-23">Fab 23, 2022</time>
</div>
<h3 className="h3 blog-item-title">
兼具顏值手感的 Nuphy 鍵盤初體驗!!!
</h3>
<p className="blog-text">
對於機械鍵盤小白的我來說,每個軸體、手感、鍵帽等⋯⋯挑選鍵盤的考量對我來說都非常新奇,身為曾經買過一把機械鍵盤的我來說,正是個適合探索更多鍵盤的時機,於是決定購入觀望已久的鍵盤品牌 Nuphy — Halo 65。
</p>
</div>
</a>
</li>
那你可以幫我改寫這些嗎?透過 PostsData 這樣就不用寫三次
當然,我們可以透過 postsData
來動態渲染這些博客文章列表。讓我們修改一下程式碼:
import React from 'react';
const Posts: React.FC = () => {
// 將你的 `postsData` 放在這裡
const postsData = [
{
title: '忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!',
category: 'Unboxing',
imageUrl: noAdsImage,
date: 'Feb 11, 2024',
content: '在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!',
link: 'https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a',
},
{
title: '踏入 Git 的世界:使用 ssh 與 GitHub 連線 👨🏻💻',
category: 'DevOps',
imageUrl: gitTipsImage,
date: 'Fab 23, 2022',
content: '兼顧安全及隱私,利用 ssh key,push 到 GitHub 再也不需要打密碼了🔑',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
{
title: '兼具顏值手感的 Nuphy 鍵盤初體驗!!!',
category: 'Unboxing',
imageUrl: nuphyUnboxingImage,
date: 'Fab 23, 2022',
content: '對於機械鍵盤小白的我來說,每個軸體、手感、鍵帽等⋯⋯挑選鍵盤的考量對我來說都非常新奇,身為曾經買過一把機械鍵盤的我來說,正是個適合探索更多鍵盤的時機,於是決定購入觀望已久的鍵盤品牌 Nuphy — Halo 65。',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
// 其他文章資料...
];
return (
<section className="blog-posts">
<ul className="blog-posts-list">
{postsData.map((post, index) => (
<li
key={index}
className={`blog-post-item active`}
data-filter-item
data-category={post.category.toLowerCase()}
>
<a href={post.link} target="_blank" rel="noopener noreferrer">
<figure className="blog-banner-box">
<img src={post.imageUrl} alt={post.title} loading="lazy" />
</figure>
<div className="blog-content">
<div className="blog-meta">
<p className="blog-category">{post.category}</p>
<span className="dot"></span>
<time dateTime={post.date}>{post.date}</time>
</div>
<h3 className="h3 blog-item-title">{post.title}</h3>
<p className="blog-text">{post.content}</p>
</div>
</a>
</li>
))}
</ul>
</section>
);
}
export default Posts;
在這個更新後的程式碼中,我們將 postsData
陣列中的資料遍歷並且渲染成了列表。這樣你就不需要手動寫三次相同的代碼了。
import noAdsImage from "../../Assets/images/posts/no_ads.png";
import gitTipsImage from "../../Assets/images/posts/git_tips.png";
import nuphyUnboxingImage from "../../Assets/images/posts/nuphy_unboxing.png";
interface Post {
title: string;
category: string;
imageUrl: string;
date: string;
content: string;
link: string;
}
const postsData: Post[] = [
{
title: '忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!',
category: 'Unboxing',
imageUrl: noAdsImage,
date: 'Feb 11, 2024',
content: '在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!',
link: 'https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a',
},
{
title: '踏入 Git 的世界:使用 ssh 與 GitHub 連線 👨🏻💻',
category: 'DevOps',
imageUrl: gitTipsImage,
date: 'Fab 23, 2022',
content: '兼顧安全及隱私,利用 ssh key,push 到 GitHub 再也不需要打密碼了🔑',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
{
title: '兼具顏值手感的 Nuphy 鍵盤初體驗!!!',
category: 'Unboxing',
imageUrl: nuphyUnboxingImage,
date: 'Fab 23, 2022',
content: '對於機械鍵盤小白的我來說,每個軸體、手感、鍵帽等⋯⋯挑選鍵盤的考量對我來說都非常新奇,身為曾經買過一把機械鍵盤的我來說,正是個適合探索更多鍵盤的時機,於是決定購入觀望已久的鍵盤品牌 Nuphy — Halo 65。',
link: 'https://medium.com/@1chooo/%E8%B8%8F%E5%85%A5-git-%E7%9A%84%E4%B8%96%E7%95%8C-%E4%BD%BF%E7%94%A8-ssh-%E8%88%87-github-%E9%80%A3%E7%B7%9A-7324b01349dd',
},
];
export {};
我想要寫成 components 被 import 請問我要怎麼做?
如果您想將 postsData
從外部文件中導入並在 Posts
組件中使用,您可以將它作為一個模塊導出,然後在需要的地方進行導入。
假設您將 postsData
定義在一個名為 data.ts
的文件中,您可以這樣導出它:
// data.ts
import noAdsImage from "../../Assets/images/posts/no_ads.png";
import gitTipsImage from "../../Assets/images/posts/git_tips.png";
import nuphyUnboxingImage from "../../Assets/images/posts/nuphy_unboxing.png";
export interface Post {
title: string;
category: string;
imageUrl: string;
date: string;
content: string;
link: string;
}
export const postsData: Post[] = [
{
title: '忘掉 YouTube Premium!這些無廣告瀏覽器讓你愛不釋手!',
category: 'Unboxing',
imageUrl: noAdsImage,
date: 'Feb 11, 2024',
content: '在這個廣告橫行的 YouTube 時代,享受影片卻不被廣告干擾的感覺真是太棒了!透過 Brave 瀏覽器,我終於找到了解脫的方法,而且完全不必花錢購買 Premium。讓我們一起換個方式,享受無廣告的 YouTube 世界吧!',
link: 'https://medium.com/@1chooo/%E5%BF%98%E6%8E%89-youtube-premium-%E9%80%99%E4%BA%9B%E7%84%A1%E5%BB%A3%E5%91%8A%E7%80%8F%E8%A6%BD%E5%99%A8%E8%AE%93%E4%BD%A0%E6%84%9B%E4%B8%8D%E9%87%8B%E6%89%8B-901f7d15a59a',
},
// 其他文章資料...
];
然後在 Posts
組件中導入它:
import React from 'react';
import { Post, postsData } from './data'; // 請替換成正確的文件路徑
const Posts: React.FC = () => {
return (
<section className="blog-posts">
<ul className="blog-posts-list">
{postsData.map((post, index) => (
<Post key={index} post={post} />
))}
</ul>
</section>
);
}
export default Posts;
這樣您就可以在 Posts
組件中使用 postsData
了,而不需要將它寫在組件內部。
TOCs
重構 Blog 結構
這樣檔案太長了,你會有什麼建議改寫?因為目前功能是互相關連的,我是 tsx
這個檔案確實有一些地方可以重構和改進,特別是在事件處理、元素選擇和狀態管理方面。以下是一些改進的建議:
將事件處理移動到 React 狀態中管理:目前你在 React 元件外部使用事件監聽器和DOM操作,這不符合 React 的最佳實踐。應該將事件處理移動到 React 元件中,以便更好地利用 React 的生態系統。
使用 useState 和 useEffect 管理選擇狀態:目前你使用了 useState,但是它只管理了選擇狀態的一部分。應該將選擇狀態和元素的顯示狀態整合到一個狀態中,並使用 useEffect 來處理初始狀態和事件訂閱。
提取重複邏輯:在你的代碼中有一些重複的邏輯,比如對過濾按鈕和選擇框的處理。可以考慮將這些邏輯提取到單獨的函數中,以提高代碼的可讀性和重用性。
組件化:如果可能的話,將代碼分成更小的組件,每個組件負責管理自己的狀態和渲染。這樣可以使代碼更具可維護性和可擴展性。
將樣式移動到 CSS 文件中:目前的代碼中包含了大量的樣式,最好將這些樣式移動到單獨的 CSS 文件中,以提高代碼的可讀性和可維護性。
基於上述建議,以下是一個重構後的代碼示例,仍然使用 TypeScript:
這個示例中,我將過濾邏輯整合到了 React 狀態中,使用了 map 函數動態生成了過濾按鈕和選擇框,並將文章數據提取到了單獨的數組中。這樣做使代碼更具可讀性和可維護性,並符合 React 的最佳實踐。
文章取得方法
可以幫我寫個拿到文章資訊的方法嗎?例如變數之類的 這是
.tsx
您可以創建一個函數,讓它接受文章的索引作為參數,然後返回相應索引的文章信息。這是一個示例:
這將返回給定索引處的文章信息,如果索引無效,則返回undefined。您可以根據需要在此基礎上擴展函數,比如添加錯誤處理或其他功能。