Skip to content

react笔记(二):header导航栏组件

图片

新建脚手架

shell
npx create-react-app my-app --template typescript
npx create-react-app my-app --template typescript

运行以上命令会自动生成集成typescript的react脚手架

我也是第一次用typescript,现在的感受是:还是用js爽

刚刚写了一个header标题栏组件,因为不熟悉typescript,所以基本一直在坑里待着,刚刚才出来

图片

这是刚刚写的标题栏,还没有加菜单点击展开和收起的效果

现在先讲正事

标题栏分了2个组件

第一个是header组件

用typescript的接口方式定义了props的参数类型

第12行开始就是

然后把接口当做props的类型,23行props:HeaderProps

至于这个接口默认值,原本觉得应该和文档一样,后面跟等号赋值,结果获取不到,最后还是利用老方法,在函数里另外设置默认值

js
import React from 'react'

import './open_header.css'

/**
 * 使用interface定义props类型
 * @param height:number 元素的高
 * @param bagColor:string 元素的背景色
 * @param child:React.ReactNode 标识子元素
 * @param:?  问号代表不是必需,可不传参
*/ 
interface HeaderProps {
    height?: number,//number类型
    bagColor?: string,//字符串类型
    borColor?: string,//字符串类型
    children?: React.ReactNode//节点类型
}

/**
 * header布局头部元素
 * @param props传参的数据 类型为HeaderProps
*/
function Header (props:HeaderProps) {
    // 设置默认值
    const height = props.height || 55;
    const bagColor = props.bagColor || '#fff'; 
    const borColor = props.borColor || '#fff'; 
    return (
        <div className="header" style={{height:`${height}px`,background:`${bagColor}`,borderBottom:`1px ${borColor} solid`}}>
            {props.children}
        </div>
    );
}

export default Header;
import React from 'react'

import './open_header.css'

/**
 * 使用interface定义props类型
 * @param height:number 元素的高
 * @param bagColor:string 元素的背景色
 * @param child:React.ReactNode 标识子元素
 * @param:?  问号代表不是必需,可不传参
*/ 
interface HeaderProps {
    height?: number,//number类型
    bagColor?: string,//字符串类型
    borColor?: string,//字符串类型
    children?: React.ReactNode//节点类型
}

/**
 * header布局头部元素
 * @param props传参的数据 类型为HeaderProps
*/
function Header (props:HeaderProps) {
    // 设置默认值
    const height = props.height || 55;
    const bagColor = props.bagColor || '#fff'; 
    const borColor = props.borColor || '#fff'; 
    return (
        <div className="header" style={{height:`${height}px`,background:`${bagColor}`,borderBottom:`1px ${borColor} solid`}}>
            {props.children}
        </div>
    );
}

export default Header;

header组件props参数主要用来实现:自定义高度,背景色和底部边框颜色,还有子组件 children。类似vue的插槽slot

下面实现navbar组件

js
import React from 'react'
import * as ReactDOM from 'react-dom';
//自定义图片组件,可自定义加载占位图和加载失败图
import Image from './image'

import './navbar.css'

/**
 * 使用interface定义props类型
 * @param logo:  string 标题栏logo
 * @param title: string 标题栏网站名
 * @param data:  any[]  菜单栏数据,类型是任意的数组类型
*/ 
interface NavbarProps {
    logo?:string,
    title?:string,
    data?: any[],
    top: numbar}

/**
 * 菜单栏的默认数据
 * :any[] 定义类型为任意数组类型
*/
var datas:any[] = [
    {
        title: '首页',
        link: '/'
    },
    {
        title: '产品',
        link: '/'
    },
    {
        title: '哈哈',
        childs: [
            {
                title: '首页',
                link: '/'
            },
            {
                title: '产品',
                link: '/'
            }
        ]
    },
] 

/**
 * navbar组件
 * @param any,OpenNavbarProps类型
*/
class Navbar extends React.Component <any,NavbarProps> {
    //props后需要定义类型
    constructor(props:NavbarProps) {
        super(props);
        //获取props参数并设置默认值
        this.state = {
            logo: this.props.logo || require('../../assets/img/open.png'),
            title: this.props.title || 'ui-react',
            data: this.props.data || datas,
            top: 0
        }
    }
    componentDidMount() {
        //获取当前navbar的高度,然后设置展开菜单距离顶部距离
        // 类型断言,需要手动指定值的类型
        let el = this.refs.navbar as HTMLElement;
        this.setState({top: el.offsetHeight});
    }
    render() {
        //需要判断一下菜单栏数据,因为是用的本地生命的数据,所以确定有,但是一直报错,判断一下后正常显示了
        const data = this.state.data ? this.state.data : [];
        return  <div className="navbar" ref="navbar">
                    <div className="navbar-brand">
                        <Image width={40} height={40} ></Image>
                        <p className="nav-brand-title">{this.state.title}</p>
                    </div>
                    <ul className="navbar-nav">
                        //遍历时也要定义一下数据类型,因为之前定义的是数组类型,
                        // 但是这里循环内部数据是其他类型,所以要重新定义一下,不然会报错
                        // 定义any任意类型
                        {data.map((item:any,i)=>{
                        return  <li key={i}>
                                {item.childs
                                ?   <div>
                                        <p>{item.title}</p>
                                        <ul style={{top:`${this.state.top}px`}}>
                                            //这里也一样,遍历都重新定义一下类型,这个坑我花了大半个小时才填好
                                            // 一直以为是上面定义菜单数据 时候类型不对,一直去看typescript文档
                                            // 希望找出原因,但是档档最多就定义了2层类型,里面没法定义
                                            // 后面才发现是这里要重新定义一下即可,
                                           {item.childs.map((items:any,index:any)=>{
                                                return <li key={index} >{items.title}</li>
                                            })}
                                        </ul>
                                    </div>
                                : <div><p>{item.title}</p></div>
                                }
                                </li>
                        })}
                    </ul>
                </div>
    }
}

export default Navbar;
import React from 'react'
import * as ReactDOM from 'react-dom';
//自定义图片组件,可自定义加载占位图和加载失败图
import Image from './image'

import './navbar.css'

/**
 * 使用interface定义props类型
 * @param logo:  string 标题栏logo
 * @param title: string 标题栏网站名
 * @param data:  any[]  菜单栏数据,类型是任意的数组类型
*/ 
interface NavbarProps {
    logo?:string,
    title?:string,
    data?: any[],
    top: numbar}

/**
 * 菜单栏的默认数据
 * :any[] 定义类型为任意数组类型
*/
var datas:any[] = [
    {
        title: '首页',
        link: '/'
    },
    {
        title: '产品',
        link: '/'
    },
    {
        title: '哈哈',
        childs: [
            {
                title: '首页',
                link: '/'
            },
            {
                title: '产品',
                link: '/'
            }
        ]
    },
] 

/**
 * navbar组件
 * @param any,OpenNavbarProps类型
*/
class Navbar extends React.Component <any,NavbarProps> {
    //props后需要定义类型
    constructor(props:NavbarProps) {
        super(props);
        //获取props参数并设置默认值
        this.state = {
            logo: this.props.logo || require('../../assets/img/open.png'),
            title: this.props.title || 'ui-react',
            data: this.props.data || datas,
            top: 0
        }
    }
    componentDidMount() {
        //获取当前navbar的高度,然后设置展开菜单距离顶部距离
        // 类型断言,需要手动指定值的类型
        let el = this.refs.navbar as HTMLElement;
        this.setState({top: el.offsetHeight});
    }
    render() {
        //需要判断一下菜单栏数据,因为是用的本地生命的数据,所以确定有,但是一直报错,判断一下后正常显示了
        const data = this.state.data ? this.state.data : [];
        return  <div className="navbar" ref="navbar">
                    <div className="navbar-brand">
                        <Image width={40} height={40} ></Image>
                        <p className="nav-brand-title">{this.state.title}</p>
                    </div>
                    <ul className="navbar-nav">
                        //遍历时也要定义一下数据类型,因为之前定义的是数组类型,
                        // 但是这里循环内部数据是其他类型,所以要重新定义一下,不然会报错
                        // 定义any任意类型
                        {data.map((item:any,i)=>{
                        return  <li key={i}>
                                {item.childs
                                ?   <div>
                                        <p>{item.title}</p>
                                        <ul style={{top:`${this.state.top}px`}}>
                                            //这里也一样,遍历都重新定义一下类型,这个坑我花了大半个小时才填好
                                            // 一直以为是上面定义菜单数据 时候类型不对,一直去看typescript文档
                                            // 希望找出原因,但是档档最多就定义了2层类型,里面没法定义
                                            // 后面才发现是这里要重新定义一下即可,
                                           {item.childs.map((items:any,index:any)=>{
                                                return <li key={index} >{items.title}</li>
                                            })}
                                        </ul>
                                    </div>
                                : <div><p>{item.title}</p></div>
                                }
                                </li>
                        })}
                    </ul>
                </div>
    }
}

export default Navbar;

然后就是引用

html
<Header height={55} borColor={'#eee'}>
    <Navbar title={"openui"}/>
</Header>
<Header height={55} borColor={'#eee'}>
    <Navbar title={"openui"}/>
</Header>

header组件引用navbar,

因为第一次用typescript,可能有些地方还没有写好,后续出问题再修改吧!

本文到此结束。

反馈信息

INFO

邮箱: open_teams@163.com