# nav-react **Repository Path**: guobinyong/nav-react ## Basic Information - **Project Name**: nav-react - **Description**: React版本的导航条,可配置、可扩展! - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2018-01-28 - **Last Updated**: 2022-05-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README [React特性精华]: https://www.jianshu.com/p/2e1421a01ace [本项目的Git仓库]: https://gitee.com/guobinyong/nav-react [默认]: ./assets/默认.png [Navigator结构图]: ./assets/Navigator结构图.jpg [默认navConfig]: ./assets/默认navConfig.gif [页面1]: ./assets/页面1.png [页面切换]: ./assets/页面切换.gif [嵌套导航]: ./assets/嵌套导航.gif [自定义导航条]: ./assets/自定义导航条.gif [自定义导航条Item]: ./assets/自定义导航条Item.gif 目录 ======================= ``` 一.简介 二.安装方式 三.基本使用方式 四.相关组件的功能说明 五.导航条的基本结构 六.简单的设置导航条的基本样式 七.设置导航条的默认配置 八.更改导航条的设置 九.隐藏导航条 十.嵌套导航条 十一.深入理解 NavConfiger 和 Navigator 十二.导航条的高级使用技巧:自定义导航条 十三.设置导航条的各种方式 ``` 内容 ================ # 一.简介 nav-react 是React版本的导航条,后续还会开发 Vue、Angular 版本; 在项目中,导航条是很常用的,大多数页面都需要导航条,所以,在合理的项目结构中,应该把导航条抽离出来共用;于是,通过良好的设计,我便开发出了具备:超级可定制、可扩展、可以实现导航条根据页面内容而改变等强大能力的导航条 nav-react; **如果您在使用该库的过程中有遇到了问题,或者有好的建议和想法,您都可以通过以下方式联系我,期待与您的交流:** - 邮箱:guobinyong@qq.com - QQ:guobinyong@qq.com - 微信:keyanzhe # 二.安装方式 目前,安装方式有以下几种: ## 方式1:通过 npm 安装 ``` npm install --save nav-react ``` ## 方式2:直接下载原代码 您可直接从 [本项目的Git仓库][] 下载,此仓库里包含了 nav-react 和 下文的示例代码;nav-react 库在 [本项目的Git仓库][] 项目的 package/lib 目录下,您可以直接把 lib 目录拷贝到您的项目中去;然后使用如下代码在您的项目中引入 `NavConfiger` 和 `Navigator`: ``` import { NavConfiger,Navigator } from "path/to/lib/Navigator.js"; ``` # 三.基本使用方式 1. 导入 `NavConfiger` 和 `Navigator`: ``` import { NavConfiger,Navigator } from "nav-react"; ``` 2. 用 `NavConfiger` 包在需要导航的内容的外层; 3. 将 `Navigator` 放在导航条的位置,并确保 `Navigator` 是被 `NavConfiger` 包住的; ```

页面内容

``` **效果如下:** ![默认][] 这是没有经过任何配置的 `Navigator` ,只有一个返回图标,点击可返回,导航条也没有背景色;我之所以没有给 `Navigator` 设置太多默认的样式,是因为:项目的导航条是因项目而异的,几乎没有太多共同的样式,我设置默认的样式越多,在您使用此组件时,需要修改的就越多; # 四.相关组件的功能说明 - NavConfiger : 设置 Navigator 的桥梁,为使用者提供了设置导航条的相关的方法; - Navigator : 导航条; **注意:** - Navigator 必须被 包含于 NavConfiger 中; - NavConfiger 和 Navigator 可以不在同一组件中,即: NavConfiger 可以在 Navigator 所以在组件的祖先组件中,只要确保 Navigator 是被 NavConfiger 包着的就行; # 五.导航条的基本结构 ![Navigator结构图][] 在上图所示的导航条结构中,area 表示的是导航条的布局结构,相当容器;item 是被布局的项目,所有的 area 和 item 的组合就构成了导航条;具体的解释如下: - navArea:就是导航条的容器,它是导航条最外层的元素;它里面有3个区域(area),分别用来放置导航条的 左、中、右 item;item 是导航条中 显示的、可操作的项目,可以是 字符串 或者 React元素; - leftArea:在导航条的左部,用来放置 leftItem ,如:返回按钮 等等; - centerArea:在导航条的中部,用来放置 centerItem ,如:导航条的标题 等等; - rightArea:在导航条的右部,用来放置 rightItem ; - leftItem:导航条左边的用来显示 或者 操作的 项目,可以是 字符串 或 React元素; - centerItem:导航条中间的用来显示 或者 操作的 项目,可以是 字符串 或 React元素,如:页面的标题 等等; - rightItem:导航条右部的用来显示 或者 操作的 项目,可以是 字符串 或 React元素; # 六.简单的设置导航条的基本样式 您可以在 `Navigator` 上设置 `className`、`style` 等普通 HTML 元素具有的 props ,`Navigator` 会把它设置到根元素上,即 navArea 上;如: ``` ``` # 七.设置导航条的默认配置 可以通过 Navigator 的prop navConfig 给 Navigator 设置 默认的配置,示例如下: ``` ``` navConfig 接受一个配置对象,该配置对象可配置的字段如下: - hide ?: boolean, // 设置是否显示 导航条 - left ?: string || element, //设置leftItem - center ?: string || element, //设置centerItem - right: ?: string || element, //设置rightItem - leftAction ?: function, //设置 leftItem 的 click 事件处理函数 - rightAction ?: function, //设置 rightItem 的 click 事件处理函数 - navClass ?: string, //设置 navArea 的 css 类 - leftAreaClass ?: string, //设置 leftArea 的 css 类 - centerAreaClass ?: string, //设置 centerClass 的 css 类 - rightAreaClass ?: string, //设置 rightArea 的 csss 类 **示例:** Index.jsx ``` //导入 import React, { Component } from 'react'; import './Index.css' import { NavConfiger, Navigator } from 'nav-react'; class Index extends Component { rightClickHandle(){ alert("您点击了导航条的rightItem!"); } navConfig = { left: "返回", center: "默认的标题", right:

弹窗

, navClass: "nav_area_default" }; render() { return (
基本导航
); } } export { Index }; ``` Index.less ``` .nav_area_default { background-color: #00ff00; } ``` **效果:** ![默认navConfig][] # 八.更改导航条的设置 在实际的项目中,通常会有很多页面都有导航条,为每个页面都加个导航条是编程思想不成熟的一种体现,最好的做法是:把导航条抽离成一个单独的组件,并且各个页面共享一个导航条;这就是本组件 `Navigator` 的任务,但是通常并非所有页面的导航条都一样,比如:有些页面需要给导航条换个样式,有些页面的导航条右侧有按钮,每一个页面的标题不一样...等等,这些都是常见的情况;为了实现页面能够个性化定制导航条,Navigator 提供了这样的机制,使用方法如下: **页面组件定制导航条:** 1. 导入 `PropTypes`; ``` import PropTypes from 'prop-types'; ``` 2. 给组件类添加 contextTypes 属性; ``` // ES6的设置方式 static contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; // 普通的添加方式 PageComponent.contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; ``` 3. 在需要设置导航条时,通过 pushNavConfig 方法将导航条的配置对象推入导航条的配置栈; ``` let navConfig = { left: "默认", center: "页面1" }; this.configID = this.context.pushNavConfig(navConfig); ``` 4. 在需要移除对导航条的设置时,通过 popNavConfig 方法将相应的导航条配置对象推出导航条配置栈; ``` this.context.popNavConfig(this.configID); ``` **完整的示例代码如下:** Page1.jsx ``` import React, { Component } from 'react'; import PropTypes from 'prop-types'; class Page1 extends Component { // 定义 contextTypes ,以使该组件能够接收到 context static contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; configID; navConfig = { left: "默认", center: "页面1", navClass: "page1_nav" }; componentWillMount() { this.configID = this.context.pushNavConfig(this.navConfig); //设置导航条 } componentWillUnmount() { this.context.popNavConfig(this.configID); //移除对导航条的设置 } render() { return (
页面1 我是页面1的内容
); } } export {Page1}; ``` **效果:** ![页面1][] 用同样的方法,再添加个页面2,让 页面2 对 导航条的配置 与 页面1 不一样,可以试下来这2个页面做切换的效果,具体代码我就不再写了,但可以导示下示例效果,如下: ![页面切换][] **说明:** - pushNavConfig : (navConfig)-> configId //往导航条配置栈中推入一个导航条的配置对象 navConfig,并返回配置id,该 id 可用于通过 popNavConfig 方法推出该 id 对应的配置对象; - popNavConfig : (configId)->void //从导航条配置栈中推出 configId 对应的配置对象;configId 是 执行 pushNavConfig 方法的返回值; - 在您需要改变导航条时 通过 pushNavConfig 方法设置导航条,在需要还原改变时,通过 popNavConfig 方法还原导航条; - 对于一个 React 组件,您可以在 `constructor` 、`componentWillMount`、`componentDidMount` 这些方法中执行 `pushNavConfig` 推入导航条的配置对象 ,在 `componentWillUnmount` 中执行 `pushNavConfig` 推出导航条的配置对象; - 我个人建议:最好在 `componentWillMount` 或者 `componentDidMount` 中 执行 `pushNavConfig`,不建议在 `constructor` 中执行; # 九.隐藏导航条 可以通过导航条的配置对象 navConfig 的 hide 字段来设置导航条是否需要隐藏; # 十.嵌套导航条 有时在组件的层级树中可能需要多个导航条,比如:在有导航的页面中打开一个带有导航的子页面...等等; `Navigator` 支持这种使用场景,在 `Navigator` 中,这种机制叫做 嵌套导航; 嵌套导航的使用方式和普通导航的使用方式没什么区别,您只需要在原来的 `NavConfiger` 所包的 内容 或者子组件中 再添加一对 `NavConfiger` 和 `Navigator` 即可; **示例代码:** Index.jsx ``` class Index extends Component { navConfig = { left: "上一页", center: "外层导航", right: 下一页, navClass: "nav_area_default" }; render() { return (
嵌套导航

我是外层页面的内容

); } } ``` Index.css ``` .nav_area_default { background-color: #00ff00; } ``` Page1.jsx ``` class Page1 extends Component { // 定义 contextTypes ,以使该组件能够接收到 context static contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; configID; navConfig = { left: "默认", center: "页面1", right: 子导航, navClass: "page1_nav" }; componentWillMount() { this.configID = this.context.pushNavConfig(this.navConfig); //设置导航条 } componentWillUnmount() { this.context.popNavConfig(this.configID); //移除对导航条的设置 } render() { return (
页面1

我是页面1

); } } ``` Page1.css ``` .page1_nav { background-color: red; } ``` Page2.jsx ``` class Page2 extends Component { static contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; configID; myNavConfig = { left: "页面1", center: "页面2", navClass: "page2_nav" }; defaultNavConfig = { left: "上一页", center: "内层导航", right: 下一页, navClass: "nav_area_default" }; componentWillMount() { this.configID = this.context.pushNavConfig(this.myNavConfig); } componentWillUnmount() { this.context.popNavConfig(this.configID); } render() { return (
页面2

我是内层导航的内容

); } } ``` Page2.css ``` .page2_nav { background-color: blue; } ``` Page3.jsx ``` class Page3 extends Component { // 定义 contextTypes ,以使该组件能够接收到 context static contextTypes = { pushNavConfig: PropTypes.func, popNavConfig: PropTypes.func, }; configID; navConfig = { left: "上一页", center: "页面3", right: 列表, navClass: "page3_nav" }; componentWillMount() { this.configID = this.context.pushNavConfig(this.navConfig); //设置导航条 } componentWillUnmount() { this.context.popNavConfig(this.configID); //移除对导航条的设置 } render() { return (
页面3

我是页面3

); } } ``` Page3.css ``` .page3_nav { background-color: yellow; } ``` **示例效果:** ![嵌套导航][] ## NavConfiger 和 Navigator 的嵌套使用规则 为了使用更加简单,我把 `NavConfiger` 设计成可以管理多个 `Navigator` ,但是由于 React 在切换组件时,会先创建和挂载新组件,然后再卸载被替换掉的组件,导致这个特性只能在以下情况中使用: - 如果:多个 `Navigator` 总是同时销毁,那么:这几个 `Navigator` 可以共同一个 `NavConfiger`,也可以每个 `Navigator` 单独用一个 `NavConfiger` 管理 ; - 如果:多个 `Navigator` 并不是同时销毁,那么:应该用多个 `NavConfiger` 分别管理不同时销毁的 `Navigator`; 否则,将可能产生与您预期不符的现象; 关于造成这种使用限制的原因,可参考: 下面的《NavConfiger 和 Navigator 的工作原理》并结合 “《[React特性精华][]》/5. 组件/组件的渲染”; # 十一.深入理解 NavConfiger 和 Navigator ## NavConfiger 有以下几个功能: - 为子组件在上下文中提供 `pushNavConfig` 和 `popNavConfig` 方法来 推入 和 弹出 导航条的配置对象; - 提供一个 导航条栈 ,管理着子组件中的导航条; ## Navigator 有以下几个功能: - 提供一个导航条配置对象栈,管理着多个导航条的配置对象; - 把配置栈中栈顶的配置对象渲染成导航条; ## 导航条栈 和 导航条配置对象栈 的工作机制: - 导航条栈 由 NavConfiger 实例管理;导航条配置对象栈 由 Navigator 实例管理; - 每当 Navigator 实例被将要被挂载时,会把自己推入到祖先组件中最近的 NavConfiger 实例的 导航条栈 的 栈顶; - 每当 Navigator 实例在将根被卸载时,会把自己从祖先组件中最近的 NavConfiger 实例的 导航条栈 导航条栈中 弹出; - 每当在组件中调用 `pushNavConfig` 方法时,会把传入的配置对象推入到该组件的祖先组件中最近的 NavConfiger 实例的 导航条栈 中 位于栈顶的 Navigator 实例的 导航条配置对象栈 的栈顶; - 每当在组件中调用 `popNavConfig` 方法时,会从该组件的祖先组件中最近的 NavConfiger 实例的 导航条栈 中 位于栈顶的 Navigator 实例的 导航条配置对象栈 中弹出与传入的 configID 对应的导航条配置对象; # 十二.导航条的高级使用技巧:自定义导航条 通过 navConfig 配置对象,您可以充分配置 Navigator 实例,通常,这已经能够满足绝大部分场景;尽管如此,我仍然给 Navigator 设计了允许您完全定制导航条的接口,您可以通过 Navigator 的 children 实现自定义的导航条,具体规则如下: **通过 Navigator 实例的 children 来定制 导航条的规则:** - 当 Navigator 实例有1个 children 时,该 children 会作为整个导航条; - 当 Navigator 实例有2个 children 时,第1个 children 会作为导航条的 leftItem,第2个 children 会作为导航条的 rightItem; - 当 Navigator 实例有3个 children 时,第1个 children 会作为导航条的 leftItem,第2个 children 会作为导航条的 centerItem,第3个 children 会作为导航条的 rightItem; - 所有的 children 都会接收一个表示当前生效的配置对象的prop `navConfig`,所以,可以在自定义的 children 组件中 通过 `props.navConfig` 访问当前生效的导航条配置对象; ## 完全自定义导航条 ``` ``` CustomNav 是您自定义的导航条,CustomNav 会接收一个表示当前生效的配置对象的prop `navConfig`, 所以,在 CustomNav 中,可以通过 this.props.navConfig 访问当前生效的配置对象; **示例代码:** ``` function CustomNav(props) { return

自定义:{props.navConfig.center}

} class Index extends Component { rightClickHandle() { alert("您点击了导航条的rightItem!"); } navConfig = { left: "返回", center: "默认的标题", right:

弹窗

, navClass: "nav_area_default" }; render() { return (
自定义导航

跳转到:页面1
); } } ``` **示例效果:** ![自定义导航条][] ## 自定义导航条的 左部 和 右部 ``` ``` ## 自定义导航条的 左部、中部、右部 ```
``` **示例代码:** Index.jsx ``` function Left(props) { return

左:{props.navConfig.left}

} function Center(props) { return

中:{props.navConfig.center}

} function Right(props) { return

右:{props.navConfig.right}

} class Index extends Component { rightClickHandle() { alert("您点击了导航条的rightItem!"); } navConfig = { left: "LeftItem", center: "Title", right: "RightItem", navClass: "nav_area_default" }; render() { return (
自定义导航

跳转到:页面1
); } } ``` Page1的 navConfig 对象: ``` navConfig = { left: "1左", center: "页面1", right:"1右", navClass: "page1_nav" }; ``` Page2的 navConfig 对象: ``` navConfig = { left: "2左", center: "页面2", right:"2右", navClass: "page2_nav" }; ``` **示例效果:** ![自定义导航条Item][] # 十三.设置导航条的各种方式 看到这里,您应该发现:有多种配置导航条的方式;现总结如下: - 给 Navigator 标签设置 prop ``,如: `className`、`style` 等等; 这种方式只能设置导航条的样式; - 给 Navigator 设置默认配置对象 ,如:``; 这种方式只是提供导航条的默认配置对象; - 通过context的方法 `pushNavConfig`、`popNavConfig`,来设置 导航条的配置对象; 这种方式用于每个页面根据自己的情况配置单独配置导航条;这种方式提供的配置对象 会 覆盖 Navigator 的默认配置对象; - 通过 Navigator 的 children 来自定义导航条; 这种方式可以自定义导航条,可能完全改变导航条的结构;