iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
Modern Web

MERN Stack + Tailwind CSS - React 小專案實踐計畫系列 第 28

【Day 28】調整專案細節

  • 分享至 

  • xImage
  •  

鐵人挑戰終於快到尾聲了…今天就來調整一些專案的小細節吧:

  • 中英文字串長度判斷
  • 修改 Header 樣式
  • 增加 Back to Top 按鈕

中英文字串長度判斷

因為中文一個字是2個 byte,英文一個字母是1個 byte,但 .length 卻會將中文字當作1個字來回傳,這樣會造成我們在使用 .splice().substring() 時計算長度錯誤,為了解決這種情況,我們可以另外寫一個函數來處理:

  • utils/formatter.js 中新增 subString 函數
  • 傳入參數 str(要判斷的字串)、n(要裁切的長度)
  • 用 Regular Expression 判斷 str 長度是否大於 n ,若小於則回傳字串 str
  • 如果大於的話,則判斷字串的每個字元為中文或英文,如果是中文則 len 長度+2,反之則 len +1(使用 RegExp.test() 來判斷字元是否為中文(符合表達式))
  • 如果判斷後的字串長度 len > n ,則跳出迴圈,反之則將當前字元加入暫時存放字串的 tmpStr
  • 最後回傳符合 n 長度的字串 tmpStr 並加上 「…」
export const subString = (str, n) => {
    if (str.replace(/[\u4e00-\u9fa5]/g, '**').length <= n) {
        return str;
    } else {
        let len = 0;
        let tmpStr = '';
        for (let i = 0; i < str.length; i++) {
            if (/[\u4e00-\u9fa5]/.test(str[i])) {
                len += 2;
            } else {
                len += 1;
            }
            if (len > n) {
                break;
            } else {
                tmpStr += str[i];
            }
        }
        return tmpStr + ' ...';
    }
};

接著一樣匯入使用即可!

<div className="">{loading ? <Skeleton count={3} /> : subString(el.content, 120)}</div>

Header 樣式

目前的 Header 背景設定是透明的,我們可以定義一個狀態變數 isScrollDown 並搭配 window.addEventListener() 來監控使用者是否有往下瀏覽視窗,然後依據條件來渲染不同的樣式

https://i.imgur.com/uTc6j0Q.gif

const [isScrollDown, setIsScrollDown] = useState(false);

useEffect(() => {
    window.addEventListener('scroll', handleScroll, { passive: true });

    return () => {
        window.removeEventListener('scroll', handleScroll);
    };
}, []);

const handleScroll = () => {
    if (window.scrollY >= 80) {
        setIsScrollDown(true);
    } else {
        setIsScrollDown(false);
    }
};

接著在 className 用樣板字串`` 包起來,放入條件判斷來更改樣式

<div
    className={`sticky top-0 z-50 w-screen h-20 text-xl flex flex-row items-center px-14 mb-14 transition ease-in ${
        isScrollDown ? 'bg-yellow-50 h-16' : 'bg-transparent border-b border-b-yellow-700/50'
    }`}
>
...
</div>

Back to Top

https://ithelp.ithome.com.tw/upload/images/20221013/20152502rvHCkKcBVw.png

建立 components/BackToTop.js 檔案,大致上跟 Header 相同概念,在 onClick 時呼叫 scrollToTop → 將視窗移至最上方 window.scrollTo(0, 0)

import React, { useState, useEffect } from 'react';
import { ArrowUpCircleIcon } from '@heroicons/react/24/solid';

export default function BackToTop() {
    const [isVisible, setIsVisible] = useState(false);

    useEffect(() => {
        window.addEventListener('scroll', handleScroll, { passive: true });

        return () => {
            window.removeEventListener('scroll', handleScroll);
        };
    }, []);

    const handleScroll = () => {
        if (window.scrollY > window.innerHeight / 5) {
            setIsVisible(true);
        } else {
            setIsVisible(false);
        }
    };

    const scrollToTop = () => {
        window.scrollTo(0, 0);
    };

    return (
        <div>
            {isVisible && (
                <div
                    className="fixed bottom-16 right-16 text-yellow-700/50 hover:cursor-pointer hover:text-yellow-700/80"
                    onClick={scrollToTop}
                >
                    <ArrowUpCircleIcon className="w-14 h-14" />
                </div>
            )}
        </div>
    );
}

參考資料:


上一篇
【Day 27】資料載入前… Loading 畫面
下一篇
【Day 29】專案部署 - Railway
系列文
MERN Stack + Tailwind CSS - React 小專案實踐計畫30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言