react仿网易云音乐项目实践(一)

954 阅读2分钟

前言

react +webpack5 + ts 框架搭建专栏学习后,很长时间没有来掘金更新了,今天起正式开始进行项目实践开发!!!

产品:仿网易云音乐demo

前置项

react:react18
打包工具:webpack5
路由:react-router-dom@6.x
UI:antd4.21.7
语言:typescript
node: node14
axioseslintprettier代码规范配置


1. 头部导航菜单

header引入logo图片时,报以上问题: image.png 解决方法:global.d.ts中进行声明 image.png

头部导航效果如下: image.png 引入antd-icon图标时一直报:缺少rev属性 image.png 解决:antd官网上也有好多人反馈该问题 image.png

官网大牛建议:升级@type/react @type/react-dom至最新版本 image.png 以上升级之后,又报错: image.png 原因查找:说是由于TS版本与@types/react版本不匹配导致 但是版本一致后仍存在该问题

最终解决: tsconfig.json中添加改配置 image.png 最终header效果:

image.png

2.二级导航

image.png 前期准备,回顾下screenX pageX clientX offsetX区别:

  • screenXscreenY鼠标点击的位置相对屏幕水平、垂直方向上的距离。 image.png

  • clientXclientY:鼠标点击位置相对于用户端(当前屏幕/浏览器窗口) 能看到的可视区域 水平、垂直方向上的距离(不关心溢出的部分,只关注能看到的区域),从当前区域的左上角可视计算距离。 image.png 无需考虑溢出的部分 image.png

  • pageXpageY:页面未溢出不存在滚动的时候,pageX就相当于clientX,若页面发生滚动,则pageX即为 滚动距离 scrollTop + clientX;pageY同理。

    未滚动时: image.png 滚动时: image.png

  • offsetXoffsetY:相对于绑定事件的元素 水平、垂直方向上的距离。 image.png

一级导航选中icon元素定位:

效果: Rec_2023-12-19_0001000000-000007.gif

思路:动态设置该icon元素的left值 = menu-selected 元素的 offsetLeft + (offsetWidth - icon的width) / 2

动态计算left值

// 每次切换路由,获取当前最新的pathname,并赋给menu组件
    useEffect(() => {
        // 初始化路由重定向
        if (location.pathname === '/') {
            navigate('/home')
        }
        // 获取当前选中的menu item
        getSelectedMenu()
    }, [location.pathname])
    // 动态计算icon定位元素的left数据
    const getSelectedMenu = () => {
        let iconLeft = 0
        // 获取当前选中的menu item
        const menuSelected = document.getElementsByClassName('ant-menu-item-selected')[0]
        // 获取该元素到浏览器可视范围的距离
        const rect = menuSelected.getBoundingClientRect()
        // 动态计算icon的left值
        iconLeft = rect.left + (rect.width - 14) / 2
        props.menuChange(iconLeft) // 将数据传递到父组件
    }

将计算的数据动态绑定到iconstyle样式即可

    state = {
        iconLeft: 271,
    }
    // 接收子组件数据
    menuChange = val => {
        this.setState({ iconLeft: val })
    }
   <CaretUpOutlined className={header.cor} style={{ left: this.state.iconLeft }} />

添加二级导航内容,完善交互

<div className={home.nav}>
    {btnList.map(btn => {
        return (
            <Button
                type="text"
                key={btn.value}
                value={btn.value}
                className={home.btn}
                onClick={() => btnClick(btn.value)}
            >
                <span
                    style={{
                        backgroundColor: currentType === btn.value ? '#9B0909' : '',
                    }}
                >
                    {btn.text}
                </span>
            </Button>
        )
    })}
</div>

最终效果: Rec_2023-12-20_0001000000-000004.gif

业务模块页面

1. 发现音乐

1.1 推荐页

走马灯效果: Rec_2023-12-21_0002(1)000000-000012.gif

待续...

相关链接: github代码地址 dev分支