代码如下:
<!-- 引入babel,用于将jsx转为js --> <div id="test"></div> <script type="text/babel"> const VDOM = <h2>无需引号</h2>//这里不用引号是因为script标签里用的babel,将jsx转换为js ReactDOM.render(VDOM, document.getElementById('test')); //将VDOM渲染到test中,且需要一个盒子 </script>
代码如下:
<script type="text/babel"> function Demo() { console.log(this) //此处的this是undefined,因为babel编译后开启严格模式,否则此时应该指向window return <h2>函数式组件</h2> } //渲染组件到页面 ReactDOM.render(<Demo/>, document.getElementById('test')) /// React解析组件 标签,找到了Demo组件 /// 发现组件是使用函数定义的,随后调用该函数,剪个返回的虚拟DOM转为真实DOM,渲染到页面中 // demo() { // //bebal开启了严格模式禁止自定义的this指向window,这里的this指的是undefined // console.log(this.state.isHot) // } </script>
代码如下:
/// 创建类式组件 //必须要继承一个React中的Component //必须要有render //render 必须要有返回值 class MyComponent extends React.Component { constructor(props) { //在构造器里初始化状态,并且改变this指向 //constructor只调用一次 super(props) // super(props)的作用:构造器完全可以省略,但是如果不省略,props也不接不传,通过this访问props会undefined, // 构造器开发时几乎不会用 this.state = { isHot: true, wind: '大风' } this.demo = this.demo.bind(this); //解决this指向问题(bind:一是生成新的函数,一是改变this),右侧的demo是从原型链上找到的,左侧上的是挂在自身上的demo } render() { //调用1+n次,n是状态的更改 //render中的this,是MyComponent是实例对象 const {isHot, wind} = this.state; //这里的this.demo 首先要先找挂在自身的方法,如果没有再找原型链 return <h2 onClick={this.demo}>今天天气很{this.state.isHot ? '炎热' : '寒冷'}, {wind}</h2> } demo() { //点几次调用几次 //这里的this指的是undefined,只有通过实例调用demo时它的this才会是实例对象, //render()中的this.demo不是通过实例调用的 //类中方法this的指向:类中所有的方法都开启了局本严格模式,所以不能指向window,所以为undefined //由于demo是作为onclick的回调,所以不是调用类中的方法,而是直接调用堆中的函数,而又因为这个方法是类的方法被开启为局部严格模式,所以this为undefined console.log(this.state.isHot) const isHot = this.state.isHot; // state状态中的数据,React不支持直接更改,要使用内置API更改setState!!!!!!!! //且更新是一种合并不是替换 this.setState({isHot: !isHot}) //成功 } } //渲染组件到页面 ReactDOM.render(<MyComponent/>, document.getElementById("test3")); /* 执行了ReactDOM.render(<MyComponent/>...发生了什么? 1、React解析组件标签,找到来了组件 2、发现组件是用类定义的,然后new出来该类的实例 并通过该实例调用到原型上的render方法 3、将render返回的虚拟DOM转为真是DO。呈现在页面中 */
state是指组件内部自身的值
<div id="test"></div> <script type="text/babel"> //创建组件 class Simple extends React.Component { //初始化状态,类中可以直接赋值,且不能在前面加变量声明 state= {isHot: false, wind: '清风'} render() { const {isHot, wind} = this.state return <h1 onClick={this.Weather} className={isHot ? 'active' : 'actived'}>今天天气:{isHot ? '炎热' : '凉爽'}, {wind}</h1> } //赋值语句加箭头函数 //自定义方法中this为undefined:1,强制绑定this,(bind()), 2,箭头函数 Weather = ()=>{ const isHot = this.state.isHot; this.setState({isHot:!isHot}) } } //渲染组件到页面上 ReactDOM.render(<Simple/>, document.getElementById('test')) </script>
props是指外部传入类式组件内部的值
<div id="test"></div> <script type="text/javascript" src="../js/prop-types.js"></script> <script type="text/babel"> class Demo extends React.Component { render() { const {name, age, sex} = this.props; return ( <ul> <li>姓名:{name}</li> <li>年龄:{age}</li> <li>性别:{sex}</li> </ul> ) } } //props只读 //类型与必选 Demo.propTypes = { //PropTypes的类型为了避开关键字,所以大多小写 name: PropTypes.string.isRequired, sex: PropTypes.string, age: PropTypes.number, //不能用function,因为function是一个关键字,所以传func, speak: PropTypes.func } //默认值 Demo.defaultProps = { sex: '喵喵喵', age: 19 } let obj = { name: "S", age: 23, sex:"女" } //渲染组件到页面 //批量传递props,也就是批量传递标签属性 ReactDOM.render(<Demo {...obj}/>, document.getElementById('test')) //进行类型限制、进行必传行限制、进行默认值限制 ReactDOM.render(<Demo name="tom" age={22} sex="男" speak={speak} />, document.getElementById('test2')) function speak() { console.log('正在说话') } </script>
<script type="text/babel"> //创建组件 class Person extends React.Component { //props只读 //类型与必选 static propTypes = { //PropTypes的类型为了避开关键字,所以大多小写 name: PropTypes.string.isRequired, sex: PropTypes.string, age: PropTypes.number, //不能用function,因为function是一个关键字,所以传func, speak: PropTypes.func } //默认值 static defaultProps = { sex: '喵喵喵', age: 19 } // state= {name: 'tome', age: 18, sex: '女'} render() { const { name, age, sex, speak } = this.props; return ( <ul> <li onClick={speak}>姓名:{name}</li> <li>性别:{age + 1}</li> <li>年龄:{sex}</li> </ul> ) } } let obj = { name: "S", age: 23, sex: "女" } //渲染组件到页面 //批量传递props,也就是批量传递标签属性 ReactDOM.render(<Person {...obj} />, document.getElementById('test')) //进行类型限制、进行必传行限制、进行默认值限制 ReactDOM.render(<Person name="tom" age={22} sex="男" speak={speak} />, document.getElementById('test2')) function speak() { console.log('正在说话') } </script>
ref就是把自身节点存入一个容器
<script type="text/babel"> class Person extends React.Component { // static propsTypes = { // } // static defaultProps = { // } //展示左侧输入框的数据 showData = () => { const {input1} = this.refs; alert(input1.value) } showData2 = ()=>{ const { input2 } = this.refs; alert(input2.value) } // ref用来代替id是一个标识 // 字符串的ref存在一些效率上的问题,写的过多之后会有问题 //使用其它两种 render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示数据"/> <button ref="button100" onClick={this.showData}>点击按钮</button> <input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/> </div> ) } } ReactDOM.render(<Person/>, document.getElementById('test')) </script>
createRef比较麻烦,所以还是经常用内联样式
<script type="text/babel"> class Demo extends React.Component { myRef = React.createRef(); //调用后返回一个容器,该容器可以存储被ref所标识的节点,该容器是专人专用的也就是说只能存一个 //展示左侧输入框的数据 showData = () => { const {input1} = this; console.log(this.myRef.current.value) alert(input1.value) } showData2 = () => { const { input2 } = this; alert(input2.value) } //ref就是把自身节点存入一个容器 //回调形式的ref //注释掉的内联样式的ref会被执行两次: //这是因为状态更改之后重新调用render,之前的内联函数执行完被释放了,所以这里的函数就是一个新函数了, //因为不确定之前释放的函数做了什么,所以要先清空,所以传了一个null,然后再传入自身节点 //但是无关紧要,所以大多数还是用内联 saveInput= (c)=> { this.input1 = c } render() { return ( <div> {/*<input ref={c=>this.input1 = c} type="text" placeholder="点击按钮提示数据" />*/} <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" /> <button ref="button100" onClick={this.showData}>点击按钮</button> <input onBlur={this.showData2} ref={c =>this.input2 = c} type="text" placeholder="失去焦点提示数据" /> <input ref={this.myRef} type="text"/> </div> ) } } ReactDOM.render(<Demo/>, document.getElementById("test")) </script>
<script type="text/babel"> //发生事件的元素刚好是要操作的元素就不要用ref //收集表单数据 // react没有vue的双向数据绑定,需要自己用onChange去写 //受控组件类似vue双向绑定,而且不用ref,所以一般用这种 class NotContral extends React.Component { state = { username: '', password: '' } //保存表单数据到状态中 //这就是函数的柯里化技术:两个函数里的dataType和event两个参数最后集中处理 saveFormData = (dataType)=>{ //render首次直接将saveFormData的返回值给onChange,也就是一个匿名函数, //当onChange触发时,调用的其实是这个匿名函数,所以react会传event给这个匿名函数 //这是个高阶函数 /* 高阶函数满足条件:(promise,setTimeOut,arr.map()) 1.若A函数接收的参数是一个函数,那么这个A就是高阶函数 2.若A函数,调用的返回值是一个函数,那么A就是高阶函数 函数的柯里化: 通过函数连续调用继续返回函数,实现多次接受参数最后统一处理的编码方式 */ return (event)=>{ console.log(dataType, event.target.value) this.setState([dataType], event.target.value) } } //不用柯里化的实现方式 saveFormData = (dataType, event)=>{ this.setState({[dataType]: event}) } submit = (event) => { event.preventDefault(); //阻止表单默认跳转操作 const { username, password } = this.state; console.log(username, password) } render() { return ( <form onSubmit={this.submit}> {/*不用柯里化*/} 用户名:<input type="text" onChange={event=>this.saveFormData('username', event.target.value)} name="username" placeholder="请输入用户名" /> {/*用柯里化*/} 用户名:<input type="text" onChange={this.saveFormData('username')} name="username" placeholder="请输入用户名" /> 密码:<input type="password" name="password" onChange={this.saveFormData('password')} placeholder="请输入密码" /> <button>登录</button> </form> ) } } ReactDOM.render(<NotContral />, document.getElementById('test')) </script>
。