React与vue.js的对比
组件化方面
什么是模块化:从 **代码** 的角度,去分析问题,把我们编程时候的业务逻辑,分割到不同的模块中来进行开发,这样能够**方便代码的重用**;
什么是组件化:从 **UI** 的角度,去分析问题,把一个页面,拆分为一些互不相干的小组件,随着我们项目的开发,我们手里的组件会越来越多,最后,我们如果要实现一个页面,可能直接把现有的组件拿过来进行拼接,就能快速得到一个完整的页面, 这样方**便了UI元素的重用**;**组件是元素的集合体**;
Vue是如何实现组件化的:
.vue 组件模板文件,浏览器不识别这样的.vue文件,所以,在运行前,会把 .vue 预先编译成真正的组件;
template: UI结构
script: 业务逻辑和数据
style: UI的样式
React如何实现组件化:
在React中实现组件化的时候,根本没有 像 .vue 这样的模板文件,而是,直接使用JS代码的形式,去创建任何你想要的组件;
React中的组件,都是直接在 js 文件中定义的;
React的组件,并没有把一个组件 拆分为 三部分(结构、样式、业务逻辑),而是全部使用JS来实现一个组件的;(也就是说:结构、样式、业务逻辑是混合在JS里面一起编写出来的)
React核心概念
DOM
DOM的本质:就是用JS表示的UI元素
虚拟DOM(Virtual Document Object Model)
为什么要实现虚拟DOM:
比如要实现下面的表格排序案例:
需求:实现一个点击表头,完成数据根据点击的列进行排序的功能
分析步骤:
首先,我们这些所有的列表中渲染出来的数据,都在浏览器的内存中,以一个数组的形式存在;当点击每一个表头的时候,为这每一个表头绑定点击事件,在事件的处理函数中:根据点击的列名,对数组中的每一项进行排序,最终,排序好的新数组,就是我们将要展示到页面上的数据;(这一步完成后,数组是最新的,页面老的,并没有被刷新)
当得到排序好的数组之后,应该把最新的数组,更新到页面中去:使用原生的for循环手动拼接每个tr字符串,append到页面中,使用jquery、使用前端模板引擎;当我们拼好字符串后,就可以把最新的html字符串替换到页面上
上述的实现思路所存在的性能问题:
只要数据发生了一点点变化,也会被强制重建整顿DOM树,这么做会导致很多元素的重绘和重排,导致性能浪费严重
如何解决上述问题:
只要实现按需要更新页面上的元素即可,只需要把修改的数据,所对应的DOM元素重新构建一下,其他没有变化的数据,所对应的DOM节点不需要被强制更新
如何实现上述的解决方案(如何按需更新页面上的元素)
需要拿到页面被更新前的内存中的DOM树,同时,还要拿到页面更新前,新渲染出来的内存DOM树,然后,对比这两颗新旧DOM树,只需要找到那些需要被重新创建和修改的元素即可,这样就能实现DOM的按需更新
如何拿到这两颗新旧DOM树
如果要拿到浏览器中的DOM树,那么,我们必须要调用浏览器提供的相关js的api才行,但是浏览器并没有提供这样的api,既然浏览器没有提供这样的api,那么我们需要自己模拟这两颗新旧DOM树
如何模拟新旧两颗DOM树(如何自己模拟一个DOM节点<p title="真的">这是一个段落</p>)
手动模拟DOM树的原理:使用js创建一个对象,用这个对象,来模拟每个DOM节点,然后在每个DOM节点中,又提供了类似于children这样的属性,来描述当前DOM的子节点,这样,当DOM节点形成了嵌套关系,就模拟出了一颗DOM树
var p = {
tagName : 'p',
attrs : {
title : '真的',
id : ''
},
children : [
'这是一个段落',
{
tagName : 'span',
children : [
'这是span'
]
}
]
}
虚拟DOM的本质:就是使用js对象来模拟DOM树
虚拟DOM的目的:为了实现DOM节点的高效更新
DOM和虚拟DOM的区别
DOM是由浏览器中的JS提供功能,所以我们只能人为的使用 浏览器提供的固定的API来操作DOM对象
虚拟DOM:并不是由浏览器提供的,而是我们手动模拟实现的,类似于浏览器中的DOM,但是有着本质的区别
Diff算法
tree diff:
新旧DOM树,逐层对比的方式,就叫做 tree diff,每当我们从前到后,把所有层的节点对比完后,必然能够找到那些 需要被更新的元素;
component diff:
在对比每一层的时候,组件之间的对比,叫做 component diff;当对比组件的时候,如果两个组件的类型相同,则暂时认为这个组件不需要被更新,如果组件的类型不同,则立即将旧组件移除,新建一个组件,替换到被移除的位置;
element diff:
在组件中,每个元素之间也要进行对比,那么,元素(a、span、div.....这种)级别的对比,叫做 element diff;
key:
key这个属性,可以把 页面上的 DOM节点 和 虚拟DOM中的对象,做一层关联关系;
React基本用法
安装两个包react和react-dom:
react 这个包,是专门用来创建React组件、组件生命周期等这些东西的;
react-dom 里面主要封装了和 DOM 操作相关的包,比如,要把 组件渲染到页面上
cnpm install react react-dom --save-dev
在项目中导入两个相关的包:
import React from 'react'
import ReactDOM from 'react-dom'
使用JS的创建虚拟DOM节点:
在 react 中,如要要创建 DOM 元素了,只能使用 React 提供的 JS API 来创建,不能【直接】像 Vue 中那样,手写 HTML 元素
React.createElement() 方法,用于创建 虚拟DOM 对象,它接收 3个及以上的参数
参数1: 是个字符串类型的参数,表示要创建的元素类型
参数2: 是一个属性对象,表示 创建的这个元素上,有哪些属性
参数3: 从第三个参数的位置开始,后面可以放好多的虚拟DOM对象,这写参数,表示当前元素的子节点
var myH1 = React.createElement('h1', null, '这是一个大大的H1')
var myDiv = React.createElement('div', { title: 'this is a div', id: 'mydiv' }, '这是一个div', myH1)
使用 ReactDOM 把元素渲染到页面指定的容器中:
ReactDOM.render('要渲染的虚拟DOM元素', '要渲染到页面上的哪个位置中')
注意: ReactDOM.render() 方法的第二个参数,和vue不一样,不接受 "#app" 这样的字符串,而是需要传递一个 原生的 DOM 对象
ReactDOM.render(myDiv, document.getElementById('app'))