在我们刚一提到组件的时候就说过react
组件有三大属性,分别是state
,props
和refs
。经过前面十几个课时的学习,我们也终于学完了state
和props
。那么今天我们就正式开始学习最后一个组件属性refs
。
回顾
按照老规矩,开始这节课的内容之前要对上节课来做一个简单地回顾。
上节课我们结束了props
的学习。总结下来就是props
是一个只读的对象,可以批量从组件标签传入,可以利用prop-types
对props
的传入进行限制,构造器尽量省略,而且函数组件可以使用props
。
以上就是我们前节课的内容,接下来,我们正式开始学习有关refs
的课程。
refs
与事件处理
其实我们学习refs
的时候会伴随着事件处理一起来说,因为这二者之间的联系还挺密切,不过我们先来说一下refs
。
refs
是什么
我们都知道refs
是react
组件三大属性之一,但是这个东西到底是什么呢?我们通过一个小案例来看一下:
我们看见页面上现在有两个输入框。第一个输入框要求输入文字之后点击右侧的按钮然后弹窗提醒输入的内容,右边的第二个输入框则要求我们输入内容之后,输入框失去焦点时弹窗提示输入内容:
那么我们先一步一步来,我们先让页面上有这两个输入框和这个按钮,那么代码应该怎么编写?
我们来分析一下页面元素:
- 输入框
- 输入框中还有提示信息
- 按钮
那么输入框是不是要用<input>
?输入框中的提示信息不是要用placeholder
?这个要点要是忘了,大家就自行回去复习HTML
基础。按钮就简单了,就是<button>
。那么好我们来写代码
我们来看一下,这里为什么报红了啊?还记不记得早期课程中我们说过的所有标签都必须闭合。这里的input
标签是不是没闭合那我们就给改一下:
class Demo extends React.Component { render() { return( <div> <input type="text" placeholder="点击按钮提示"/> <button>点击弹窗</button> <input type="text" placeholder="失去焦点提示"/> </div> ); } } ReactDOM.render(<Demo/>, document.getElementById("test"));
大家看一下上面这段代码是不是已经对结构很熟悉了?创建类组件,类组件中必须写render
方法,render
方法中必须有return
,必须只有一个根节点,所以用div
标签封装起来。然后渲染组件到页面。好我们看一下页面:
页面已经出来了。但是我们点击按钮好像并没有用啊,失去焦点也没用啊。那肯定没用啊,我们按钮连onClick
都没给点击怎么可能有用呢?而且失去焦点的时间我们也没写肯定都是没有用的啊。那么我们就来开始吧,还是那句话别着急,一步步来,先给左侧这个组合中的按钮添加一个onClick
。
class Demo extends React.Component { showData = () => { console.log("clicked!"); } render() { return ( <div> <input type="text" placeholder="点击按钮提示" /> <button onClick={this.showData}>点击弹窗</button> <input type="text" placeholder="失去焦点提示" /> </div> ); } }
我们先看一下上面这段代码,通过前面的学习我觉得大家应该能看明白吧,我给按钮加了一个onClick
的时间监听,调用的方法是showData
,但是我们得定义showData
啊,不然报错说showData
没有定义啊。那么好,根据前面的课程学习,我们是不是用赋值语句而且写箭头函数?不写箭头函数就会导致this
指向丢失的问题。
但是我们的showData
方法里面就只写了一行打印。我们先来验证一下这样行不行,然后再继续。
控制台中可以看出我们的点击时间已经生效了。好了,那么我们的目的是打印这个玩意儿吗?不是啊,我们想要拿到输入框中的值啊.
但怎么拿?如果原生js
的话我们可以给输入框加个id
然后const i = document.getElementById(id)
然后再使用alert(i.value)
。这样当然是完成了我们的需求。但是我们是不是操作了真实DOM
啊?我们用react
,它的设计哲学是什么?各种操作都使用虚拟DOM
,仅仅只在渲染页面时才操作真实DOM
。那么我们在这里直接操作了真实DOM
那是不是有点不讲道理?
那么我们这么写?其实react
给我封装了相应的工具,那就是通过refs
,之前我们给input
标签id
属性,现在不用了,我们要用ref
属性来代替。可能有人要问,不是refs
吗?你这是不是写错了?不是,就是得写ref
,我们先别急往后看。
使用refs
我来问一个问题,我们这里的showData
方法中的this
指向的是谁?这个时候大家应该不会有任何迟疑直接就应该回答出来。这里的this
指向的是不是就是Demo
组件的实例对象?我们先不给input
加ref
标签,我们先来输出一下this
再来回顾一下this
上有什么:
我们发现控制台中打印的this
上有一个refs
我们也看见了props
和refs
都是空对象。那么这俩会不会是一个性质呢?
我们在渲染组件的时候,组件标签传什么,react
就会把我们传的东西收集成对象存放在props
里面,那么refs
会不会也一样?现在是空对象,那是因为我们什么都没传,那我们给input
标签加一个ref
属性试试
class Demo extends React.Component { showData = () => { console.log(this); } render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示" /> ... </div> ); } }
那我们看看这次this
中的refs
会是什么呢?
这次我们发现,现在的this
中的refs
已经有了一组key-value
,而且key
是我们之前传入的ref
属性的值,而value
是当前所处的节点,为啥我们传的是ref
,而this
上是refs
呢?大家可能也猜到了,复数呗,refs
可以收集存放多组key-value
。
我们看一下:
class Demo extends React.Component { showData = () => { console.log(this); } render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示" /> <button ref="button1" type="button" onClick={this.showData}>点击弹窗</button> <input ref="input2" type="text" placeholder="失去焦点提示" /> </div> ); } }
我在代码中给这几个标签都加上了ref
属性,那我们再来看this
这下refs
里面是不是就有了多组key-value
。这是不是和props
很像啊?那我们就继续往下写。
class Demo extends React.Component { showData = () => { console.log(this.refs.input1); } render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示" /> <button type="button" onClick={this.showData}>点击弹窗</button> <input type="text" placeholder="失去焦点提示" /> </div> ); } }
我们现在是不是还不打算给其他两个标签加ref
?我们目前先实现点击事件,失去焦点事件后面再说。而且从始至终是不是都不需要给按钮加ref
?那么我们收集到了ref
存放到refs
中之后,我们怎么用?refs
是不是在this
上?那么this.refs
能不能访问到?肯定可以的。然后refs
是不是一个对象?那么不就好办了嘛。这个是不是和props
几乎没有什么区别?那我们打印一下我们取到的是什么
我们看见这是不是我们写的input
标签?但是为什么这个标签里面没有ref
属性啊?我们回想一下HTML
的标签里面有ref
属性吗?从来就没有啊。ref
属性只是给react
用的一个标识。所以说我们给这个input
标签加了ref
标识为input1
,那么我们用this.refs.input1
获取到的就是这个标签所在的节点。
但是又有人要问了,那我们这里拿到的是不是虚拟DOM
啊?当然不是,我们在讲虚拟DOM
的时候就说过,虚拟DOM
只在react
内部使用,是我们开发人员拿不到的。这里其实是虚拟DOM
转成真实DOM
的一个input
标签所在的节点。也可以说这是一个真实DOM
。
那么我们接下来就简单了,我们都知道这是个真实DOM
了,那么我们按照真实DOM
的操作方法来做就行了啊:
class Demo extends React.Component { showData = () => { alert(this.refs.input1.value); } render() {return ...} }
那我们来看一下效果:
这下我就完成了点击按钮来弹窗展示输入框输入的值的功能了。
那么右侧的失去焦点弹窗展示输入框内容是不是就以此类推一下就可以了?
或许有人说失去焦点我们没写过啊,原生js
中失去焦点是不是onblur
?在react
中是啥?我们都知道onclick
到react
中要把Click
的首字母大写,那么onblur
依葫芦画瓢呗:
class Demo extends React.Component { showData = () => {...} blurData = () => { alert(this.refs.input2.value); } render() { return ( <div> <input ref="input1" type="text" placeholder="点击按钮提示" /> <button type="button" onClick={this.showData}>点击弹窗</button> <input ref="input2" onBlur={this.blurData} type="text" placeholder="失去焦点提示" /> </div> ); } }
我们看一下,onBlur
绑定一个方法blurData
,然后定义方法,在方法里面弹窗提醒this.refs.input2.value
,这样是不是就取到了ref="input2"
的节点,然后取到数据,弹窗展示出来。那我们来看一下具体效果:
这样,我们就完成了右侧输入框失去焦点自动弹窗展示输入框中内容的功能。
以上就是我们这节课的内容
总结
refs
是一个收集各个标签ref
属性来作为标识的一个对象refs
可以代替document.getElementById
方法来获取页面节点refs
可以配合事件处理来完成相应的功能需求。
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/string_refs/