React的学习1
React 是什么?
一个用于构建用户界面的 JavaScript 库
中文手册:https://react.docschina.org/
用户界面:WEB --- 网页 --- 用户可以看到并使用的视图界面
命令式编程 和 声明式编程
命令式编程:告诉计算机怎么做(How) - 过程
命令式编程: 命令“机器”如何去做事情(how),这样不管你想要的是什么(what),它都会按照你的命令实现。 举个例子: var numbers = [1,2,3,4,5] var doubled = [] for(var i = 0; i < numbers.length; i++) { var newNumber = numbers[i] * 2 doubled.push (newNumber) } console.log (doubled) //=> [2,4,6,8,10]声明式编程:告诉计算机我们要什么(What) - 结果
举个例子: var numbers = [1,2,3,4,5] var doubled = numbers.map (function (n) { return n * 2 }) console.log (doubled) //=> [2,4,6,8,10]能让我们站在更高的层面是思考,站在云端思考我们想要的是什么,而不是站在泥里思考事情该如何去做。
如何使用 React
基于浏览器的模式
基本的api使用:
React.createElement(type,props,children);
React.createElement 用于构建视图,返回值是一个用来描述视图的虚拟DOM(纯对象格式) React.createElement(type,props,children,...childrenN); - type 节点类型 (标签名|组件名) - props 元素对应的属性 (object|null) - children 内容或子节点(包括文本节点) (可以有多个)
ReactDOM.render(Vnode, container[, callback])
ReactDOM.render(VDom, container[, callback]) 将构建好的视图(虚拟DOM)渲染成真实DOM - VDom:要渲染的内容(要构建的视图) - container:要渲染的内容存放容器(挂载节点、要构建的视图放在哪个真实元素中) - callback:渲染后的回调函数(可选参数)举个例子:
<head> <script src="js/react.js"></script> <script src="js/react-dom.js"></script> </head> <body> <div id="root"></div> <script> /* react.js主要负责构建视图和构建组件 依赖顺序:react-dom.js依赖于react.js 所以得先引入react.js!! */ //$$typeof: Symbol(react.element) console.log(React,'react.js暴露了一个React对象(大写R)'); console.log(React.createElement('div',{className:'box'},'box')); // 返回值是一个用来描述视图的虚拟DOM // 对象格式 问题:为什么需要加入虚拟DOM?对比虚拟Dom的原理? //创建虚拟DOM let header = React.createElement("header",{className:"header div",id:"header"},"页面头部"); //console.log(ReactDOM,'react-dom.js暴露了一个ReactDOM对象'); //将虚拟DOM转换为真实的DOM元素 //被渲染为:<header class="header div" id="header">页面头部</header> ReactDOM.render( header, document.querySelector("#root"),()=>{ console.log("构建完成") } ); </script> </body>
基于React的视图构建
- 构建一个复杂点的视图
<head>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
</head>
<body>
<div id="root"></div>
<script>
//创建虚拟DOM
//React.createElement的第三个参数可以是子节点
let logo = React.createElement("h1",{id:"logo"},"林");
let a1 = React.createElement("a",{href:"/index"},"a1");
let a2 = React.createElement("a",{href:"/about"},"a2");
let nav = React.createElement("nav",{className:"nav"},a1,a2);
let header = React.createElement("header",{className:"header div",id:"header"},logo,nav);
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
复杂点的视图构建暴露出来的问题:构建试图过于麻烦!
用JSX就来解决这个问题
浏览器默认是不认识JSX语法的
- 在不使用脚手架构建react项目之前,为了让浏览器认识JSX语法需要引入babel.js
- babel.js链接
<head> <script src="js/react.js"></script> <script src="js/react-dom.js"></script> <script src="js/babel.js"></script> </head> <body> <div id="root"></div> <script type="text/babel"> let header = <header className="header div" id="header"> <h1 id="logo">林吧</h1> <nav> <a href="/index">a1</a> <a href="/about">a2</a> </nav> <br /> </header> ReactDOM.render( header, document.querySelector("#root"), ()=>{ console.log("构建完成") } ); </script> </body>
- 注意点:jsx的标签全部是小写的
- 注意点:jsx只接收一个顶层元素标签
- 注意点:在html中的class在jsx中要写为className
- 注意点:jsx支持插值表达式 {} ,可以配合js的表达式一起使用
- 注意点:在jsx中在标签上书写行间样式的话style={{width:20}}是这么书写的
- 注意点:jsx只能有一个顶层元素标签,可以通过<></>空标签或者Fragment来解决
- 注意点:JSX expressions must have one parent element.
- 注意点:可以用大括号来加入JavaScript表达式。遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。
- 注意点:在react中通常约定组件类的第一个字母必须大写,XML标签都是小写
- 注意点:它并不是字符串 ,不要带上``,如果带上会默认为字符串,于是全部全部转义后渲染
- 它也不是HTML,所以很多写法与HTML有出入,例如 class 要写为 className、XML的标签全部必须要闭合 </> 、JSX支持插值表达式
- 它可以配合JavaScript 表达式一起使用
JavaScript有以下表达式类型: 1.变量 2.算术运算 || && ?: ❗ 3.函数调用后有合法的运算结果的 (fuunction(){return '1'})() 4.string | number 5.bollean | null | undefined 6.数组 7.对象 if、for、while 这些都是语句,JSX 不支持语句
JSX JavaScript for XML
引入三个库
<script src="js/react.js"></script> <script src="js/react-dom.js"></script> <script src="js/babel.js"></script>
在 JXS 中可以使用 {表达式} 嵌入表达式
表达式是一组代码的集合,它返回一个值。
表达式:产生值的一组代码的集合,有运行结果的一段程序
在{表达式}里使用表达式
-
变量
<body>
<div id="root"></div>
<script type="text/babel">
const data={
title:'欢迎来到react的世界',
subTitle:'欢迎来到react的世界'
}
let header = <header className="main" >
<h1 id="logo">{data.title}</h1>
<nav>
<a href="/index">{data.subTitle}</a><br/>
<a href="/about">常量值:{1+1}</a><br/>
</nav>
<br />
</header>
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
-
算术运算
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className="main" >
<h1 id="logo">{1==1 && (1+3)}</h1>
<a href="/about">&&运算:{true && 2}</a>返回值2<br/>
<a href="/about">||运算:{false || 222}</a>返回值222<br/>
<br />
</header>
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
-
函数调用后有运算结果的
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className="main" >
<a href="/about">函数没调用的话整体被忽略:{function(){console.log('1')}}</a><br/>
<a href="/about">函数调用后的返回值合法就可以呈现:{(function(){return 1})()}</a><br/>
<br />
</header>
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
-
是一个ReactElement
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className="main" >
<a href="/about">react element:{ <a href="/index">react element</a> }</a>有返回值<br/>
</header>
//1.其实这也是一个ReactElement
console.dir(header,'header'); //$$typeof: Symbol(react.element)
//2.{ <a href="/index">react element</a> } 是可以这么做的
//接收的是一个基于React构建的元素节点 狭义上的ReactElement
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className="main" >
<a href="/about">react element:{ <a href="/index">react element</a> }</a>有返回值
</header>
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
-
string | number 会原样输出
-
bollean | null | undefined 都没有返回值 全部空
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className="main" >
<a href="/about">null:{false || null}</a>无返回值<br/>
<a href="/about">null:{ null }</a>无返回值<br/>
<a href="/about">undefined:{ undefined }</a>无返回值<br/>
<a href="/about">for语句不行:{ for(let i=0;i<10;i++){console.log(i)} }</a>无返回值<br/>
</nav>
<br />
</header>
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成)
}
);
</script>
</body>
-
数组 数组会自动去掉连接符号进行输出
数组会自动去掉连接符号进行输出 有几位就输出为几个子节点
arr中一定不要写成字串 写成字符串是另一种效果
const arr=[
<div>hello arr1</div>,
<div>hello arr2</div>
]
<a href="/about">数组:{ arr }</a><br/>
被渲染为
<a href="/about">数组:<div>hello arr1</div><div>hello arr2</div></a>
-----------------------------------------
注意点: arr中一定不要写成字串 写成字符串是另一种效果
即
const arr1=[
'<div>hello arr1</div>',
'<div>hello arr2</div>'
]
<a href="/about">数组:{ arr1 }</a><br/>
被渲染为 全部给你转义了
<a href="/about">数组:<div>hello arr1</div><div>hello arr2</div></a>
-
对象 对象是不能直接输出的
const obj={
title:'欢迎来到react的世界',
subTitle:'欢迎来到react的世界'
}
const obj1={
title:<div>欢迎来到react的世界</div>,
subTitle:<div>'欢迎来到react的世界'</div>
}
对象配合数组使用
<a href="/about">对象是不能直接输出的:{ obj }</a>这样报错<br/>
<a href="/about">对象:{ Object.keys(obj).map(item=>{return obj[item]}) }</a><br/>
<a href="/about">对象:{ Object.keys(obj1).map(item=>{return obj1[item]}) }</a><br/>
被渲染为
<a href="/about">对象:欢迎来到react的世界欢迎来到react的世界</a>
-----------
<a href="/about">对象:<div>欢迎来到react的世界</div><div>'欢迎来到react的世界'</div></a>
-
JSX的特殊属性 ---> 行间样式:style
style
<body>
<div id="root"></div>
<script type="text/babel">
const data={
title:'欢迎来到react的世界',
subTitle:'欢迎来到react的世界'
}
const style={
width:500,
fontSize:100
}
let header = <header
className={'main-' + 'box'}
>
<h1 id="logo" style={style}>{data.title}</h1>
<nav>
</nav>
<br />
</header>
console.dir(header,'header'); //$$typeof: Symbol(react.element)
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
简写为 外面是插值表达式 里面是一个对象 记住是针对style属性特有的 支持对象
<h1 id="logo" style={{width:500,fontSize:100}}>{data.title}</h1>
-
在元素的属性中使用插值表达式
1.元素的属性中也可以使用插值表达式
<body>
<div id="root"></div>
<script type="text/babel">
let header = <header className={'main'}>
<br />
</header>
console.dir(header,'header'); //$$typeof: Symbol(react.element)
ReactDOM.render(
header,
document.querySelector("#root"),
()=>{
console.log("构建完成")
}
);
</script>
</body>
被渲染为<header class="main"><br></header>
2.在属性上使用表达式 当在属性中使用 {} 的时候,不要使用引号包含
let header = <header className={'main-' + 'box'}>
<br />
</header>
被渲染为<header class="main-box"></header>
-
注释
注释
{/*注释*/}
{/*
多行注释
*/}
总结各种类型内容在插值中的使用
- 注释
- 输出数据类型
- 字符串、数字:原样输出
- 布尔值、空、未定义 会被忽略
- 列表渲染
- 数组
- 对象
- 扩展:虚拟 DOM (virtualDOM) 和 diff
- 条件渲染
- 三元运算符
- 与或运算符
- 在属性上使用表达式
- JSX 中的表达式也可以使用在属性上,但是使用的时候需要注意
- 当在属性中使用 {} 的时候,不要使用引号包含
- JSX 使用注意事项
- 必须有且只有一个顶层的包含元素 - 除非使用React.Fragment或者空标签<></>
- JSX 不是html,很多属性在编写时不一样
- className
- 标签行间样式 style
- 列表渲染时,必须有 key 值
- 在 jsx 所有标签必须闭合
- 组件的首字母一定大写,标签一定要小写
- XSS:为了有效的防止 XSS 注入攻击,React DOM 会在渲染的时候把内容(字符串)进行转义,所以字符串形式的标签是不会作为 HTML 标签进行处理的
基于自动化的集成环境模式 create-react-app - 脚手架 简称cra
介绍
通过前面 script 的方式虽然也能完成 React.js 的开发,但是有一个现在前端很重要的特性 - 模块化,无法使用。
Create React App 是一个使用 Node.js 编写的命令行工具,通过它可以帮助我们快速生成 React.js 项目,并内置了 Babel、Webpack 等工具帮助我们实现 ES6+ 解析、模块化解析打包,也就是通过它,我们可以使用 模块化 以及 ES6+ 等更新的一些特性。同时它还内置 ESLint 语法检测工具、Jest 单元测试工具。还有一个基于 Node.js 的 WebServer 帮助我们更好的在本地预览应用,其实还有更多。
这些都通过 Create React App(CRA) 帮助我们安装并配置好了,开箱即用
安装与使用
通过 npm、yarn、npx 都可以
安装:
npm
npm i -g create-react-app
yarn
yarn global add create-react-app
使用:安装完成以后,即可使用 create-react-app 命令
create-react-app <项目名称>
npx create-react-app <项目名称>
项目目录结构说明
运行命令以后,就会在运行命令所在目录下面创建一个以项目名称为名的目录
my-app/
README.md
node_modules/
package.json
public/
index.html 根节点 默认是#root
favicon.ico
src/
App.css
App.js
App.test.js
index.css
index.js 项目的入口文件 通常从这里起书写代码
logo.svg
命令脚本
1.npm run start
启动一个内置的本地 WebServer,根目录映射到 './public' 目录,默认端口:3000
2.npm run test
运行 Jest 测试
3.npm run build
打包应用(准备上线)
4. npm run eject 该命令慎用
将webpack配置暴露出来 是不可逆的操作
5.react-scripts 中内置了webpack功能等配置
6.web-vitals 用于性能监测
通过create-react-app启动项目
实践一:在"react": "^17.0.1"版本及之后中直接书写JSX语法
/**
* 版本区别 JSX-runtime
*
* 在"react": "^17.0.1"版本及之后中直接书写JSX语法
* React能够直接将其解析虚拟DOM
* 不需要通过React.createElement来创建虚拟DOM
*/
//在17之前的版本必须通过引入react库来将JSX语法转为虚拟DOM
//在17以及之后的版本无需通过react库来将JSX语法转为虚拟DOM,可以自动转为虚拟DOM
//在这里我们还是引入了react库 虽然当前的版本是"react": "^17.0.1"
import React from 'react';
import ReactDOM from 'react-dom';
// 项目入口文件 file:src/index.js
// 如何打包以及如何将打包后的文件运行在服务器端??
//最终被渲染为<a href="/about">hello world</a>
const data={
title:'hello',
subTitle:'world'
}
//17以及之后的版本可以直接在页面上书写JSX语法
//会被直接编译为虚拟DOM
let header =
<div className="header div" id="header">
<h1 id="logo" style={{
width:50,
height:50,
fontSize:10,
backgroundColor:'red'
}}>开课吧</h1>
<nav>
<a href="/index">a1</a>
<a href="/about">{data.title + ' '+ data.subTitle}</a>
<a href="/about">a2</a>
</nav>
<br />
<input type="text" ></input>
</div>
console.log(header);
//$$typeof: Symbol(react.element) 直接被编译成虚拟DOM
//file:public/index.html的默认根节点是#root
ReactDOM.render(header,document.querySelector('#root'))
实际二:一个项目中只会运行src目录下的文件 其他目录下不参与运行
import React from 'react';
import ReactDOM from 'react-dom';
/**
* 条件输出 react只关心视图构建
*
* 但是可以使用下方语法来做到
* || 或
* && 与
* ? : 三目运算符
* 函数调用后返回的合法值 (function(i){return i})(1)
*/
console.log('hello world');
let header =
<div className="header div" id="header">
<nav>
<a href="/about">||的使用:{ false || 2}</a><br/>
<a href="/about">&&的使用:{ false && 2}</a><br/>
<a href="/about">&&的使用:{ 3 && 2}</a><br/>
<a href="/about">三目的使用:{ true ? 2: 0}</a><br/>
<a href="/about">函数的使用必须有返回一个合法值:{ (function(i){return i ;})(2)}</a><br/>
</nav>
<br />
<input type="text" ></input>
</div>
//虚拟DOM
console.log(header); //$$typeof: Symbol(react.element)
ReactDOM.render(header,document.querySelector('#root'))
实践三:使用{表达式}实现列表输出渲染
import React from 'react';
import ReactDOM from 'react-dom';
console.log('hello world');
//数组中有几位就渲染为几位子节点
//这里是被渲染为三个子节点
// const arr=[
// <div>1</div>,
// <div>2</div>
// ]
//被渲染为<a href="/about">列表输出:列表-1列表-2列表-3</a>
const data1=[
'列表-1',
'列表-2',
'列表-3',
]
// const list =<ul>
// {<li>{data1}</li>}
// </ul>
//列表输出就是根据原有数据映射为一个数组
const dataArr=[
<li>item1</li>,
<li>item2</li>,
<li>item3</li>
]
const newData=data1.map(item=>{
return <li>{item}</li>
})
console.dir(newData); //每一项:$$typeof: Symbol(react.element)
const list =<ul>
{newData}
</ul>
console.log(list); //$$typeof: Symbol(react.element)
ReactDOM.render(list,document.querySelector('#root'))
实践四:对象要怎么使用{}
通常情况下 对象不能像 {对象} 这样来使用
可以转换为数组的形式
import React from 'react';
import ReactDOM from 'react-dom';
/**
* 对象
根据原有数据映射成数组
列表输出时每一项必须有key值
*/
console.log('hello world');
const data={
a:{
title:'列表一'
},
b:{
title:'列表二'
},
c:{
title:'列表三'
}
}
console.log(Object.keys(data));
//data[item]是个对象 对象不能用在{}中
const newData=Object.keys(data).map((item,key)=><li key={key}>{data[item].title}</li>)
const list =<ul>
{newData}
</ul>
console.log(list); //$$typeof: Symbol(react.element)
ReactDOM.render(list,document.querySelector('#root'))
总结实践:
-
jsx不是html
-
jsx中不是字符串
-
jsx最终会被解析成一个虚拟DOM 也就是说 jsx会被解析为一个对象值
-
jsx必须有一个且只有一个顶层父级
-
但是可以借助Fragment 它最终不会被渲染为一个真正的DOM Fragment 是包含容器 另一种解决方法 17版本及之后可以使用 <></> 空标记来作为顶层父级 而且这个空标记 不需要 额外去引入 import React,{Fragment} from 'react'; import ReactDOM from 'react-dom'; console.log('hello world'); const data={ a:{ title:'列表一' } } const newData=Object.keys(data).map((item,key)=><li key={key}>{data[item].title}</li>) const list =<Fragment><ul> {newData} </ul> <div>现在可以有多个父级了 Fragment标签不会被渲染为一个真正的DOM</div> </Fragment> console.log(list); //$$typeof: Symbol(react.element) ReactDOM.render(list,document.querySelector('#root'))
-
-
jsx中区分大小写 标签名要全部小写 组件名字首字母大写
-
列表输出时必须添加key值
组件的概念
对具有一定独立功能的数据与方法的封装,对外暴露接口,有利于代码功能的复用,且不用担心冲突问题。
类式组件
- 组件类必须继承 React.Component
- 组件类必须有 render 方法
file: app.js
import React,{Component} from 'react';
class App extends Component{
render(){
return <h1>hello world</h1>
}
}
export default App
-------------------------------------------
file: index.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import App from './app';
/**
* 组件
*
* 根据视图拆分为各个组件
* 每一个组件都有封闭的数据等等
*
* 类组件:
* - 组件类必须继承 **React.Component**
* - 组件类必须有 **render** 方法
* --render的返回值是该组件要构建的视图(虚拟DOM)
*/
console.log('hello world');
//组件实例对象 虚拟DOM
console.log(App,'APP');
ReactDOM.render(<App/>,document.querySelector('#root'))
函数式组件
- 函数的名称就是组件的名称
- 函数的返回值就是组件要渲染的内容
props 和 state
-
props 父组件传递过来的参数
-
state 组件自身状态
-
state组件状态: 当组件状态有修改时,会对组件进行更新,从而实现组件的视图更新 修改组件状态: 要通过调用组件的setState方法来完成 -
setState:修改组件状态
-
setState方法怎么使用??? /* 1.调用setState方法 传入newState 传入希望更新的值 setState(newState) 异步的 完成组件更新 原理:调用setState之后,会调用render生成新的VDOM完成组件更新 */ import React,{Component} from 'react'; class App extends Component{ state={ //组件自身状态 类似vue中的data属性 count:1 //当希望通过数据更新视图的时候可以添加使用状态 } handleClick=()=>{ //1.先获取count let {count} =this.state // console.log(this,'指向App组件实例'); // 2.接收一个对象 this.setState({ count:count+1 }) } render(){ const {count}=this.state return <h1>hello world <p>{count}</p> <button onClick={this.handleClick}>递增</button> </h1> } } export default App
-
-
多个 setState 合并
-
-
props 与 state 的区别
-
state 的主要作用是用于组件保存、控制、修改自己的可变状态,在组件内部进行初始化,也可以在组件内部进行修改,但是组件外部不能修改组件的 state
-
props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件,它是外部传进来的配置参数,组件内部无法控制也无法修改
-
state 和 props 都可以决定组件的外观和显示状态。通常,props 做为不变数据或者初始化数据传递给组件,可变状态使用 state
-
使用事件时this的指向问题
- 类在实例化的时候一定会执行constructor
- new的过程不需要我们去书写 react会自动帮我们去new这个App实例
- 组件在每次实例化的时候才会去调用constructor
- class 语法 class App extends Component
- 注意:事件名on之后 每个单词首字母大写
演示使用事件时this的指向问题:this指向undefined而不是该组件实例
import React,{Component} from 'react'; // class App extends Component{ // state={ //组件自身状态 类似vue中的data属性 // count:1 //当希望通过数据更新视图的时候可以添加使用状态 // } // render(){ // const {count}=this.state // return <h1>hello world // <p>{count}</p> // <button onClick={function(){console.dir(this,'指向undefined')}}>递增</button> // </h1> // } // } export default App解决方法一:使用箭头函数
import React,{Component} from 'react'; // class App extends Component{ // state={ //组件自身状态 类似vue中的data属性 // count:1 //当希望通过数据更新视图的时候可以添加使用状态 // } // render(){ // const {count}=this.state // return <h1>hello world // <p>{count}</p> // <button onClick={()=>{ // console.dir(this,'指向App') // }}>递增</button> // </h1> // } // } export default App版本二:单独把函数抽离出来 // class App extends Component{ // state={ //组件自身状态 类似vue中的data属性 // count:1 //当希望通过数据更新视图的时候可以添加使用状态 // } // handleClick=()=>{ // console.log(this,'指向App组件实例'); // } // render(){ // const {count}=this.state // return <h1>hello world // <p>{count}</p> // <button onClick={this.handleClick}>递增</button> // </h1> // } // }解决方法二:使用bind重绑this指向
import React,{Component} from 'react'; class App extends Component{ //可以将state写在构造函数中 // state={ //组件自身状态 类似vue中的data属性 // count:1 //当希望通过数据更新视图的时候可以添加使用状态 // } //绑定this一般在构造函数中完成 constructor(props){ //一定要 继承至父类的构造函数 //且要一定要接收 props super(props) this.state={ count:1 } //在构造函数中进行this的硬绑定 //最方便的写法是用箭头函数 this.handleClick=this.handleClick.bind(this) } //写在render中的bind绑定 因为在每次更新视图时会重新触发render函数 //所以会导致每一次都会重新绑定一次this指向!! //不推荐:<button onClick={this.handleClick.bind(this)}>递增</button> handleClick=function(){console.log(this)} render(){ const {count}=this.state return <h1>hello world <p>{count}</p> <button onClick={this.handleClick}>递增</button> </h1> } } export default App
案例演示一
第一步:构建静态视图 模板+样式
- 分析数据
let rootdata = {
React:["Component","Hooks","state&props"],
Router:["Browsers","Hash","NavLink"],
Redux:["reducer","action","dispatch"]
};
export default rootdata;
- 使用数据构造视图
import React,{Component} from 'react';
//组件
import Menu from './menu';
//数据
import rootdata from './data';
//最终版本:
class App extends Component{
render(){
// const {count}=this.state
// 为了构造[<Menu/>,<Menu/>,<Menu/> ]
// <Menu title={item} data={rootdata[item]}/>来传递props给子组件
return <ul id="menu">
{Object.keys(rootdata).map((item,index)=>{
return <Menu
key={index}
title={item}
data={rootdata[item]}
/>
})}
</ul>
}
}
//版本二:
// class App extends Component{
// render(){
// // const {count}=this.state
// return <ul id="menu">
// <Menu></Menu>
// <Menu></Menu>
// <Menu></Menu>
// </ul>
// }
// }
//版本一:
// class App extends Component{
// render(){
// // const {count}=this.state
// return <ul id="menu">
// {Object.keys(rootdata).map((item,index)=>{
// console.log(item,'item');
// console.log(rootdata[item],'子项');
// return <Menu
// key={index}
// title={item}
// data={rootdata[item]}
// />
// })}
// </ul>
// }
// }
export default App
第二步:拆分组件 有三个调用数组生成三个组件
- 实际工作中有几项数据就生成几个
- 怎么在父级中传递给子项 props
- 父组件调用子组件时 可以将数据添加在子组件的属性上
- 在子组件中可以通过props属性接收父级传递的数据
import { Component } from "react";
//版本二:
class Menu extends Component{
state={
show:false
}
render(){
const {title,data}=this.props;
const {show}=this.state
console.log(title,data,'title');
return <li className={show ? 'subList-show' :''}>
<a onClick={()=>{
this.setState({
show:!show
})
}}>{title}</a>
<ul className="subList">
{data.map((item,index)=><li key={index}>{item}</li>)}
</ul>
</li>
}
}
// 版本一:
// class Menu extends Component{
// render(){
// const {title,data}=this.props;
// console.log(title,data,'title');
// return <li className='subList-show'>
// <a>React</a>
// <ul className="subList">
// <li>Component</li>
// <li>Hooks</li>
// <li>state&props</li>
// </ul>
// </li>
// }
// }
export default Menu;
样式文件:
body {
margin: 0;
background: #f3f3f3;
}
ul {
margin: 0;
padding: 0;
list-style: none;
}
#menu {
margin: 50px auto;
display: flex;
width: 360px;
height: 40px;
border: 1px solid #000;
border-left:none;
background: #fff;
}
#menu>li {
position: relative;
width: 119px;
border-left: 1px solid #000;
}
#menu>li:after {
content: ">";
position: absolute;
left: 10px;
top: 13px;
font: 14px/1 "宋体";
}
#menu a {
display: block;
font: 14px/40px "宋体";
text-align: center;
}
.subList {
display: none;
position: absolute;
left: -1px;
top: 30px;
width: 109px;
padding: 5px;
background: #fff;
border: 1px solid #000;
border-top: none;
}
.subList li {
font: 12px/30px "宋体";
text-indent: 20px;
border-bottom: 1px solid #ccc;
}
#menu .subList-show .subList{
display: block;
}
#menu .subList-show:after {
transform: rotate(90deg);
}
模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link href="css/index.css" rel="stylesheet" />
</head>
<body>
<ul id="menu">
<li>
<a>React</a>
<ul class="subList">
<li>Component</li>
<li>Hooks</li>
<li>state&props</li>
</ul>
</li>
<li class="subList-show">
<a>Router</a>
<ul class="subList">
<li>Browsers</li>
<li>Hash</li>
<li>NavLink</li>
</ul>
</li>
<li>
<a>Redux</a>
<ul class="subList">
<li>reducer</li>
<li>action</li>
<li>dispatch</li>
</ul>
</li>
</ul>
</body>
</html>

浙公网安备 33010602011771号