[每周日-先行者课堂笔记] -- react版的倒计时实现

时间:2022-04-27
本文章向大家介绍[每周日-先行者课堂笔记] -- react版的倒计时实现,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

各位同学们大家好,今天是4月9号周日,今天我们继续来做“倒计时”这个前端组件。之前我们是使用原生js来实现的,其实更多的只是实现了功能。

这一次我们使用ReactJs来实现它。react本身就不做过多的介绍了,相信真心关注前端的小伙伴们不可能对它一无所知。只提一下它的重点吧,一虚拟dom;二是全组件化。

而我们在日常使用react的过程中,更多的是跟组件化这三个字打交道。一般来讲,组件就是指被封装好的,且有一定功能的ui零件。

而react的思考方式,就是把页面上的每一个部分都按组件来看待。简单来讲,就是每个div,在react中都可以被看做一个组件,然后把这些react编写的组件,像div嵌套那样,进行大组件套小组件的这种层层包装的形式,组装成整个ui页面。

新的开发方式会肯定有它的好处,就是模块之间的彻底分离。比之前的所谓mvc更加彻底。

另外老话重提,react组件三特征:可组合,可重用,可维护。

来看ui图,先一分析一下结构。其实结构很简单,就是div里有一个ul,ul里有三个li容器横向排列,每个li里有从上到下的label span 而已。

在我看来,如果前端新人对于react的组件概念不太好理解,不太容易分得清每个组件要包含哪些东西?

那么可以直接用div容器的概念来理解react的组件。因为它们不管它们在开发、生产环境是什么样的形式,落实到页面dom中,全都是dom节点了。所以开始的时候,可以反着来理解一下。

就说这个倒计时应用吧,在开发它的时候,你可以按着先页面,后js的顺序。也就是先用react来把页面结构生成出来,然后在再相应的页面组件中添加各种js程序。

//==============

首先把页面的结构先搭出来,新建一个目录,。。。新建个html文件,js,css目录,

js目录里放这三个文件:

react.js 、react-dom.js 和 Browser.js

然后在html中引用。

其中,react.js 是 React 的核心库,

react-dom.js 是提供与 DOM 相关的功能,

Browser.js 的作用是将 JSX 语法转为 JavaScript 语法

最后写一个 <script> 标签,注意它的 type 属性为 text/babel 。

<script type="text/babel">

这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。

凡是使用 JSX 的地方,都要加上 type="text/babel" 。

现在我们就可以开始写react了

回忆一下我们切静态页面的时候会怎么做?肯定是先搞个大的父容器出来,然后再在父容器中添加相应的各个子容器。

首先肯定得有个“根”节点做为最外层的父容器呀,那么,

  <body>
    <div id="timeWrap"></div>
  </body>

这个timewrap的div,它就是最外层的父容器。而我们刚才已经分析过,div里面就是ul,ul里面就是li,,,,

那么,用react生成的第一个组件类,就是ul,使用 React.createClass 生成第一个组件类:

//要记得react里的组件类,第一个字母要大写

var TimeWrapUl = React.createClass({
 render:function(){
 return <ul>...</ul>
 }
});

这里用到了 render 方法,该方法会返回一个React组件树,用来接受该组件树的变量名称必须首字母大写。并且该组件树只能有一个根节点,最终这棵组件树会被ReactDOM.render渲染成HTML标签。

这时的ul,它并不是一个真正的DOM节点,而是一个虚拟的DOM节点,这些节点就是一些标记之类的记号,只是React知道该如何处理它们。

ReactDOM.render(
  <TimeWrapUl />,
  document.getElementById('timeWrap')
);

按切页面的套路,接下来就该li了,

用 React.createClass 再来生成一个组件类,Day:

var Day = React.createClass({
  render:function(){
    return:<li></li>
  }
});

它里面要有li。

写好的Day这个组件类,怎么放呢?其实很简单,就是跟切页面的思路一样,就是放在ul里面就好,这样:

var TimeWrapUl = React.createClass({
  render: function() {
    return <ul>
  <Day />
    </ul>;
  }
});

接下来,把时,分,秒的都如此写出来,好了,到此时,页面结构搭完,就类似于静态页面切完了,该往里写js了。

//===================

按照一般的js开发思路,在写js之前 应该先搞一些初始值,然后开始加载 dom,

再搞一些function方法来修改操作这些值

当dom都加载好了,开始绑定事件,

然后再把这些值传递到“更新dom”的方法中。

//===================

而react它的特点之一,就是把组件看成一个状态机,有一个初始状态。

然后当“情况或条件”发生改变的时候,导致状态变化,然后重新渲染ui了。

而不能用以往操作dom的思路,不能想操作哪些,就去用id控制哪里

//===================

react中

初始化的方法: getInitialState (只会在组件初始化的时候调用一次)就是用来初始化状态的,这就相当于一般js开发之中的init()方法。

而传统前端开发中的“当dom加载完成”,在react中对应的,

// componentDidMount

就可以理解为,只会在组件渲染结束后调用一次

有点类似于window.onload

那么,一些要在dom加载之后才做的事情,应该放在它里面

我们可以通过this.setState()来修改状态。状态的每次修改都会出发render函数。

好啦,初始化,加载dom,修改状态都找到对应的方法了。

那么就这样,

在ul这个组件中添加相应的初始化方法 getInitialState

加载dom之后执行的方法 componentDidMount

//===================

getInitialState,用于定义初始状态,就是一个对象,

它可以通过this.state 属性读取

//===================

初始化完了,该加载dom了,用 componentDidMount 方法

在它里面写 this.setState() 来修改状态,触发 return 修改

为啥没变?

你得往Day这个组件里传数据啊,

我们需要给组件添加一个属性

组件的属性可以接受任意值,字符串、对象、函数等等都可以,

也就是说,基本可以随便命名,当然你不能乱写,差不多就行

写一个属性dayVal,

<Day dayVal = {this.state.day} />

为啥还没变?

//===================

因为Day这个组件类里,还没有写接收参数呢。

它也得有 初始化方法,getInitialState

然后还得有个接收参数的方法,它得用来显示日期呀,

因为状态改变了,它做为被加载的组件,得接受新的参数啊

需要使用,componentWillReceiveProps( object nextProps ) 方法

然后 this.setState() 修改状态,在Day中触发 render 修改,

在修改中用 this.state来获取属性

//===========

我们按着day的样式,把时,分,秒都这样写好。这样就是整个组件在初始化的时候给一个值,然后当dom加载完成之后给了另一个值,然后触发了render方法。

接下来我们就要使用setInterval方法,让这个过程不断的重复。这样计时器就Ok了。

把之前的倒计时js拿过来,就这样放这,间隔1000毫秒。

然后这个 this.setState 是不是应该放在setInterval里呀?这样才可以每隔一秒修改一次时分秒的值。

报错!!

说是this.setState is not a function,为啥?

因为在setInterval里,this的值变了。console.log看一下this,它的值变成了window,因为setInverval是window的方法

这有二种解决方法,

第一种,

我们需要一个绑定方法,bind(),许多同学可能以为它是react的。

但事实上,它是es5的方法,

参看,https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Function.prototype.bind()

bind()方法会创建一个新函数。当这个新函数被调用时,bind()的第一个参数将作为它运行时的 this,

bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。

其实很简单,就是把componentDidMount所对应的匿名函数的this,传到了 setInterval里面去,

其实这种情况我更喜欢这样做,

var _self...

//===========

到这一步,这个倒计时的react版本,基本就算是做完了吧。