# 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 (
);
}
}
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 (
);
}
}
```
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 (
);
}
}
```
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 (
);
}
}
```
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 (
);
}
}
```
**示例效果:**
![自定义导航条][]
## 自定义导航条的 左部 和 右部
```
```
## 自定义导航条的 左部、中部、右部
```
```
**示例代码:**
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 (
);
}
}
```
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 来自定义导航条;
这种方式可以自定义导航条,可能完全改变导航条的结构;