一:见:react 一
二
jsx 更多写法
cnpm install --save react babel-standalone react-dom 运算操作( js学到的所有运算符 )同样可以进行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let a=1;
let b=2;
let bool=false;
let el=(
<div>
<h1>{a+b}</h1>
<h1>{bool?"你好":"你坏"}</h1>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
属性插变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let ahref="http://www.baidu.com"
let atext="点我去百度"
let el=(
<div>
<h1>属性插变量</h1>
{}
<a href={ahref}>{atext}</a>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
行内样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let el=(
<div>
<h1>行内样式的设置</h1>
{}
<h1 style={{color:"red",backgroundColor:"pink"}}>设置我的样式</h1>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
类名设置 设置样式的时候 使用类名来进行样式的设置
传统的时候设置类名使用的html属性是 class属性
在react中如设置类名时 , 必须使用className来设置(原因是因为class是es6类的关键字)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<style>
.demoh{
color:yellow;
background-color: blueviolet;
}
</style>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let el=(
<div>
<h1 className="demoh">我想使用类样式设置我的样子</h1>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
jsx总结扩展
1.style行内样式 使用对象来描述 所以有两个{{}}
2.类样式 不能使用class 而是要使用className
3.html中有一个value的属性 需要写成 defaultValue
4.html中有一个checked的属性 需要写成 defaultChecked
react 列表遍历数组(遍历展示)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let arr=[111,2222,3333,4444,5555,66666]
let el=(
<div>
<ul>
{
arr.map((v,i)=>{
return (
<li key={i}>{v}</li>
)
})
}
</ul>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
遍历数组对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let obj=[
{name:"xixi1",age:171},
{name:"xixi2",age:172},
{name:"xixi3",age:173},
{name:"xixi4",age:174},
{name:"xixi5",age:175},
{name:"xixi7",age:176}
]
let newel=obj.map((v,i)=>{
return (
<tr key={i}>
<td>{v.name}</td>
<td>{v.age}</td>
</tr>
)
})
let el=(
<div>
<table border="1">
<tbody>
{newel}
</tbody>
</table>
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
除了map方式还有什么方式可以进行循环便利??
react 列表便利对象
知识点回顾
对象转成数组
object.Keys() 返回一个数组 数组的内容就转换对象的key
object.Values() 返回一个数组 数组的内容就转换对象的value
object.entrise()返回一个数组 数组的内容就转换对象的key与value 他是一个二维数组
let obj={name:"xixi",age:18};
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));
对象怎么取值
let newage="age"
console.log(obj[newage]);
便利对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let obj={name:"xixi",age:18,sex:"nan"};
let newel=Object.keys(obj).map((v,i)=>{
return (
<h1 key={i}>{obj[v]}</h1>
)
})
let el=(
<div>
{newel}
</div>
)
ReactDOM.render(el,document.getElementById("demodiv"))
</script>
</body>
</html>
因为我们便利出来的v是一个变量但是在对象取值的方式中打点不能取变量所以要用另外一种取值方式 [ ]
组件
无状态组件/函数组件/工厂函数组件
首先是一个函数 但是函数的首字母必须大写首字母必须大写首字母必须大写首字母必须大写 里面return一段你当前组件的jsx
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
function Mycom(){
return (
<div>
<h1>我是一个函数组件1</h1>
<h1>我是一个函数组件2</h1>
<h1>我是一个函数组件3</h1>
</div>
)
}
function Fu(){
return (
<div>
<Mycom/>
<Mycom/>
<Mycom/>
<Mycom/>
<Mycom/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props传值
props是当前组件对外的一个接口,可以方便从组件外部向组件内部传递参数数据 props是只读,peops是不能修改的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
function Mycom(props){
return (
<div>
<h1>我是一个函数组件1----{props.title}</h1>
<h1>我是一个函数组件2----{props.age}</h1>
<h1>我是一个函数组件3</h1>
</div>
)
}
function Fu(){
return (
<div>
<Mycom age="我是传递的age" title="我是传递的title"/>
<Mycom/>
<Mycom/>
<Mycom/>
<Mycom/>
</div>
)
}
</script>
</body>
</html>
使用es6新语法来完成传值,props是一个对象 可以使用对象解构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
function Mycom(props){
let {title,age,sex}=props;
return (
<div>
<h1>我是一个函数组件1----{title}</h1>
<h1>我是一个函数组件2----{age}</h1>
<h1>我是一个函数组件3----{sex}</h1>
</div>
)
}
let obj={
title:"新的title",
age:999,
sex:"男"
}
function Fu(){
return (
<div>
<Mycom {...obj}/>
<Mycom/>
<Mycom/>
<Mycom/>
<Mycom/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props验证
在react15.5之前 props验证使用的是react核心库中带的 propTypes来进行
在react15.5之后 props验证移植到了一个propTypes库中
使用 下载:
npm install --save prop-types
使用的时候注意单词大小写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<script src="node_modules/prop-types/prop-types.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
function Mycom(props){
let {title}=props
return (
<div>
<h1>我是一个函数组件1---{title}</h1>
</div>
)
}
Mycom.propTypes={
title:PropTypes.number
}
let obj={
title:"1234"
}
function Fu(){
return (
<div>
<Mycom {...obj}/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props默认值
defaultProps 来是先props的默认值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
function Mycom(props){
return (
<div>
<h1>我是一个函数组件1--{props.title}</h1>
</div>
)
}
Mycom.defaultProps={
title:"我是title的默认值么么哒"
}
function Fu(){
return (
<div>
<Mycom title="我是传递的值"/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
类组件
基本的创建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
return (
<div>
我是一个类组件
</div>
)
}
}
class Fu extends React.Component{
render(){
return (
<div>
<Mycom/><Mycom/><Mycom/><Mycom/><Mycom/><Mycom/>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props 传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
let {title,age,sex}=this.props
return (
<div>
我是一个类组件---{title}
我是一个类组件---{age}
我是一个类组件---{sex}
</div>
)
}
}
class Fu extends React.Component{
render(){
let obj={
title:"tttt1",
age:6666,
sex:"naan"
}
return (
<div>
<Mycom {...obj}/>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props验证
同上面
props默认值
同上面
组件整理
组件分为函数组件与类组件
他们两者在使用的时候语法有区别
props
函数组件是吧props当成一个函数的形参来进行接收 使用的时候直接用props这个形参.xxxxx
类组件简单一些 想在那用 直接在哪里this.props.xxxx 来直接使用
三
state 状态机
在react之前的内容中 我们如果修改了数据中的内容 那么页面会跟着改变吗?
不会改变
state 基本概念
在react中我们只需要关心数据,数据改变我们需要让页面跟着改变,所以就需要使用到state状态机制(状态等同于数据变量)状态改变了,那么react就会着视图自动发生变化。
state使用
首选函数组件不能使用state,因为函数组件是无状态组件
类组件
创建使用:this.state={} 读取使用:this.state.XXX 修改必须用 this.setState()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
constructor(props){
super(props)
this.state={
text:"我是state的变量数据",
arr:[1111,222,333]
}
}
fun=()=>{
this.setState({
text:"我变了"
})
}
render(){
return (
<div>
<h1>state使用</h1>
{}
<h1>{this.state.text}</h1>
{}
<button onClick={this.fun}>点我修改</button>
</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
</script>
</body>
</html>
setState()
setState的作用就是用来更新state数据的
特点
setState()是异步的 并且会自动触发render重新渲染
setState 是异步的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
constructor(props){
super(props)
this.state={
num:6666
}
}
fun=()=>{
this.setState({
num:9527
})
console.log(this.state.num);
}
render(){
return (
<div>
<h1>setState是异步的</h1>
<h1>{this.state.num}</h1>
<button onClick={this.fun}>点我修改</button>
</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
</script>
</body>
</html>
setstate 的回调
setState第二个参数是一个回调函数
this.setState({
num:999
},()=>{
console.log("我会在setState这个异步操作执行完毕后 自动被调用"+this.state.num)
})
state的联系,视图跟着模型变
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
constructor(props){
super(props)
this.state={
inputval:""
}
}
fun=(e)=>{
this.setState({
inputval:e.target.value
})
}
render(){
return (
<div>
<h1>state小练习</h1>
<input type="text" onInput={this.fun}/>
<br/>
<h1>输入框的内容是------{this.state.inputval}</h1>
</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
</script>
</body>
</html>
扩展----插入字符串html标签
dangerouslySetInnerHTML={{__html(双底杠):你要渲染的变量l}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Fu extends React.Component{
constructor(props){
super(props)
this.state={
newhtml:"<h1>我是一个h1</h1>"
}
}
render(){
return (
<div>
<div>{this.state.newhtml}</div>
<div dangerouslySetInnerHTML={{__html:this.state.newhtml}}></div>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
ref 转发
ref 就是标识组件内部的元素内容 (给组件中的dom起个名字)
react中由于无状态组件/函数组件没有实例 所以不能使用ref
创建ref
React.createRef()
react16.3新增的 当前方法也是通过ref属性进行挂载 但是在找寻当前dom的时候要使用current来进行dom的选取
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Fu extends React.Component{
constructor(props){
super(props)
this.state={
}
this.demoref=React.createRef()
}
fun=()=>{
this.demoref.current.style.color="yellow"
}
render(){
return (
<div>
{}
<h1 ref={this.demoref}>我是createref的方式</h1>
<button onClick={this.fun}>点我修改他的颜色</button>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
回调函数方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Fu extends React.Component{
constructor(props){
super(props)
this.state={
}
}
funa=()=>{
this.refs.demoh.style.color="pink"
}
funb=()=>{
this.refh.style.color="red";
}
render(){
return (
<div>
{}
<h1 ref="demoh">我是ref字符串方式</h1>
<button onClick={this.funa}>点我修改他的颜色</button>
{}
<h1 ref={(demohb)=>{this.refh=demohb}}>我是ref回调函数方式</h1>
<button onClick={this.funb}>点我修改他的颜色</button>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
字符串方式
不推荐
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Fu extends React.Component{
constructor(props){
super(props)
this.state={
}
}
funa=()=>{
this.refs.demoh.style.color="pink"
}
render(){
return (
<div>
{}
<h1 ref="demoh">我是ref字符串方式</h1>
<button onClick={this.funa}>点我修改他的颜色</button>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
事件处理
react如果想要绑定事件 使用小驼峰命名法。 在函数调用的时候不加 (),加了()函数就会自动执行
事件修饰
阻止事件默认行为 preventDefault()
react 中阻止事件默认行为 阻止事件传播 都是js原生的语法
函数实参传递
在react中调用函数不加()但是不加了 那么实参写在哪?
方式: 1.通过bind()进行传递实参
<button onClick={this.funa.bind(this,"参数1","参数2")}>我是bind传递方式</button>
接收:
funa=(numa,numb)=>{
console.log(numa + "----" + numb);
}
2.通过箭头函数调用函数传参
<button onClick={()=>{this.funb("参数666")}}>我是箭头函数调用函数的方式</button>
funb=(num)=>{
console.log(num)
}
this指向修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Fu extends React.Component{
constructor(props){
super(props)
this.state={
num:"我是state的变量"
}
this.func=this.func.bind(this)
}
fun=function(){
console.log(this.state.num);
}
funa=function(){
console.log(this.state.num);
}
funb=function(){
console.log(this.state.num);
}
func=function(){
console.log(this.state.num);
}
render(){
return (
<div>
<h1>this指向</h1>
<button onClick={this.fun}>点我看错误的写法</button>
<br/>
<button onClick={this.funa.bind(this)}>点我看bind绑定的写法</button>
<br/>
<button onClick={()=>{console.log(this.state.num)}}>事件直接调用箭头函数</button>
<br/>
<button onClick={()=>{this.funb()}}>用箭头函数调用函数</button>
<br/>
<button onClick={this.func}>在constructor中提前bind绑定</button>
</div>
)
}
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
以上每一个方式的详细 1.在创建函数的时候使用箭头函数
2.通过bind绑定
<button onClick={this.funa.bind(this)}>点我看bind绑定的写法</button>
funa=function(){
console.log(this.state.num);
}
3.事件直接调用箭头函数
<button onClick={()=>{console.log(this.state.num)}}>事件直接调用箭头函数</button>
4,使用箭头函数调用函数
<button onClick={()=>{this.funb()}}>用箭头函数调用函数</button>
5,.在constructor中提前使用bind绑定
constructor(props){
super(props)
this.state={
num:"我是state的变量"
}
this.func=this.func.bind(this)
}
ToDolist的添加删除修改
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
constructor(props){
super(props)
this.state={
arr:[
"ez",
"MF",
"NOC",
"vn"
]
}
this.inputval=React.createRef()
}
showel=()=>{
return this.state.arr.map((v,i)=>{
return (
<li key={i}>{v}------- <span onClick={()=>{this.del(i)}} style={{color:"red"}}>x</span><button onClick={this.update.bind(this,i)}>点我修改</button></li>
)
})
}
update=function(i){
let upinput=prompt("请您输入修改的内容")
if(upinput==null){
alert("您放弃了修改")
}else{
let newarr=this.state.arr
newarr[i]=upinput
this.setState({
arr:newarr
})
}
}
add=()=>{
console.log(this.inputval.current.value)
let newarr=this.state.arr
newarr.push(this.inputval.current.value)
this.setState({
arr:newarr
})
this.inputval.current.value=""
}
del=(i)=>{
if(window.confirm("是否删除吗?"+i)){
console.log("用户点击了确定")
let newarr=this.state.arr
newarr.splice(i,1)
this.setState({
arr:newarr
})
}else{
console.log("用户点击了取消")
}
}
render(){
return (
<div>
<input type="text" ref={this.inputval}/>
<button onClick={this.add}>添加</button>
<ul>
{this.showel()}
</ul>
</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
</script>
</body>
</html>
</script>
</body>
</html>
四 脚手架
create-react-app CRA
cra 是facebook官方出品
创建
1.全局下载(除了你重装node了或者是重装系统了)
npm install -g create-react-app
2.查看版本 看看是否安装ok了 create-react-app --version
3.切换路径 需要把cmd的路径切换到你想下载项目的路径下 cd到指定路径下
4 创建项目 create-react-app 项目名
5启动 npm start
组件创建
在components下 rcc创建出组件 在需要展示的地方引用使用
props
同本地模式
props.children
this.props.children 代表的就是当前组件的所有子节点
import React, { Component,Fragment } from 'react'
export default class userzi extends Component {
render() {
return (
<Fragment>
<h1>我是userzi1</h1>
<h1>我是userzi2</h1>
{this.props.children}
<h1>我是userzi3</h1>
<h1>我是userzi4</h1>
</Fragment>
)
}
}
this.props.children值有三种可能
1.如果当前没有插入子节点 他就是 undefined
2.只插入了一个子节点 他就是 object
3.插入了多个子节点 他就是 array
state
同本地模式
事件与this
同本地模式
扩展—空标签
因为在jsx中要求多行标签必须有父节点包裹 但是这个时候可能就会出现很多冗余的没有代码
解决方式
空标签来完成
1 使用<></>来包裹
import React, { Component } from 'react'
export default class userzi extends Component {
render() {
return (
<>
<h1>我是userzi1</h1>
<h1>我是userzi2</h1>
<h1>我是userzi3</h1>
<h1>我是userzi4</h1>
</>
)
}
}
2 Fragment 来添加空标签
import React, { Component,Fragment } from 'react'
export default class userzi extends Component {
render() {
return (
<Fragment>
<h1>我是userzi1</h1>
<h1>我是userzi2</h1>
<h1>我是userzi3</h1>
<h1>我是userzi4</h1>
</Fragment>
)
}
}
组件样式怎么设置
注意类名的写法 className
引用使用 import “你的样式文件路径”
扩展----强制刷新
forceUpdate() 强制刷新 — 重新调用render进行渲染
import React, { Component } from 'react'
export default class demoa extends Component {
constructor(){
super()
this.text="你好"
}
fun=function(){
this.text="你坏"
this.forceUpdate()
console.log(this.text)
}
render() {
return (
<div>
<h1>强制刷新</h1>
{}
<h1>{this.text}</h1>
<button onClick={()=>{this.fun()}}>点我修改</button>
</div>
)
}
}
组件传值
正向传值
props
逆向传值
是通过事件调用一个父组件传递过来的函数,并在子组件中传入对应的实参,从而完成的逆向传值 父组件
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
fufun=(text)=>{
console.log(text)
}
render() {
return (
<div>
父组件
<Zi zifun={this.fufun}/>
</div>
)
}
}
子组件
import React, { Component } from 'react'
export default class zi extends Component {
render() {
return (
<div>
子组件
<button onClick={this.props.zifun.bind(this,"我是子组件的数据")}>点我逆向传值</button>
</div>
)
}
}
同胞传值 pubsub-js
下载: npm install --save pubsub-js
使用 在需要传递的组件之上,进行自定义事件的抛出 pubsub.pulish(“自定义事件名”,“你要传递的数据”)
import React, { Component } from 'react'
import PubSub from "pubsub-js"
export default class zia extends Component {
fun=()=>{
PubSub.publish("ziapao","我是zia的数据么么哒")
}
render() {
return (
<div>
zia
<button onClick={this.fun}>点我抛出自定义事件</button>
</div>
)
}
}
在需要接收的组件中使用 pubsub.subscribe(“你要监听的自定义事件”,(a你监听的事件名,b数据)=>{})
import React, { Component } from 'react'
import PubSub from "pubsub-js"
export default class zib extends Component {
componentDidMount() {
PubSub.subscribe("ziapao",(a,b)=>{
console.log(a);
console.log(b);
})
}
render() {
return (
<div>
zib
</div>
)
}
}
跨组件传值
因为react的组件传值是通过props向下一层层的传值 是单向传递的 从父组件中可以一层层的传给下面的子孙组件 但是一层层的传值后期维护分麻烦。
1.上下文对象 context
context可以很好的解决react中跨组件传值的复杂度,可以快速的进行组件与组件之间跨层级的传值
要使用context对象必须要通过一个createContext()方法来进行上下文对象的创建
创建出context对象之后会有两个属性方法帮助我们进行传值:
Provider对象 用来生产数据的 生产者
Consumer对象 用来使用数据的 消费者
使用
1.新建文件与文件夹来容纳上下文对象
2.创建一个组件 并且设置this.props.children
import React, { Component } from 'react'
export default class Mycontext extends Component {
render() {
return (
<div>
{}
{this.props.children}
</div>
)
}
}
3.在index.js中 让上下文对象变成所有组件的父组件
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/pubsub/fu.jsx';
import reportWebVitals from './reportWebVitals';
import Mycontext from "./context"
ReactDOM.render(
<Mycontext>
<Home />
</Mycontext>,
document.getElementById('root')
);
reportWebVitals();
4.开始创建上下文对象 与生产者和消费者
import React, { Component,createContext } from 'react'
let context=createContext()
let {Provider,Consumer}=context
class Mycontext extends Component {
render() {
return (
<div>
{}
<Provider value={9527}>
{}
{this.props.children}
</Provider>
</div>
)
}
}
export {Mycontext,Consumer}
5.需要修改之前的引用
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/pubsub/fu.jsx';
import reportWebVitals from './reportWebVitals';
import {Mycontext} from "./context"
ReactDOM.render(
<Mycontext>
<Home />
</Mycontext>,
document.getElementById('root')
);
reportWebVitals();
6.在你想用的组件上使用consumer来消费数据
import React, { Component } from 'react'
import Zia from "./zia.jsx"
import Zib from "./zib.jsx"
import {Consumer} from "../../context/index.js"
export default class fu extends Component {
render() {
return (
<div>
{}
<Consumer>
{
(value)=>{
return (
<h1>{value}</h1>
)
}
}
</Consumer>
<h1>同胞传值</h1>
<Zia/>
<Zib/>
</div>
)
}
}
2.redux
后续再说
五
条件渲染
就是根据指定的条件来进行指定的内容渲染
三元运算符
import React, { Component,Fragment } from 'react'
export default class demoa extends Component {
constructor(){
super()
this.state={
bool:false
}
}
fun=function(){
this.setState({
bool:!this.state.bool
})
}
render() {
return (
<Fragment>
<h1>条件渲染</h1>
<h2>三元运算符</h2>
<button onClick={this.fun.bind(this)}>点我切换显示</button>
{
this.state.bool? <p>你好</p>:<p>你坏</p>
}
</Fragment>
)
}
}
if方式
if这种条件渲染的方式不能写在jsx中
import React, { Component } from 'react'
export default class demob extends Component {
render() {
let newel;
if(false){
newel=<p>你好</p>
}else{
newel=<p>你坏</p>
}
return (
<React.Fragment>
<h1>条件渲染</h1>
{
newel
}
</React.Fragment>
)
}
}
逻辑与(&&)
import React, { Component } from 'react'
export default class democ extends Component {
render() {
return (
<div>
{}
{ false && <p>你好</p>}
</div>
)
}
}
高阶组件—HOC
在react中创建项目的时候 经常会有一些需求 就是一类功能需要被不同的组件使用,需要对一些代码进行复用,把一些特定的功能抽离并且封装起来,方便其它组件使用
HOC—参数是一个组件返回值还是一个组件
Hoc—也是react中组件重用的一个高阶技术 但是HOC不是reactAPI中的内容 而是在现有语法之上进行的一个升级
创建
import React, { Component } from 'react'
let hocdemo=(El)=>{
return class index extends Component {
render() {
return (
<div>
我是复用的内容么么哒
<El/>
</div>
)
}
}
}
export default hocdemo
使用
1,修改使用组件的,暴漏在最下面 2,引用高阶组件 3,在暴漏位置引用使用的Hoc(你的组件)
import React, { Component } from 'react'
import hoc from "../hoc/index.js"
class hocdemo extends Component {
render() {
return (
<div>
<h1>HOC高阶组件</h1>
</div>
)
}
}
export default hoc(hocdemo)
高阶组件HOC—反向继承
反向继承最核心的就是----渲染拦截(拦截了渲染可以让我们在高阶组件中进行条件渲染)
高阶组件的反向继承就是在高阶组件中进行条件渲染
import React, { Component } from 'react'
let hocb=(Hehe,num)=>{
return class indexb extends Hehe {
render() {
if(num>18){
return (
<Hehe></Hehe>
)
}else{
return (
<h1>未满18不能访问!!!!</h1>
)
}
}
}
}
export default hocb
import React, { Component } from 'react'
import hocb from "../hoc/indexb.js"
class hocdemob extends Component {
render() {
return (
<div>
<h1>反向继承</h1>
</div>
)
}
}
export default hocb(hocdemob,19)
路由
根据url的不同来切换对应的组件页面
用来实现SPA单页面应用的技术 整个项目只有一个页面 并且在页面切换的时候不会刷新 没有屏幕闪烁
小拓展
react路由分类
1。React-Router 只提供了路由的核心API 2.react-router-dom 除了这些基本的API之外还提供了一些遍历的API方法
react路由模式
1,HashRouter url带有#号 2.BrowerRouter 类似于HistoryRouter不带 # 号 上线之后刷新404.
基本一级路由创建
1,下载 npm install --save react-router-dom 2,设置路由模式 2-1 需要在index.js中进行设置 引用react-router-dom 2-2 设置路由模式
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/hocdemob.jsx';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
reportWebVitals();
3.新建router文件夹用来存放路由的配置 在新建views文件夹来存放路由页面
4.编写路由文件
4-1 引用Route
4-2 引用路由页面组件
4-3 配置出口与规则
import React, { Component } from 'react'
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
import {Route} from "react-router-dom"
export default class index extends Component {
render() {
return (
<React.Fragment>
{}
{}
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</React.Fragment>
)
}
}
5.配置路由文件与项目关系
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './router/index.js';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
reportWebVitals();
路由导航
声明式
Link to属性设置去哪里的路径
NavLink to属性设置去哪里的路径 会在选中的导航上添加一个avtive的类名
小问题:
NavLink会添加一个active的类名 但是这个类名 太常用了 外衣出现了冲突很麻烦 所以如何修改这个类名呢?
使用 activeClassName的属性来修改
<NavLink to="/user" activeClassName="xiaoming">user</NavLink>
编程式
this.props.history.push("/去哪里")
import React, { Component } from 'react'
export default class phone extends Component {
fun=()=>{
this.props.history.push("/user")
}
render() {
return (
<div>
phone
<button onClick={this.fun}>点我去user</button>
</div>
)
}
}
报错
TypeError: Cannot read property ‘push’ of undefined
出现这个错的原因是因为 如果当前使用编程式导航的页面 不是被路由所管理的 那么这个页面就没有路由的history属性 从而也就没有了push这个跳转的方法
如果我就是想让不是被路由所管理的页面也要使用编程式跳转 怎么办呢?
withRouter 高阶组件------让不是被路由管理的页面页具有history属性,如下 1,引入withRouter 注意:声明式跳转用Link或NavLink时也要引入
import {Route,Link,NavLink,withRouter} from "react-router-dom"
2,修改暴漏到最下面
export default withRouter(index)
如此即可完成让不是被路由管理的页面页具有history属性,可跳转
更多的跳转
replace() 替换
goBack() 后退
goforward() 前进
六
404页面
写在规则的最下面 不要path
import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
import {Route} from "react-router-dom"
export default class index extends Component {
render() {
return (
<div>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
{}
<Route component={No}/>
</div>
)
}
}
但是你会发现当我们设置了404页面之后 每个页面都会出现 404页面,解决如下:
switch 唯一匹配
为了解决router的多渲染问题 所以我们需要使用switch来进行唯一渲染 保证每次只渲染一个路由
是唯一渲染 匹配到指定路由后就会停止渲染
import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
import {Route,Switch} from "react-router-dom"
export default class index extends Component {
render() {
return (
<div>
{}
<Switch>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
{}
<Route component={No}/>
</Switch>
</div>
)
}
}
重定向 redirect
exact 精准匹配
import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
import {Route,Switch,Redirect} from "react-router-dom"
export default class index extends Component {
render() {
return (
<div>
{}
<Switch>
{}
{}
<Redirect from="/" to="/home" exact/>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
{}
<Route component={No}/>
</Switch>
</div>
)
}
}
多级路由创建
1, 创建二级路由页面 2,需要在对应的一级路由中引用二级路由,并在引用他的父级路由中配置规则与出口 3,使用Router来配置对应的二级路由的规则与出口
import React, { Component } from 'react'
import Bb from "../components/bottombar.jsx"
import Era from "../pages/era.jsx"
import Erc from "../pages/erc.jsx"
import {Route,Link} from "react-router-dom"
export default class user extends Component {
render() {
return (
<div>
user
<Bb/>
<Link to="/user/era">era</Link>
<Link to="/user/erc">erc</Link>
{}
<Route path="/user/era" component={Era}/>
<Route path="/user/erc" component={Erc}/>
</div>
)
}
}
路由传参
params方式 1.在路由规则中配置接收参数
{}
<Route path="/all/:xiaoming" component={All}/>
2.开始发参
声明式发参
<Link to="/all/我是params传递的参数么么哒!!!!"></Link>
编程式发参
this.props.history.push("/all/我是params传递的参数么么哒!!!!")
3,需要参数接受的页面
this.props.match.params.xxx
import React, { Component } from 'react'
export default class all extends Component {
componentWillMount() {
console.log(this.props.match.params.xiaoming)
}
componentDidMount() {
}
render() {
return (
<div>
<h1>我是详情页</h1>
<p>我是来测试路由传参的---{this.props.match.params.xiaoming}</p>
</div>
)
}
}
总结
params: 传递的数据会在url中进行展示 刷新依然存在
但是只能传递字符串 并且传递太多的话 url不太好看
state方式
1.发送参数
声明式发参
<Link to={{pathname:"/all",state:{xiaoming:"我是state发送的数据么么哒###"}}}></Link>
编程式
fun=()=>{
this.props.history.push({pathname:"/all",state:{xiaoming:"我是state发送的数据么么哒###"}})
}
2 接收的页面 this.props.location.state.key
import React, { Component } from 'react'
export default class all extends Component {
componentWillMount() {
console.log(this.props.location.state.xiaoming)
}
componentDidMount() {
}
render() {
return (
<div>
<h1>我是详情页</h1>
{}
<p>我是来测试路由传参的---{this.props.location.state.xiaoming}</p>
</div>
)
}
}
总结
传递数据的时候在url中不显示传递的数据,并且不params只能传递字符串 statre可以传递对象
刷新地址 数据丢失 注意:传参的时候同一页面只能用一种传参方式,两种传参方式一起用的话会相互影响,并且用state传参的时候要删除接受参数的路由后面配置的接受规则,否则会404
render渲染路由
在路由跳转的时候 可以编写一些逻辑来判断具体渲染那个路由的组件页面
import React, { Component } from 'react'
import Home from "../pages/home.jsx"
import Phone from "../pages/phone.jsx"
import Shop from "../pages/shop.jsx"
import User from "../pages/user.jsx"
import No from "../pages/no.jsx"
import All from "../pages/all.jsx"
import {Route,Switch,Redirect} from "react-router-dom"
export default class index extends Component {
fun=()=>{
if(false){
return <Shop/>
}else{
return <Redirect to="/no"/>
}
}
render() {
return (
<div>
{}
<Switch>
{}
{}
<Redirect from="/" to="/home" exact/>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
{}
<Route path="/shop" render={this.fun}/>
<Route path="/user" component={User}/>
{}
{}
<Route path="/all" component={All}/>
{}
<Route component={No}/>
</Switch>
</div>
)
}
}
数据请求
axios
同vue 但是建议用async await来封装
async和await
字面意思来理解。async 是“异步”的简写(可以理解为parmise的语法糖),而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。 await 只能出现在 async 函数中。 async 函数返回的是一个 Promise 对象。如果在函数中return 一个值,async 会把这个值通过 Promise.resolve() 封装成 Promise 对象。
<script>
async function fun(){
return "你好么么哒"
}
console.log(fun());
</script>
async 函数返回的是一个 Promise 对象,所以then() 来处理这个 Promise 对象
async function fun(){
return "你好么么哒"
}
fun().then((ok)=>{
console.log(ok)
})
一般来说,都认为 await 是在等待一个 async 函数完成。不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值 因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值
用async和await封装api请求
引入拦截器
import service from "../util/server.js"
async function getlink (url){
return await service.request({
url,
method:"GET"
})
}
export default getlink
页面中同原来一样
export default class login extends Component {
componentDidMount() {
getlink("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187").then((ok)=>{
console.log(ok)
})
}
render() {
return (
<div>
</div>
)
}
}
fetch
XMLHttpRequest的一个替代技术 w3c最新标准的一个数据请求技术 (有兼容性问题) 使用:
fetch("请求数据").then((ok)=>{
你的逻辑
})
import {useEffect,useState} from "react"
let Home=()=>{
let [val,setval]=useState([])
useEffect(()=>{
fetch("http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187")
.then(res=>res.json())
.then((ok)=>{
console.log(ok.data.commentList)
setval(val=ok.data.commentList)
})
})
return (
<div>
<h1>使用fetch</h1>
<ul>
{
val.map((v,i)=>{
return (
<li key={i}>{v.commentTxt}</li>
)
})
}
</ul>
</div>
)
}
export default Home
发送数据 get
fetch("地址/key=val&key=val",{method:"GET"}).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
post
fetch("地址",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:"key-val&key=val"
}).then((ok)=>{
console.log(ok)
}).catch((err)=>{
console.log(err)
})
ajax fetch axios 区别
传统的ajax是基于XMLHttpRequest对象 是一个早期新出现的请求方式 属于原生的js 通过这个xhr可通过前后台的数据交互 但是如果出现多个请求嵌套的话就会出现回调地狱的问题 jquery的ajax对象也是基于xhr对象, 只是在他的基础上进行了数据的封装简化了语法提高了兼容性
axios也是基于 xhr 对象的 也是在此基础上进行了封装 只是使用了promise来进行的封装,让它符合最新的ES规范
**fetch **他和XHR对象没有半毛钱关系 他是原生js最新的一个数据请求的标准
JSON-server (模拟数据)
注意:它不像vue只能用于vue,它的话不仅用于react,也能用于vue 用来进行模拟数据的
下载 npm install -g json-server
测试版本 json-server --version
新建文件夹(mock)与.json文件编写模拟数据
{
"user":[
{"name":"xixi1","age":181},
{"name":"xixi2","age":182},
{"name":"xixi3","age":183},
{"name":"xixi4","age":184},
{"name":"xixi5","age":185},
{"name":"xixi6","age":1865}
],
{
"userbb":[
{"name":"xixi12","age":181},
{"name":"xixi22","age":182},
{"name":"xixi33","age":183},
{"name":"xixi44","age":184},
{"name":"xixi55","age":185},
{"name":"xixi66","age":1865}
],
"xixi":{
"xx222222":"xx11111"
}
}
"xixi":{
"xx222222":"xx11111"
}
}
cd到mock文件夹下 使用 json-server --watch json文件名 --port 端口号(会编译出模拟数据的地址)
跨域
http://www.weather.com.cn/data/cityinfo/101320101.html 带有跨域的试验测试地址
1.找到项目目录下/node_modules/react-scripts/config/webpackDevServer.config.js
2.在112行修改文件 跨域内容同vue
弹射 eject
刚才在解决跨域的时候配置文件隐藏过深非常麻烦。
命令 npm run eject
如果报错 使用git 提交一次项目 在 npm run eject
七
redux
redux是为了解决组件与组件之间跨层级关系传值的一个技术 帮助我们简化了传值的过程
redux是什么?
redux是一个js库 主要用于状态管理的一个工具 集中的管理redux多个组件的状态 redux是一个状态库(他是一个第三方的库,也可以在vue中使用)
redux特点/三大原则
1,单一数据源 整个redux的应用中只有一个store对象 2,state是只读的:想要改变state中的数据不能直接修改 而是要通过一个action的方法进行改变。 3.使用纯函数来进行修改:为了使用action来修改state的数据 我们需要编写一些reducers的纯函数来进行修改
基本使用
1,下载 npm install --save redux 2.创建store文件夹并创立文件来容纳redux代码 3.创建store对象并且暴漏
import {createStore} from "redux"
let store=createStore()
export default store
4,传递对应参数
import {createStore} from "redux"
let data={
name:"xixi",
age:18,
arr:[111,2222,333,444]
}
let reducer=(state=data,action)=>{
return state
}
let store=createStore(reducer)
export default store
5.读取数据 getState()获取redux中的state数据
import React, { Component } from 'react'
import store from "../store/index.js"
export default class home extends Component {
constructor(){
super()
this.state={
text:store.getState().name
}
}
render() {
return (
<div>
{}
home---{this.state.text}
</div>
)
}
}
修改
1,创建修改动作
import {createStore} from "redux"
let data={
name:"xixi",
age:18,
arr:[111,2222,333,444]
}
let reducer=(state=data,action)=>{
switch (action.type) {
case "ADD_LISTDATA_USERDATA":
return {...state,age:state.age+1}
break;
case "DEL_LISTDATA_USERDATA":
return {...state,age:state.age-1}
break;
default:
return state
break;
}
}
let store=createStore(reducer)
export default store
2页面中触发修改动作
import React, { Component } from 'react'
import store from "../store/index.js"
export default class home extends Component {
constructor(){
super()
this.state={
text:store.getState().name
}
}
render() {
return (
<div>
{}
home---{this.state.text}
</div>
)
}
}
但是发现redux的数据改变了 但是页面没有更新 没有更新的原因是没有在组件中触发render渲染
3,subscribe()监听器 监听redux中state的数据改变 当redux中state发生了改变 那么sbuscribe就会触发
import React, { Component } from 'react'
import store from "../store/index.js"
export default class shop extends Component {
constructor(){
super()
this.state={
age:store.getState().age
}
}
componentDidMount() {
store.subscribe(()=>{
this.setState({
age:store.getState().age
}
)
})
}
add=()=>{
store.dispatch({type:"ADD_LISTDATA_USERDATA"})
}
del=()=>{
store.dispatch({type:"DEL_LISTDATA_USERDATA"})
}
render() {
return (
<div>
shop---{this.state.age}
<br />
<button onClick={this.add}>+1</button>
<button onClick={this.del}>-1</button>
</div>
)
}
}
4.也可以在调用的时候给actions传递参数 只需要在dispatch(传递)即可
redux拆分写法
actionCreator—拆分派发动作
redux希望有一个专门文件用来存放我们的派发动作 1.在store文件夹下新建一个文件 actionCreator.js用来存放派发动作
export let ADD_LISTDATA_USERDATA=()=>{
return {
type:"ADD_LISTDATA_USERDATA",num:10
}
}
export let DEL_LISTDATA_USERDATA=()=>{
return {
type:"DEL_LISTDATA_USERDATA",num:10
}
}
2,在组件中修改原有的dispatch中调用的动作
import React, { Component } from 'react'
import store from "../store/index.js"
全部引用
全部引用
全部引用
全部引用
全部引用
import * as actioncreator from "../store/actioncreator.js"
export default class shop extends Component {
constructor(){
super()
this.state={
age:store.getState().age
}
}
componentDidMount() {
store.subscribe(()=>{
this.setState({
age:store.getState().age
}
)
})
}
add=()=>{
使用封装的actioncreator动作
使用封装的actioncreator动作
使用封装的actioncreator动作
使用封装的actioncreator动作
使用封装的actioncreator动作
store.dispatch(actioncreator.ADD_LISTDATA_USERDATA())
}
del=()=>{
store.dispatch(actioncreator.DEL_LISTDATA_USERDATA())
}
render() {
return (
<div>
shop---{this.state.age}
<br />
<button onClick={this.add}>+1</button>
<button onClick={this.del}>-1</button>
</div>
)
}
}
封装动作名
因为我们dispath的动作中type的名字出现了两次 后期不方便管理所以进行封装
1.新建一个actiontype.js的文件
2.开始封装
export const ADD_LISTDATA_USERDATA="ADD_LISTDATA_USERDATA"
export const DEL_LISTDATA_USERDATA="DEL_LISTDATA_USERDATA"
3.在派发动作 与 store修改的位置使用
import * as actiontype from "./actiontypes.js"
export let ADD_LISTDATA_USERDATA=()=>{
return {
type:actiontype.ADD_LISTDATA_USERDATA,num:10
}
}
export let DEL_LISTDATA_USERDATA=()=>{
return {
type:actiontype.DEL_LISTDATA_USERDATA,num:10
}
}
注意store的修改动作中也要如上的引用使用
封装reducer
今后的项目体积会越来越大 数据和修改也会越来越多 那么这个时候如果reducer写在一个文件中后期就没有办法进行维护了 所以我们需要把组件自己的reducer单独剥离出来 一个组件一个reducer 或者多个组件一个reducer 方便后期维护与管理 使用: 1.新建文件夹与文件用来存放每个组件的reducer(数据与修改)
2.把原有写在一起的数据与修改单独提取出来 例如将文件名为home和shop的进行封装,只存放各自的数据,代码如下: Home里面
let homedata={
text:"我是home的数据"
}
let homereducer=(state=homedata,action)=>{
return state
}
export default homereducer
Shop里面
import * as actiontypes from "../actiontypes.js"
let data={
name:"xixi",
age:18,
arr:[111,2222,333,444]
}
let shopreducer=(state=data,action)=>{
switch (action.type) {
case actiontypes.ADD_LISTDATA_USERDATA:
console.log({...state,age:state.age})
return {...state,age:state.age+action.num}
break;
case actiontypes.DEL_LISTDATA_USERDATA:
return {...state,age:state.age-action.num}
break;
default:
return state
break;
}
}
export default shopreducer
注意:封装reducer就是类似于vuex的moddule,为每个组件创建一个自己的模块(.js文件),里面写入需要的数据,方便后期维护与管理。
import * as actiontype from "./actiontypes.js"
export let ADD_LISTDATA_USERDATA=()=>{
return {
type:actiontype.ADD_LISTDATA_USERDATA,num:10
}
}
export let DEL_LISTDATA_USERDATA=()=>{
return {
type:actiontype.DEL_LISTDATA_USERDATA,num:10
}
}
3合并reducer很重要
3合并reducer很重要
3合并reducer很重要
3合并reducer很重要
3合并reducer很重要
新建一个文件用来存放合并reducer的代码
import {combineReducers} from "redux"
import homereducer from "./reducers/homer.js"
import shopreducer from "./reducers/shopr.js"
let reducer=combineReducers({
homereducer,
shopreducer
})
export default reducer
4.在store下的index.js中使用刚才合并的reducer
import {createStore} from "redux"
import reducer from "./reducer.js"
let store=createStore(reducer)
export default store
5.发现没报错 但是数据不见了 因为我们现在拆分了reducer所以读取数据的时候有点变化
原始:store.getState().xxxx
新的: store.getState().模块名.xxxx 注意注意 模块名就是在合并时的模块名是啥就是啥,如下
import {combineReducers} from "redux"
import homereducer from "./reducers/homer.js"
import shopreducer from "./reducers/shopr.js"
let reducer=combineReducers({
homereducer,
shopreducer
})
export default reducer
八
react-redux
是一个专为react开发的redux插件 之前使用redux的时候在react组件中与redux的耦合度太高了 (在react的组件中有大量的store对象出现)并且让代码更简洁
使用
1.下载 npm install --save react-redux
2.你先要老老实实的把原来的redux的数据创建等先写出来
读取
3.使用react-redux读取数据
Provider-----把store对象传递给所有的子组件 方便其使用 在index.js中进行
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/demo.jsx';
import reportWebVitals from './reportWebVitals';
import {Provider} from "react-redux"
import store from "./store/index.js"
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
reportWebVitals();
4.让组件与redux进行关联
connect() 是一个函数当这个函数被调用的时候他是一个高阶组件 用来关联组件与redux进行连接
import React, { Component } from 'react'
import {connect} from "react-redux"
class reactdemo extends Component {
render() {
return (
<div>
<h1>使用react-redux读取数据</h1>
</div>
)
}
}
export default connect()(reactdemo)
5.需要向当前组件传递出相关的数据
import React, { Component } from 'react'
import {connect} from "react-redux"
class reactdemo extends Component {
render() {
return (
<div>
<h1>使用react-redux读取数据</h1>
<h1>{this.props.state.demoreducer.name}</h1>
</div>
)
}
}
export default connect(state=>({state}))(reactdemo)
修改
import React, { Component } from 'react'
import {connect} from "react-redux"
import {UPDATA_DEMO} from "../store/actioncreator.js"
class reactdemo extends Component {
fun=()=>{
this.props.dispatch(UPDATA_DEMO())
}
render() {
return (
<div>
<h1>使用react-redux读取数据</h1>
<h1>{this.props.state.demoreducer.name}</h1>
<button onClick={this.fun}>点我修改</button>
</div>
)
}
}
export default connect(state=>({state}))(reactdemo)
生命周期与性能优化
1,constructor()中完成了React数据的初始化
2,componentWillMount()一般使用较少,他更多的是在服务器渲染时使用。它代表的过程是组件已经经历了constructor()初始化数据后,但是还未渲染DOM时。 3,render()进行渲染
4,componentDidMount():组件第一次渲染完成,此时dom节点已经生成,可以在这里调用ajax请求,返回数据 setState后组件会重新渲染 5 componentWillUnmount在组件从 DOM 中移除之前立刻被调用。
更新 6,componentWillReceiveProps (nextProps) 在组件接收到一个新的prop时被调用。初始化不触发.
7,shouldComponentUpdate 判定组件是否要更新html 主要用于性能优化(部分更新)唯一用于控制组件重新渲染的生命周期,由于在react中,setState以后,state发生变化,组件会进入重新渲染的流程,在这里return false可以阻止组件的更新
8 componentWillUpdate() 组件即将更新html时候调用shouldComponentUpdate返回true以后,组件进入重新渲染的流程
9 componentDidUpdate 在组件完成更新后立即调用。
10 render()函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。
九
子组件操作父组件传递过来的数据(点击变色)
父组件
import React, { Component } from 'react'
import Zi from "./zi.jsx"
export default class fu extends Component {
constructor(props){
super(props)
this.state={
arr:[
{title:"aa1",style:false},
{title:"aa2",style:false},
{title:"aa3",style:false},
{title:"aa4",style:false},
{title:"aa5",style:false},
{title:"aa6",style:false},
]
}
}
fun=(num)=>{
console.log(num)
let newarr=this.state.arr;
newarr[num].style=! newarr[num].style
this.setState({
arr:newarr,
})
}
render() {
return (
<React.Fragment>
{
this.state.arr.map((v,i)=>{
return (
<Zi numfun={this.fun} key={i} title={v.title} style={v.style} num={i}></Zi>
)
})
}
<p>父组件</p>
</React.Fragment>
)
}
}
子组件
import React, { Component } from 'react'
export default class zi extends Component {
render() {
let {title,style,num,numfun}=this.props
return (
<div>
<input type="checkbox" onChange={numfun.bind(this,num)}/>
<span style={{color:style?'red':''}}>{title}</span>
</div>
)
}
}
性能优化
因为是在子组件中遍历的,所以在子组件中设置性能优化
shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState) {
return nextProps.style!==this.props.style
}
import React, { Component } from 'react'
export default class zi extends Component {
shouldComponentUpdate(nextProps, nextState) {
return nextProps.style!==this.props.style
}
render() {
let {title,style,num,numfun}=this.props
console.log("我是字")
return (
<div>
<input type="checkbox" onChange={numfun.bind(this,num)}/>
<span style={{color:style?'red':''}}>{title}</span>
</div>
)
}
}
纯组件 PureComponent的性能优化
PureComponent是react技术优化中比较重要 组件在更新的时候 如果props或者是state没有发生改变的时候,就不让当前组件重新render渲染,减少更新次数提高性能
省去了在重新渲染的时候 dom的比对 就是让react帮我们自动是做了一个新数据与旧数据之间的对比(因为他只比较了props和state的内存地址 如果内存地址相同那个让shouldComponentUpdate返回一个false 反之返回true)
import React, { Component,PureComponent } from 'react'
export default class zi extends PureComponent {
render() {
let {title,style,num,numfun}=this.props
console.log("我是字")
return (
<div>
<input type="checkbox" onChange={numfun.bind(this,num)}/>
<span style={{color:style?'red':''}}>{title}</span>
</div>
)
}
}
函数组件的性能优化
React.memo()
umi
umi是蚂蚁金服的一个前端框架 是一个可以扩展性的企业级前端框架 umi是以路由为基础的 同时它支持了配置时路由与约定式路由 保证了我们在react中使用路由的便捷性
什么时候不能用umi
ie8以下
react16.8之前
node10以下
umi与creater-react-app的区别
create-react-app 脚手架 是不包含路由等拓展功能的他是一个容器 用来方便我们开发react umi是一个基于react的第三方框架 在其中包含了很多方便我们开发的第三方依赖
使用
电脑上必须有node10以上
yarn
脸书公司退出的一款 包管理工具 npm和他干的是一件事
安装yarn npm install -g yarn
https://blog.csdn.net/qq_40963664/article/details/82768227
由于下载的服务器在国外 所以建议大家把yarn的下载源切换成淘宝镜像
yarn config set registry https://registry.npm.taobao.org
使用umi
1.全局下载umi npm install -g umi yarn global add umi
2.查看版本 umi -v
3.创建项目 cd到指定路径下 npm 或者 yarn create @umijs/umi-app
4.下载依赖 npm install yarn
5.启动 npm start yarn start
组件创建
可以手工正常配置
命令方式创建组件
umi g page 组件名 创建出来的是js文件
umi g page 组件名 --typescript --less 创建的是ts+less
路由配置
如果需要写路由 额请在.umirc.ts文件中进行路由配置
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
routes: [
{ path: '/', component: '@/pages/index' },
{ path: '/home', component: '@/pages/home.jsx' },
],
fastRefresh: {},
});
title属性
{ path: '/home', component: '@/pages/home.jsx',title:"我是title" },
页面导航
编程式和声明式
声明式 使用LInk 来进行页面的跳转(同react的Link,需引入)
编程式 通过history来进行页面的跳转
import React, { Component } from 'react'
import {history} from "umi"
export default class home extends Component {
fun=()=>{
history.push("/")
}
render() {
return (
<div>
你好么么哒
<button onClick={this.fun}>点我去首页</button>
</div>
)
}
}
重定向
redirect
{ path: '/',redirect:"/index",exact:true },
二级路由
使用 routes配置二级路由
import { defineConfig } from 'umi';
export default defineConfig({
nodeModulesTransform: {
type: 'none',
},
routes: [
{ path: '/',redirect:"/index",exact:true },
{ path: '/index', component: '@/pages/index' },
{
path: '/home',
component: '@/pages/home.jsx',
title:"我是title",
routes:[
{ path: '/home/era', component: '@/pages/er/era.jsx' },
{ path: '/home/erc', component: '@/pages/er/erc.jsx' },
]
},
{ path: '/shop', component: '@/pages/shop.js',title:"我是title" },
],
fastRefresh: {},
});
千万不要忘
千万不要忘
千万不要忘
千万不要忘 在一级路由页面中设置二级路由的出口
{this.props.children}
约定式路由
除了配置式路由外 umi也支持约定式路由 就是不需要我们去手写路由配置 umi会自动根据文件夹里面的文件自动生成路由规则 完成路由
十
dva
在开发大型应用的时候,组件与组件之间的数据通信是一个大问题,但dva就可以高效快速的完成统一的状态管理。
dva是什么?
dva 是一个react的框架 主要是使用简单的api快速的帮助我们实现 react-router+redux-saga
创建
1.全局下载 npm install dva-cli -g
2.查看版本 dva -v
3.dva new 项目名 创建项目
4.cd到项目下 npm start 自动项目
路由
路由页面创建在 routes文件夹下 路由的配置在 router.js中创建的
路由模式
hash 模式
默认就是
BrowerRouter模式
下载一个叫做historyd的一个模块 npm install --save hsitory
数据的状态管理
1,新建文件管理模块(在models下建立数据模块)
export default {
namespace: 'example',
state: {
text:"你好",
num:19,
sex:男
},
};
2.在index.js中建立关系
app.model(require('./models/homer').default);
- 在组件中使用
import React, { Component } from 'react'
import {connect} from "dva"
class home extends Component {
render() {
return (
<div>
{}
我是home组件页面----{this.props.state.homer.text}
</div>
)
}
}
export default connect(state=>({state}))(home)
改 在dva中修改数据都是定义在reducers中
export default {
namespace: 'homer',
state: {
text:"你好",
num:19,
sex:"男"
},
reducers:{
add(state,payload){
return {...state,num:state.num+payload.data}
}
}
};
在组件中通过dispatch调用
fun=()=>{
this.props.dispatch({
type:"homer/add",
data:9
})
}
异步操作
effect dva中进行异步操作的区域
effects:{
*fun({payload},{put,call}){
yield console.log("我是effects")
}
}
组件中通过一个点击事件调用
funa=function(){
this.props.dispatch({
type:"homer/fun"
})
}
<p><button onClick={this.funa.bind(this)}>点击调用</button></p>
请求
在services文件夹中创建自己的请求js,services就是封装的请求,类似于api
import request from '../utils/request';
export function query() {
return request('/api/users');
}
在想使用的组件中 引用 使用
func=()=>{
query().then((ok)=>{
console.log(ok)
})
}
跨域
在.webpackrc文件中写入同vue一样的proxy即可
"proxy":{
"/api":{
"target":"http://www.weather.com.cn/",
"changeOrigin":true,
"pathRewrite":{
"^/api":"/"
}
}
}
小闭环 effect请求数据
在models下的数据模块中通过dispath调用effects
import {query} from "../services/homerequest.js"
*demoa({payload},{put,call}){
let api= yield call(query)
console.log(api)
}
大闭环 请求数据并且修改展示到页面中
subscriptions
订阅 就是dva中model的一个监听器 监听各种变化
组件中
import React, { Component } from 'react'
import {connect} from "dva"
class shop extends Component {
fun=()=>{
this.props.dispatch({
type:"shopr/req"
})
}
render() {
return (
<div>
shop我是--{this.props.state.shopr.num}
<button onClick={this.fun}>点我发送请求修改数据</button>
</div>
)
}
}
export default connect(state=>({state}))(shop)
数据模块中(models下的.js文件)
import {query} from "../services/homerequest.js"
export default {
namespace: 'shopr',
state: {
num:18
},
reducers:{
update(state,payload){
return {...state,num:payload.data}
}
},
effects: {
*req({payload},{put,call}){
let api =yield call(query)
console.log(api.data.weatherinfo.city);
yield put({
type:"update",
data:api.data.weatherinfo.city
})
}
}
};
十一
TypeScript 开发环境搭建
1.下载Node.js
- 64位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64.msi
- 32位:https://nodejs.org/dist/v14.15.1/node-v14.15.1-x86.msi
2,安装node
3.使用npm全局安装typescript
- 进入命令行
- 输入:npm i -g typescript
- tsc -v 命令用来测试是否安装成功
4 创建一个ts文件
5.使用tsc对ts文件进行编译
- 进入命令行
- 进入ts文件所在目录
- 执行命令:tsc xxx.ts
通过配置编译
每次写完ts文件都要输入一次命令是不是很麻烦呢,能不能保存文件时就自动编译运行ts文件呢
- cd到项目下
- 使用 tsc -init 会生成tsconfig.json 文件 ( tsconfig.json文件与TypeScript编译器(tsc)的配置相对应 是 TypeScript 使用 tsconfig.json 文件作为其配置文件 用来 指定待编译文件和定义编译选项。 )
- 直接使用tsc命令即可编译
为什么要使用这个文件
通常我们可以使用 tsc 命令来编译少量 TypeScript 文件
但如果实际开发的项目,很少是只有单个文件,当我们需要编译整个项目时,就可以使用 tsconfig.json 文件,将需要使用到的配置都写进 tsconfig.json 文件,这样就不用每次编译都手动输入配置,另外也方便团队协作开发。
常见配置
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"outDir":"./out/"
},
"files": [
"./src/index.ts"
]
}
常见配置 以下大概了解
compilerOptions
以上大概了解
自动编译
vscode 自动编译
需要 监视tsconfig.json文件:
**步骤:点击终端—》运行任务——>选择typescript——>选择监视tsconfig.json文件 **
命令自动编译
基本类型
变量
注意:let变量不能重复声明 注意:const它拥有与 let相同的作用域规则,但是不能对它们重新赋值。 注意:除了下划线 _ 和美元 $ 符号外,不能包含其他特殊字符,包括空格
类型声明
-
类型声明是TS非常重要的一个特点 -
通过类型声明可以指定TS中变量(参数、形参)的类型 -
指定类型后,当为变量赋值时,TS编译器会自动检查值是否符合类型声明,符合则赋值,否则报错 -
简而言之,类型声明给变量设置了类型,使得变量只能存储某种类型的值 语法:
let 变量: 类型;
let 变量: 类型 = 值;
function fn(参数: 类型, 参数: 类型): 返回值类型{
...
}
自动类型判断
TS拥有自动的类型判断机制
当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
类型:
类型 | 例子 | 描述 |
---|
number | 1, -33, 2.5 | 任意数字 | string | ‘hi’, “hi”, hi | 任意字符串 | boolean | true、false | 布尔值true或false | | | | any | * | 任意类型,不需要检查类型(没有类型检查就没有意义了,跟写JS一样。很不安全) | unknown | * | 类型安全的any | void | 空值(undefined) | 没有值(或undefined) | never | 没有值 | 类型表示永远不会有值的一种类型。 | object | {name:‘孙悟空’} | 任意的JS对象 | array | [1,2,3] | 任意JS数组 | tuple(元组) | [4,5] | 元组,TS新增类型,元组类型用来表示已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同(赋值的顺序不能变) | enum | enum{A, B} | 枚举,TS中新增类型 使用枚举类型可以为一组数值赋予友好的名字。枚举表示的是一个命名元素的集合值 |
number:
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: bigint = 100n;
boolean
let isDone: boolean = false;
string
let color: string = "blue";
color = 'red';
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${fullName}.
I'll be ${age + 1} years old next month.`;
any
在一些情况下,如果我们无法确定变量的类型时(或者无需确认类型时),我们可以将其指定为 any 类型。 TS中对于被标记为 any 类型的变量,是没有进行类型检查而直接通过编译阶段的检查。 在我们的系统中还是应当尽量避免使用 any 类型,以尽可能的保证系统健壮性。
let d: any = 4;
d = 'hello';
d = true;
unknown
TypeScript 3.0 引入了新的unknown 类型,它是 any 类型对应的安全类型。 unknown 和 any 的主要区别是 unknown 类型会更加严格:
let demo:unknown="你好";
let demoa:unknown=1;
let demob:unknown=true;
let num:any=demo
let numb:string=demo;
void
? 没有返回值的函数,其返回值类型为 void
function fun(): void {
console.log("你好");
}
申明为 void 类型的变量,只能赋予 undefined 和 null
let unusable: void = undefined;
never
类型表示永远不会有值的一种类型。
object
let obj: object = {};
array
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];
tuple元组
已知数量与数据类型的数组
let x: [string, number];
x = ["hello", 10];
enum 枚举
TS中新增类型 使用枚举类型可以为一组数值赋予友好的名字。枚举表示的是一个命名元素的集合值
就是给一组数据起一个友好的名字
数字枚举类型和字符串枚举类型;
enum user{xiaoming,xiaohong,xiaobai}
console.log(user.xiaohong)
enum user{xiaoming,xiaohong=99,xiaobai}
console.log(user.xiaohong)
console.log(user.xiaobai)
enum user{xiaoming,xiaohong="小红",xiaobai="小白"}
console.log(user.xiaohong)
console.log(user.xiaobai)
类型别名
类型别名用来给一个类型起个新名字,使用 type 创建类型别名,类型别名常用于联合类型。
在实际应用中,有些类型名字比较长或者难以记忆,重新命名是一个较好的解决方案。
type xiaoming=String;
let textCon:xiaoming="xixi";
console.log(textCon);
联合类型-Union Type
联合类型表示的值可能是多种不同类型当中的某一个。 联合类型放宽了类型的取值的范围,也就是说值的范围不再限于某个单一的数据类型。同时,它也不是无限制地放宽取值的范围,如果那样的话,完全可以使用 any 代替。
type newType=String|Number;
let demoText:newType="你好我可以创建字符串与number"
面向对象
面向对象是程序中一个非常重要的思想,它被很多同学理解成了一个比较难,比较深奥的问题,其实不然。面向对象很简单,简而言之就是程序之中所有的操作都需要通过对象来完成。
- 举例来说:
- 操作浏览器要使用window对象
- 操作网页要使用document对象
- 操作控制台要使用console对象
一切操作都要通过对象,也就是所谓的面向对象,那么对象到底是什么呢?这就要先说到程序是什么,计算机程序的本质就是对现实事物的抽象,抽象的反义词是具体,比如:照片是对一个具体的人的抽象,汽车模型是对具体汽车的抽象等等。程序也是对事物的抽象,在程序中我们可以表示一个人、一条狗、一把枪、一颗子弹等等所有的事物。一个事物到了程序中就变成了一个对象。
在程序中所有的对象都被分成了两个部分数据和功能,以人为例,人的姓名、性别、年龄、身高、体重等属于数据,人可以说话、走路、吃饭、睡觉这些属于人的功能。数据在对象中被成为属性,而功能就被称为方法。所以简而言之,在程序中一切皆是对象。
类(class)
要想面向对象,操作对象,首先便要拥有对象,那么下一个问题就是如何创建对象。要创建对象,必须要先定义类,所谓的类可以理解为对象的模型,程序中可以根据类创建指定类型的对象,举例来说:可以通过Person类来创建人的对象,通过Dog类创建狗的对象,通过Car类来创建汽车的对象,不同的类可以用来创建不同的对象。
class 类名 {
属性名: 类型;
constructor(参数: 类型){
this.属性名 = 参数;
}
方法名(){
....
}
}
示例
class Person{
name: string;
age: number;
constructor(name: string, age: number){
this.name = name;
this.age = age;
}
sayHello(){
console.log(`大家好,我是${this.name}`);
}
}
使用类:
const p = new Person('孙悟空', 18);
p.sayHello();
面向对象的特点
封装
class a{
public name:String="xixi"
}
let demoa=new a()
demoa.name="haha"
console.log(demoa.name)
protected
class a{
protected name:String="xixi"
public showname(){
console.log("因为name是使用protected修饰的只能在当前类和类的子类中使用"+this.name)
}
}
let demoa=new a()
demoa.showname()
private
class a{
private name:String="xixi"
public showname(){
console.log("因为name是使用private仅类自己里头才能使用"+this.name)
}
}
let demoa=new a()
demoa.showname()
静态属性
class Tools{
static PI:Number = 3.1415926;
static sum(num1: number, num2: number){
return num1 + num2
}
}
console.log(Tools.PI);
console.log(Tools.sum(123, 456));
继承 继承是面向对象中的又一个特性 通过继承可以将其他类中的属性和方法引入到当前类中
示例:
class Animal{
name: string;
age: number;
constructor(name: string, age: number){
this.name = name;
this.age = age;
}
}
class Dog extends Animal{
bark(){
console.log(`${this.name}在汪汪叫!`);
}
}
const dog = new Dog('旺财', 4);
dog.bark();
-
通过继承可以在不修改类的情况下完成对类的扩展 -
重写
class Animal{
name: string;
age: number;
constructor(name: string, age: number){
this.name = name;
this.age = age;
}
run(){
console.log(`父类中的run方法!`);
}
}
class Dog extends Animal{
bark(){
console.log(`${this.name}在汪汪叫!`);
}
run(){
console.log(`子类中的run方法,会重写父类中的run方法!`);
}
}
const dog = new Dog('旺财', 4);
dog.bark();
在子类中可以使用super来完成对父类的引用
super
class A {}
class B extends A {
constructor() {
super();
console.log(this)
}
}
接口(Interface)
接口的作用类似于抽象类,不同点在于接口中的所有方法和属性都是没有实值的,换句话说接口中的所有方法都是抽象方法。接口主要负责定义一个类的结构,接口可以去限制一个对象的接口,对象只有包含接口中定义的所有属性和方法时才能匹配接口。同时,可以让一个类去实现接口,实现接口时类中要保护接口中的所有属性。
接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用
使用interface关键字定义 接口一般首字母大写 有的编程语言中会建议接口的名称加上 I 前缀
interface IUser{
name:String,
showname():void
}
interface IUser{
name:String,
showname():void
}
let user:IUser={
name:"xixi",
showname(){
console.log(`名字是${this.name}`)
}
}
console.log(user.name)
user.showname()
可选属性
可选属性:可选属性的含义是该属性可以不存在 有时候不要完全匹配一个接口,那么可以用可选属性。使用?
interface IUser{
name?:String,
showname():void
}
let user:IUser={
showname(){
console.log(`名字是${this.name}`)
}
}
console.log(user.name)
user.showname()
泛型(Generic)
定义一个函数或类时,有些情况下无法确定其中要使用的具体类型(返回值、参数、属性的类型不能确定),此时泛型便能够发挥作用。
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。 举个例子:
function test(arg: any): any{
return arg;
}
上例中,test函数有一个参数类型不确定,但是能确定的时其返回值的类型和参数的类型是相同的,由于类型不确定所以参数和返回值均使用了any,但是很明显这样做是不合适的,首先使用any会关闭TS的类型检查,其次这样设置也不能体现出参数和返回值是相同的类型 类中使用泛型:
class MyClass<T>{
prop: T;
constructor(prop: T){
this.prop = prop;
}
}
这里的<T> 就是泛型,T是我们给这个类型起的名字(不一定非叫T),设置泛型后即可在使用T来表示该类型。所以泛型其实很好理解,就表示某个类型。
十二
React与TS
创建项目 create-react-app 项目名 --template typescript
扩展 npx
创建项目:npx create-react-app 项目名 --template typescript
在 npm version >= 5.2.0 开始,自动安装了npx。
npx 这条命令会临时安装所依赖的环境。命令完成后原有临时下载的会删掉,不会出现在 全局中。下次再执行,还是会重新临时安装。不用全局安装,不用担心长期的污染。
也就是说 npx 会自动查找当前依赖包中的可执行文件,如果找不到,就会去 PATH 里找。如果依然找不到,就会帮你安装
组件
创建一个tsx后缀名的文件
在需要的位置引用使用 但是引用的时候可能会出错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Pl0NMXH-1629292032678)(.\img\6.png)]
在引用时候不要加后缀名
数据传递
使用传统的方式进行数据传递的时候发现会报错
在进行数据传递的时候要使用 interface接口对类型限制 在子组件中进行限制设定
状态
直接定义状态会出现问题
需要使用接口
逆向传值
React 的核心概念之一是组件。在这里,我们将引用 React v16.8 以后的标准组件,这意味着使用 Hook 而不是类的组件。
组件的创建
FC就是FunctionComponent的缩写ts+react编写组件的语法
export let Home:React.FC<{}>=()=>{
return (
<div>我事一个函数组件</div>
)
}
props的使用
interface IUser{
title?:String
}
export let Home:React.FC<IUser>=(props)=>{
return (
<div>我事一个函数组件---{props.title}</div>
)
}
父组件正常传递
HOOK
React Hooks是React 16.8.0版本推出的新特性 主要的作用就是让无状态组件 可以使用状态和react的其他特性。(在react开发中状态的管理是必不可少的 以前为了进行状态管理需要使用类组件或者redux等来管理)
Hook在class中没有作用
useState
useState()就是React提供最基础、最常用的Hook,主要用来定义和管理本地状态。
useState返回的是一个数组(长度为2),数组的第一个对象表示当前状态的值,第二个对象表示用于更改状态的函数,类似于类组件的setState。
let [val(当前状态的值),setVal(改变状态的函数)]=useState(当前状态的初始值)
import {useState} from "react"
let Home:React.FC<{}>=()=>{
let [text,setText]=useState("你好")
return (
<div>
使用useState数据---{text}
</div>
)
}
export default Home
修改
import {useState} from "react"
let Home:React.FC<{}>=()=>{
let [text,setText]=useState("你好")
let fun=():void=>{
setText(text="你坏")
}
return (
<div>
使用useState数据---{text}
<button onClick={fun}>点我修改</button>
</div>
)
}
export default Home
多个状态怎么办
1.声明对象类型的状态
let Home:React.FC<{}>=()=>{
let [text,setText]=useState({
a:"第1",
b:"第2",
c:"第3",
})
return (
<div>
使用useState数据---{text.a}----{text.b}---{text.c}
</div>
)
}
export default Home
修改
import {useState} from "react"
let Home:React.FC<{}>=()=>{
let [text,setText]=useState({
a:"第1",
b:"第2",
c:"第3",
})
let fun=():void=>{
setText({...text,a:"我变了"})
}
return (
<div>
使用useState数据---{text.a}----{text.b}---{text.c}
<button onClick={fun}>点我修改a</button>
</div>
)
}
export default Home
2.多次声明
按照传统的方式写多次即可
useRef
hooks中可以通过 useRef()获取Dom节点
import {useRef} from "react"
let Home:React.FC<{}>=()=>{
let u:any=useRef(null)
let fun=():void=>{
u.current.style.color="red"
}
return (
<div>
<p ref={u}>修改我的颜色</p>
<button onClick={fun}>点我修改a</button>
</div>
)
}
export default Home
useEffect
useEffect:函数组件中没有生命周期,那么可以使用 useEffect 来替代。可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。
import {useEffect} from "react"
let Home:React.FC<{}>=()=>{
useEffect(()=>{
console.log("执行了");
})
return (
<div>
<p>执行了</p>
</div>
)
}
export default Home
useReducer
useReducer和redux没有关系。它主要就是修改数据的 他就是加强版的useState在处理多数据修改的时候降低复杂度
创建数据
import {useReducer} from "react"
let Home:React.FC<{}>=()=>{
let reducer:any=(state:Number,action:Object):Number=>{
return state
}
let [state,dispatch]=useReducer(reducer,fu n f z z z z)
return (
<div>
<p>我是组件--{state}</p>
</div>
)
}
export default Home
修改数据
import {useReducer} from "react"
let Home:React.FC<{}>=()=>{
let reducer:any=(state:any,action:any):Number=>{
switch (action.type) {
case "ADD":
return state+1
break;
default:
break;
}
return state
}
let [state,dispatch]:any=useReducer(reducer,1)
let fun=():void=>{
dispatch({type:"ADD"})
}
return (
<div>
<p>我是组件--{state}</p>
<button onClick={fun}>+1</button>
</div>
)
}
export default Home
=()=>{ let reducer:any=(state:Number,action:Object):Number=>{ return state } // 1.初始化数据 // state代表数据 // dispatch代表修改动作 // reducer修改数据的任务 // 1 是初始化数据 let [state,dispatch]=useReducer(reducer,fu n f z z z z)
return (
<div>
<p>我是组件--{state}</p>
</div>
)
}
export default Home
修改数据
```js
import {useReducer} from "react"
let Home:React.FC<{}>=()=>{
let reducer:any=(state:any,action:any):Number=>{
switch (action.type) {
case "ADD":
return state+1
break;
default:
break;
}
return state
}
// 1.初始化数据
// state代表数据
// dispatch代表修改动作
// reducer修改数据的任务
// 1 是初始化数据
let [state,dispatch]:any=useReducer(reducer,1)
let fun=():void=>{
dispatch({type:"ADD"})
}
return (
<div>
<p>我是组件--{state}</p>
<button onClick={fun}>+1</button>
</div>
)
}
export default Home
十三
webpack
是什么
1.模块打包工具,可以分析项目结构, 2.根据模块与模块的关联 把项目从每一个单独的模块合并成一个整体 3.把浏览器不认识的项目编译成浏览器可以识别的项目 typescript less scss等变成浏览器可以识别的
webpack的核心:入口 出口 加载器 插件
webpack与gulp与grunt的区别
webpack和gulp并没有太大的可比性 gulp/grunt是一个优化前端开发的一个工具 但是webpack是一个模块化的构建方案 他可以把一个项目看成是一个整体 根据入口文件层层分析从而把这个模块化项目进行转换
基本使用
1.下载
webpack 核心文件
webpack-cli是它的命令行
npm install -g webpack@4.39.3 webpack-cli@3
2.写一个模块化的内容 让html引用 发现不能运行(新建一个文件夹,里面是js文件和HTML) a.js
export let text="hellow wotdd";
export let fun=()=>{
return "方法"
}
b.js
import * as demoa from "./a.js"
console.log(demoa.text);
console.log(demoa.fun());
Html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./b.js"></script>
</head>
<body>
</body>
</html>
3.使用webpack进行编译
? 3-1cd到项目路径下
? 3-2 输入命令 webpack 你要打包的文件 -o 打包后的文件名字自己起
4.把生成的文件引导html中 发现即可使用
问题
上面打包完发现 报了一个警告
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for
this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
出现的原因是 webpack需要我们指定打包模式 是 生产模式 压缩(production) 还是开发模式 不压缩(development) 如何制定模式
webpack --mode development 你要打包的文件 -o 打包后的文件名字自己起
简单的打包命令
首先你要打包的文件位置 必须必须必须必须 在src文件夹下 其次打包的入口文件必须要index.js
命令只需要输入 webpack --mode development
会生成一个dist文件夹 其中main.js就是打包之后的内容
配置文件
配置文件的名字必须必须必须在根路径下
webpack.config.js
入口出口
入口是 entry 出口是 output
module.exports={
entry:"./src/index.js",
output:{
path:__dirname+"/dist",
filename:"aa.js"
}
}
然后在终端输入webpack
一次打包多个文件怎么办?
module.exports={
entry:{
aa:"./src/index.js",
bb:"./src/indexb.js"
},
output:{
path:__dirname+"/dist",
filename:"new[name].js"
}
}
模式
module.exports={
entry:{
aa:"./src/index.js",
bb:"./src/indexb.js"
},
output:{
path:__dirname+"/dist",
filename:"new[name].js"
},
mode:"development"
}
加载器
插件plugins
下载:npm install --save-dev clean-webpack-plugin
插件 扩展webpack的功能 插件是用来让webpack来做与构建项目无关的事情
clean-webpack-plugin
地址:https://www.npmjs.com/package/clean-webpack-plugin
html-webpack-plugin
把打包好的内容自动移入到html中 不需要我们手动操作
dev-server
开发服务器
下载: npm install -g webpack-dev-server@3
cd到当前项目下 使用webpack-dev-server启动 打开浏览器输入 localhost:8080
自动开启
devServer:{
open:true,
port:8888
}
打包多个文件、模式指定、插件、配置dev-server代码综合如下(配置文件的名字必须必须必须在根路径下:webpack.config.js)
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
entry:{
aa:"./src/index.js",
cc:"./src/indexb.js"
},
output:{
path:__dirname+"/dist",
filename:"new[name].js"
},
mode:"development",
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template:"./public/index.html",
filename:"index.html",
title:"你好么么哒",
minify:{
collapseWhitespace: true,
removeComments: true,
}
})
],
devServer:{
open:true,
port:8888
}
}
十四
loaders 加载器
让webpack支持更多的文件 typescript less scss 等内容 对上述内容进行翻译 变成浏览器可以识别的
style-loader 与 css-loader
官网:https://webpack.docschina.org/loaders/style-loader/
在vue中使用:下载 npm install less less-loader --save-dev(如果效果不展示,则降低下载版本)
但是注意版本,如果不能正常展示的话,就降版本
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-eslint": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"babel-eslint": "^10.1.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"less": "^3.1.1",
"less-loader": "^7.0.1",
"vue-template-compiler": "^2.6.11"
}
"devDependencies": {
"@webpack-cli/serve": "^1.5.2",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"css-loader": "^4.2.0",
"html-webpack-plugin": "^5.3.2",
"style-loader": "^2"
}
vue中使用时
<style lang="less">
@demo:red;
h1{
color: @demo;
}
</style>
less-loader sass-loader
babel-loader
vue-loader
因为浏览器不认识.vue文件 就是把template翻译成html style翻译成css script 翻译成js
问题
webpack 有什么作用
1.打包
2.合并代码 把分散的代码块打包成一个大文件 减少了http的请求次数可以优化代码的传输效率 优化代码的体积
3.有各种功能 比如less-loader 翻译less babel-lader可以翻译es代码 vue-loader可以翻译vue文件等等
webpack打包原理
webpack会把一个项目当成是一个整体 我们组需要设置一个主入口文件 webpack既可以从这个主入口文件中开始去寻找它所依赖的各个模块文件 并且使用各种loader来对文件进行翻译 配合着个中plugins来打包成一个或者多个浏览器可以识别的文件
1.解析配置文件 寻找webpack。config。js文件来进行解析
2 注册配置文件中的各个插件并且做出对应的反应
3.解析entry入口文件 并且找出关联文件
4.通过递归的方式来去寻找各个模块 然后根据对应的loader匹配文件 进行转换
5.生成转换文件
6output输出
小程序
什么是小程序
触手可及 用完即走 2016 年1月 张小龙提出微信小程序
2016年9月 内测
2017年1月 第一批小程序公测上线
优势
1.无需下载
2.运行速度非常快 近似于原生app
3.构建速度快
4 体积不能超过2mb
开发
1.你要有微信号
2.下载工具
文件结构
1.pages是写页面的 一个页面由4个文件构成
js 写逻辑的
json 写页面配置的
wxml 就是html
wxss 就是css
json文件
页面内json
局部页面配置
app.json
全局页面配置
pages
用于指定小程序由哪些页面组成,每一项都对应一个页面的 路径(含文件名) 信息。文件名不需要写文件后缀,框架会自动去寻找对应位置的 .json , .js , .wxml , .wxss 四个文件进行处理。
未指定 entryPagePath 时,数组的第一项代表小程序的初始页面(首页)。
小程序中新增/减少页面,都需要对 pages 数组进行修改。
创建页面、
在pages下创建一个文件夹 在文件家中创建4个文件.json , .js , .wxml , .wxss 四个文件 但是文件的名字必须和文件夹相同
window
用于设置小程序的状态栏、导航条、标题、窗口背景色。
属性 | 类型 | 默认值 | 描述 | 最低版本 |
---|
navigationBarBackgroundColor | HexColor | #000000 | 导航栏背景颜色,如 #000000 | | navigationBarTextStyle | string | white | 导航栏标题颜色,仅支持 black / white | | navigationBarTitleText | string | | 导航栏标题文字内容 | | navigationStyle | string | default | 导航栏样式,仅支持以下值: default 默认样式 custom 自定义导航栏,只保留右上角胶囊按钮。参见注 2。 | iOS/Android 微信客户端 6.6.0,Windows 微信客户端不支持 | backgroundColor | HexColor | #ffffff | 窗口的背景色 | | backgroundTextStyle | string | dark | 下拉 loading 的样式,仅支持 dark / light | | backgroundColorTop | string | #ffffff | 顶部窗口的背景色,仅 iOS 支持 | 微信客户端 6.5.16 | backgroundColorBottom | string | #ffffff | 底部窗口的背景色,仅 iOS 支持 | 微信客户端 6.5.16 | enablePullDownRefresh | boolean | false | 是否开启全局的下拉刷新。 详见 Page.onPullDownRefresh | | onReachBottomDistance | number | 50 | 页面上拉触底事件触发时距页面底部距离,单位为 px。 详见 Page.onReachBottom | | pageOrientation | string | portrait | 屏幕旋转设置,支持 auto / portrait / landscape 详见 响应显示区域变化 | 2.4.0 (auto) / 2.5.0 (landscape) |
tabbar
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html#tabBar
十五
组件
wxml(WeiXin Markup Langyage)微信开发出的一套标签语言 提供了很多的内置组件
view
布局容器 等同于div
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|
hover-class | string | none | 否 | 指定按下去的样式类。当 hover-class="none" 时,没有点击态效果 | 1.0.0 | hover-stop-propagation | boolean | false | 否 | 指定是否阻止本节点的祖先节点出现点击态 | 1.5.0 | hover-start-time | number | 50 | 否 | 按住后多久出现点击态,单位毫秒 | 1.0.0 | hover-stay-time | number | 400 | 否 | 手指松开后点击态保留时间,单位毫秒 | 1.0.0 |
text
文本。它也支持转义字符 \n换行 \t空格
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|
selectable | boolean | false | 否 | 文本是否可选 (已废弃) | 1.1.0 | user-select | boolean | false | 否 | 文本是否可选,该属性会使文本节点显示为 inline-block | 2.12.1 | space | string | | 否 | 显示连续空格 | 1.4.0 | decode | boolean | false | 否 | 是否解码 | [1.4.0]( |
space 的合法值
值 | 说明 | 最低版本 |
---|
ensp | 中文字符空格一半大小 | | emsp | 中文字符空格大小 | | nbsp | 根据字体设置的空格大小 | |
Bug & Tip
tip : decode可以解析的有 < > & '
tip : 各个操作系统的空格标准并不一致。tip :text 组件内只支持 text 嵌套。
icon
icon
基础库 1.0.0 开始支持,低版本需做兼容处理。
图标。组件属性的长度单位默认为px,2.4.0起支持传入单位(rpx/px)。
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|
type | string | | 是 | icon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear | 1.0.0 | size | number/string | 23 | 否 | icon的大小 | 1.0.0 | color | string | | 否 | icon的颜色,同css的color | |
image
image组件默认宽度320px、高度240px 小程序的图片样式 不能设置auto
swiper(轮播)
<!--pages/login/login.wxml-->
<text>这是login</text>
<swiper autoplay="true" interval="1000" indicator-dots="true" duration="500" circular="true" indicator-color="red">
<swiper-item>
<image src="../../img/2547d64181711139.jpg"></image>
</swiper-item>
<swiper-item>
<image src="../../img/0314ff88d49e71bc.jpg"></image>
</swiper-item>
<swiper-item>
<image src="../../img/2547d64181711139.jpg"></image>
</swiper-item>
<swiper-item>
<image src="../../img/2547d64181711139.jpg"></image>
</swiper-item>
</swiper>
地图(map)
<map longitude="108.882526" latitude="34.22411">
navigator
页面链接。
open-type :
navigate 默认值 保留当前页面 并且跳转到非tabbar的页面
redirect 关闭当前页面跳转带其他非tabbar的页面
reLaunch 关闭所有页面跳转带其他非tabbar的页面
switchTab 关闭当前页面跳转到tabbar页面
navigateBank 关闭当前页面 回退到上一个页面
更多
https://developers.weixin.qq.com/miniprogram/dev/component/cover-image.html
自定义组件
一个组件也是由 wxml wxss js json4个文件构成
1.新建components文件夹 并且创建组件文件夹 与4个文件
2.在想使用的page页面的JSON来引用
{
"usingComponents": {
"com":"../../components/com/com"
}
}
3.自定义标签使用组件
组件的生命周期
生命周期 | 参数 | 描述 | 最低版本 |
---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 | attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 | ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 | moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 | detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 | error | Object Error | 每当组件方法抛出错误时执行 | |
组件的生命周期(在组件的.js中)
Component({
created(){
console.log(122);
},
attached(){
console.log("进入节点树执行");
},
ready(){
console.log("视图布局完成后执行");
},
moved(){
console.log("从组件实例被移到另一个节点");
},
error(){
console.log("错误");
},
properties: {
},
data: {
},
methods: {
}
})
```| |
## 组件传值
**正向**
在需要数据的组件的propertries中设置接收数据与数据类型
```js
properties: {
title:String
},
在子组件中直接使用
使用{{定义的接收变量}}
在父组件传递数据 和vue一样 直接传递
<zi title="我是传递给子组件的数据"/>
逆向
事件触发一个函数 ( bindtap 手指触摸后马上离开事件)调用函数的时候不加()加了就自动执行了
<button bindtap="fun">点我逆向传值</button>
在函数中进行自定义事件的抛出
methods: {
fun(){
this.triggerEvent("zipao","我是子组件的数据")
}
}
在子组件被调用的地方 接收 bind:你抛出的自定义事件
<zi title="我是传递给子组件的数据" bind:zipao="fufun"/>
需要定义父组件的函数 并且设置形参
methods: {
fufun(el){
console.log(el.detail);
}
}
优化—纯数据字段
在一个程序中 变量数据分为两种 第一种需要在页面展示的 第二种 不需要在页面展示仅仅是为了临时处理而创造的 页面展示的数据需要更快的进行渲染 那么在这个时候 小程序在处理变量的时候 就可以 把这两种变量分开处理 先在加载的时候加载需要展示的变量 然后等页面加载完毕后在慢慢的处理第二种变量
我们就需要使用纯数据字段来告诉小程序那种是要展示的那种是临时处理数据的
component构造器的第一层级使用options其中设置pureDataPattern设置一个正则来告诉小程序谁是纯数据
options:{
pureDataPattern:/^_/
},
data: {
text:"我是text",
_textb:"我是textb"
},
那么_textb因为变成了纯数据字段 所以就不会在页面展示了
数据监听----observers
就是监听data中的数据改变
observers:{
"title"(newtitle){
console.log(newtitle);
}
},
修改data数据
setData()来修改data数据
updata(){
this.setData({
title:"我变了"
})
}
behaviors
组件之间的代码共享 可以把一些重复使用的变量 方法 生命周期等内容独立出来 方便复用
1.新建文件夹与文件
2.编写代码
let behavior=Behavior({
data:{
demo:"我是复用的变量"
},
methods:{
demofun(){
console.log("我是复用的方法");
}
}
})
export {behavior}
3.哪里用 哪里引 并且使用
import {behavior} from "../../behaviors/index.js"
Component({
behaviors:[behavior],
4.想怎么用怎么用
<view>{{demo}}</view>
wxss
WXSS(WeiXin style Sheet) 样式文件
wxss具有css的大部分特性 到那时为了方便开发小程序 做了些细微的改变
尺寸单位
rpx 小程序中自适应的一个长度单位
怎么计算rpx呢?
美工给我了一个设计稿 是1px 那我应该设置多少rpx
官方建议我们使用IPhone6为设计原稿
750/屏幕宽度
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 | rpx换算px (屏幕宽度/750) | px换算rpx (750/屏幕宽度) |
---|
iPhone5 | 1rpx = 0.42px | 1px = 2.34rpx | iPhone6 | 1rpx = 0.5px | 1px = 2rpx | iPhone6 Plus | 1rpx = 0.552px | 1px = 1.81rpx |
建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。
样式导入
使用@import 语句可以导入外联样式表,@import 后跟需要导入的外联样式表的相对路径,用; 表示语句结束
便利(数据在data中)
wx:for="{{你要便利的内容}}"
<view wx:for="{{arr}}">
<!-- 默认情况下 值是item 下标是index -->
{{item}}-----{{index}}
</view>
<!-- 修改item和index -->
<view wx:for="{{arr}}" wx:for-item="v" wx:for-index="i">
<!-- 默认情况下 值是item 下标是index -->
{{v}}-----{{i}}
</view>
API
二维码
https://developers.weixin.qq.com/miniprogram/dev/api/device/scan/wx.scanCode.html 组件中
<button bindtap="code">点我扫码</button>
函数(methods)中
code(){
wx.scanCode({
onlyFromCamera: true,
success(ok){
console.log(ok);
}
})
}
注意:代码部分完成后,点击真机调试,扫码进行后续操作,该功能需要结合手机实现,扫码可搜索草料二维码生成一个
打电话(同二维码)
组件中
<button bindtap="code">点我打电话</button>
函数(methods)中
code(){
wx.makePhoneCall({
phoneNumber: '10000'
})
}
**该功能还是需要配合手机使用,在手机上点击 “点我打电话可打给对应的号码” **
十六
便利—block
就是在渲染多个节点的时候作为一个包含块 但是他不参与渲染 仅仅是包裹的作用
<block wx:for="{{arr}}">
<text>{{item}}</text>
<text>{{index}}</text>
</block>
便利—wx:key
当数据改变触发页面重新渲染的时候 他会比较带有key的内容 小程序会保证这些内容重新进行排列 而不是重新的创建 ,那么这样一来就会确保组件保持自身的状态 提高渲染效率
<block wx:for="{{arr}}" wx:key="index">
<text>{{item}}</text>
<text>{{index}}</text>
</block>
条件渲染
wx:if true 显示 false隐藏
<view wx:if="{{bool}}">我是测试wx:if的</view>
wx:else 当wx:if的条件不满足的时候生效
<view wx:if="{{bool}}">我是测试wx:if的</view>
<view wx:else>我是测试wx:else的</view>
wx:elif 多重if结构
<view wx:if="{{1==2}}">我是测试wx:if的</view>
<view wx:elif="{{2==3}}">elifa</view>
<view wx:elif="{{2==4}}">elifb</view>
<view wx:elif="{{2==2}}">elifc</view>
<view wx:else>我是测试wx:else的</view>
微信小程序的条件渲染也支持block
属性变量
小程序中如果属性插变量 那么直接使用 属性="{{变量}}"
事件
什么是事件?
就是页面到逻辑的通信方式
事件分类
冒泡事件
冒泡事件使用bind修饰 当触发事件之后 这个事件会向父节点进行传递
非冒泡事件
非冒泡事件使用catch修饰 当触发事件之后 这个事件不会向父节点进行传递
事件列表
类型 | 触发条件 | 最低版本 |
---|
touchstart | 手指触摸动作开始 | | touchmove | 手指触摸后移动 | | touchcancel | 手指触摸动作被打断,如来电提醒,弹窗 | | touchend | 手指触摸动作结束 | | tap | 手指触摸后马上离开 | | longpress | 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发 | 1.5.0 | longtap | 手指触摸后,超过350ms再离开(推荐使用longpress事件代替) | | transitionend | 会在 WXSS transition 或 wx.createAnimation 动画结束后触发 | | animationstart | 会在一个 WXSS animation 动画开始时触发 | | animationiteration | 会在一个 WXSS animation 一次迭代结束时触发 | | animationend | 会在一个 WXSS animation 动画完成时触发 | | touchforcechange | 在支持 3D Touch 的 iPhone 设备,重按时会触发 | 1.9.90 |
事件对象
谁触发这个事件事件对象指向的就是谁
路由导航
声明式
navigator
编程式
https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.reLaunch.html
路由导航传参
如果在小程序的页面之间进行参数传递的话 我们可以使用如下方式 声明式
<navigator url="../all/all?xiaoming=345"></navigator>
编程式
wx.navigateTo({
url: '../all/all?xiaoming=123',
})
接收:
只需要在你想接收的页面中找到
onLoad: function (options) {
console.log(options);
},
响应到页面
这里需要点击才能渲染到页面
Page({
data: {
title:"",
},
onLoad: function (options) {
console.log(options);
},
fun(){
this.setData({
title:this.options.xixi
})
},
onReady: function () {
},
onShow: function () {
},
onHide: function () {
},
onUnload: function () {
},
onPullDownRefresh: function () {
},
onReachBottom: function () {
},
onShareAppMessage: function () {
}
})
页面中点击
<!--pages/all/all.wxml-->
<text>详情----{{title}}</text>
<button bindtap="fun">点击修改</button>
数据请求
Page({
data: {
title:"",
arr:[],
},
onLoad: function (options) {
console.log(options);
},
fun(){
this.setData({
title:this.options.xixi
})
},
func(){
let that=this
wx.request({
url: 'http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187',
success(ok){
console.log(ok.data.data.commentList);
that.setData({
arr:ok.data.data.commentList
})
}
})
},
onReady: function () {
},
onShow: function () {
},
onHide: function () {
},
onUnload: function () {
},
onPullDownRefresh: function () {
},
onReachBottom: function () {
},
onShareAppMessage: function () {
}
})
页面中触发(func函数)并且渲染
<button bindtap="func">点我发送请求</button>
<view wx:for="{{arr}}" wx:key="index">
{{item.commentTxt}}
</view>
wx.request()
https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html
问题
我们的地址是没有问题的 但是出现一下错误
http://api.artgoer.cn:8084 不在以下 request 合法域名列表中,请参考文档:https://developers.weixin.qq.com/miniprogram/dev/framework/ability/network.html
怎么跳过域名验证
在小程序开发工具中点击 右上角详情-=----》项目设置 —》勾选 不校验合法域名即可
页面生命周期
交互
页面的弹框
https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html
|