React(一)——基本介绍和JSX

 

React基本介绍及js文件的引入,ReactDOM.render()渲染页面,防止XSS攻击,编程范式,JSX的使用/语法规则/注释/输出数据类型/在属性上使用表达式,JSX列表渲染及条件渲染。

1.react基本介绍

一个用于构建用户界面的JavaScript库。

1.1起源

`React` 起源于 `Facebook` 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,做出来以后,发现这套东西很好用,就在2013年5月开源了,随后越来越多人开始关注和使用 `React`,慢慢的 `React` 就成为了当前最流行的前端开发框架之一。

1.2特点

  • - `React` 采用了声明式编程范式,可以更加方便的构建 `UI` 应用
  • - 内部封装更加高效的与底层`DOM`进行交互的逻辑,提高性能的同时也能帮助我们更加专注于业务
  • - 可以很好的接纳其它框架或库与其进行配合

1.3React 全家桶

  • - `React` : 提供框架(库)核心功能,如 `组件`、`虚拟DOM` 、渲染等
  • - `create-react-app` : 脚手架,提供一套用于快速 构建和打包 `React` 项目的工具
  • - `react-router` : 基于 `React` 的路由库
  • - `redux、react-redux` : 状态管理库

2.React的加载引入

  • - 基于浏览器 <script> 的模式
  • - 基于自动化的集成环境模式

2.1基于浏览器 <script> 的模式

React.js 框架本身包含两个部分

  1. react.js:提供 React.js 核心功能代码,如:虚拟 dom,组件
  2. react-dom.js:提供了与浏览器交互的 DOM 功能,如:dom 渲染

引入自己下载的react.js和react-dom.js文件:

html:

<body>
    <div id="app"></div>
    <script src="./js/react.production.min.js"></script>
    <script src="./js/react-dom.production.min.js"></script>
    <script src="js/app.js"></script>
</body>

也可以引入通过 CDN 获得 React 和 ReactDOM 的 UMD 版本

开发环境:

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

上述版本仅用于开发环境,不适合用于生产环境。压缩优化后可用于生产的 React 版本可通过如下方式引用:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

通过 CDN 的方式引入 React,官方建议设置 crossorigin 属性,同时建议验证使用的 CDN 是否设置了 Access-Control-Allow-Origin: * HTTP 请求,这样能在 React 16 及以上的版本中有更好的错误处理体验

示例:

html:

<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="js/app.js"></script>
</body>

 JS:

ReactDOM.render(
    '<div>开课吧</div>',
     document.getElementById('app')
);

结果:发现会将整个内容以及标签全部渲染出来

原因:React内部是使用innerText而不是innerHTML进行渲染(为防止XSS攻击)

正确写法:需要使用React专属的JPX格式才可以进行渲染,且需要引入的JS使用text/babel类型及babel的JS文件,且通过babel进行渲染

<body>
<div id="app"></div>
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="js/app.js"></script>
</body>
ReactDOM.render(
    <div>开课吧</div>,
     document.getElementById('app')
);

注意:使用JPX格式进行渲染,是babel内部通过ajax去访问的页面,所以页面必须运行在服务器上才能正常访问。否则会报错:

解决:如果实在VSCode编辑其中可以下载插件,live server即可; 

2.2ReactDOM.render()方法解析

ReactDOM.render(element, container[, callback])

  • element:要渲染的内容
  • container:要渲染的内容存放容器(页面某个节点)
  • callback:渲染后的回调函数

2.3XSS注入攻击

为了有效的防止 `XSS` 注入攻击,`React DOM` 会在渲染的时候把内容(字符串)进行转义,所以字符串形式的标签是不会作为 `HTML` 标签进行处理的。

XSS攻击示例:通过表单的innerHTML方法会可以改变HTML上的各种标签,样式,JS等,极其不安全。

    <style>
    #app {
        width: 100px;
        height: 100px;
        background: red;
    }
    </style>
</head>
<body>
    <div id="app"></div>
    <script>
        document.querySelector("#app").innerHTML = '<style>#app {width: 100px;height: 100px;background:green;}</style>';
    </script>
</body>

3.编程范式

就是编程的一种模式,比较流行的一些编程范式:

  • - 命令式编程
  • - 声明式编程
  • - 函数式编程

3.1命令式编程

告诉计算机怎么做(How?) - 过程

在原生JavaScript中,UI的构建是使用了命令式的编程方式来完成的。

let shadow = this.attachShadow({mode: 'open'});
let style = document.createElement('style');

style.textContent = `span {color:red}`;

let span = document.createElement('span');

span.innerHTML = '我是自定义元素的内容';
span.classList.add('cred');

shadow.appendChild(style);
shadow.appendChild(span);

3.2声明式编程

告诉计算机我们要什么(What?) - 结果

如sql语句和HTML:

SELECT * FROM `USER` WHERE `gender`='男' ORDER BY `age` DESC;

上面的 SQL就是一个典型的声明式编程,告诉数据库,我要什么结果,至于怎么查询出来结果,排序如何实现的过程 SQL并不关心,由内部(底层)实现。

又如以下方法(此处也包括函数式编程):

['k',1,2,'k',true,'b'].filter(v => Number.isFinite(v)).map(v=>v*10).reduce((c, v)=>c + v, 0);

3.3React.js 中的声明式 UI

<span className="cred">我是自定义元素的内容</span>

4.DOM对象与Virtual DOM

4.1DOM 对象

DOM:文档对象模型,把文档(一堆字符,一堆有格式的字符)中的内容解析成JS中的对象格式,并且还提供许多的方法和特性来操作这些对象,同时对这些对象的操作还会同步反馈(更新)到这些对象对应的HTML中。

浏览器会把页面中的元素映射为 JavaScript 中的对象,在 JavaScript 中通过对这些对象的访问来获取页面中对应元素及其内容。同时,对这些对象进行某些操作,又会反馈到页面中对应的元素上面。

但是,原生 JavaScript DOM 对象内容和结构太复杂,有很多的特性是我们平时很少用到的,而且我们对对象的操作会立即反馈到页面(渲染),影响性能。因此react使用虚拟DOM。

html:

<body>
    <div id="app"></div>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="virtualDom.js"></script>
</body>
console.dir(document.querySelector("#app"));

 结果:发现原生DOM对象上有其所有的属性和对应的方法。

4.2虚拟 DOM

virtual DOM,参考原生 DOM 对象构建的一个对象,它的结构足够简单,同时优化渲染逻辑,减少变化带来的渲染性能影响。

HTML:

<body>
    <div id="app"></div>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="virtualDom.js"></script>
</body>

JSX:

// console.dir(document.querySelector("#app"));
const App = (
    <div>
        <h1>开课吧</h1>
        <p>web前端高级工程师</p>
    </div>
);
console.dir(App);
ReactDOM.render(
    App,
    document.querySelector("#app")
);

生成的 virtual DOM 结构如下:发现虚拟DOM下有props属性;props下面有children,children下包括所有的HTML结构;children又会有自己的props,props下依然有children,一直到最后没有内容。react后面的各种都是通过虚拟DOM进行操作。

5.JSX的使用

`JSX` 是一个基于 `JavaScript` + `XML` 的一个扩展语法。

  • - 它可以作为 `值` 使用
  • - 它并不是 `字符串`
  • - 它也不是 `HTML`
  • - 它可以配合 `JavaScript 表达式` 一起使用

需要引入babel库,内部是通过babel库去解析引入的app.js文件,再进行渲染的。使用babel库后,网络请求根本不会去加载自己引入的app.js文件,而是通过babel库中的ajax异步去加载,并且将加载过来的文件先通过babel进行解析成JS代码,再通过浏览器渲染出来。

js/app.js:jsx

ReactDOM.render(
    <div>开课吧</div>,
    document.getElementById('app')
);

引入JSX解析库:babel-standalone.js:在浏览器中处理 `JSX`

html:

<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel" src="js/app.js"></script>

> 注意:如果包含 `JSX` 或引入的代码中包含 `JSX` ,需要设置 `script` 标签的 `type` 属性为:`text/babel`

const App = (
    <div>
        <h1>开课吧</h1>
        <p>web前端高级工程师</p>
    </div>
);

6.JSX语法规则

6.1结构

每一个独立 `JSX` 结构的顶层有且只能有一个顶级父元素

jsx:

// 错误
const App = (
  <div>
    <h1>开课吧</h1>
    <p>web前端高级工程师</p>
  </div>
  <div>第二个</div>
);
// 正确
const App = (
  <div>
    <div>
      <h1>开课吧</h1>
      <p>web前端高级工程师</p>
    </div>
    <div>第二个</div>
  </div>

);

6.2在JSX中嵌入表达式

  • 在 `JXS` 中可以使用{表达式}嵌入`JavaScript`表达式

表达式:能产生值的一组代码的集合。

  • - 变量
  • - 算术运算
  • - 函数调用
  • - ……

if,while,for等是语句,JXS中不支持语句

示例:

HTML:

<body>
    <div id="app"></div>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
    <script type="text/babel" src="jsx.js"></script>
</body>

JS:

let name = "kaikeba";
let title = "welcome to kaikeba";
const App = (
    <div>
        <h1>{name}</h1>
        <p>{title}</p>
    </div>
);

ReactDOM.render(
    App,
    document.querySelector("#app")
);

结果:

  • 注意:分清楚表达式与语句的区别,if、for、while这些都是语句,JSX不支持语句
<h1>{if (true) {...}</h1> // 错误

7.JSX语法示例

在 `JSX` 中,表达式输出的内容类型与使用位置也有一些区别

7.1JSX中的注释

<div>
    {/*注释*/}
    {/*
            多行注释
    */}
</div>

7.2JSX表达式输出数据类型

  • - 字符串、数字:原样输出
  • - 数组:转成字符串。相当于使用数组.join(''),即使用空字符串而不是JS中默认的逗号连接
  • - 其它对象不能直接输出
  • - 布尔值、空、未定义会被忽略

数组:发现数组在JSX表达式中输出时,会以字符串形式对元素进行连接。

let arr = [2,7,3,4];
const App1 = (
    <div>
        {/*JSX输出数据类型:数组*/}
        <p>{arr}</p>
    </div>
);

ReactDOM.render(
    App1,
    document.querySelector("#app")
);

其他对象:直接输出会报错

{/*JSX输出数据类型:其他对象*/}
let obj = {name:'lmf',age:23};
const App2 = (
    <div>
        <p>{obj}</p>
    </div>
);

 

必须先对象转为数组,再输出:

//JSX对象不能直接输出,需要转为数组后才能输出
let obj = { name: 'lmf', age: 23 };
let zMouse = {
    name: '子鼠',
    gender: '男',
    skills: ['JavaScript', 'Node.js'],
    interests: ['音乐', '足球', '编程']
};

function getObj(obj){
    let arr = [];
    for(let k in obj){
    arr.push(<li key={k}>{k}:{
        Array.isArray(obj[k]) ? Object.keys(obj[k]).map(item => {
            return <ul><li key={item}>{obj[k][item]}</li></ul>
        }) : obj[k]
    }</li>)//注意此处使用了JSX语法,所以取值必须使用{k}
    }
    return arr;
}

const AppCont = (
    <div>
        <p>对象转为数组输出:{Object.keys(obj).map((k, v) => { return k + ': ' + obj[k] + '; ' })}</p>
        对象转为数组输出(先通过方法生成列表循环数组,再调用方法(注意也需要在{}中进行调用)进行显示):
        {getObj(zMouse)}

        对象循环列表输出:
        {/*注意:不能使用数组作为唯一key,['JavaScript', 'Node.js']没有可作为key的,[name:'JavaScript', remark:'较难']可将arr.name或arr.remark作为唯一key*/}
        <ul>
            {Object.keys(zMouse).map((k) => {
                return <li key={k}>{k}:{
                    Array.isArray(zMouse[k]) ? Object.keys(zMouse[k]).map(item => {
                        return <ul><li key={item}>{zMouse[k][item]}</li></ul>
                    }) : zMouse[k]
                }</li>

            })}
        </ul>
    </div>
);

ReactDOM.render(
    AppCont,
    document.querySelector("#app")
);

结果:

布尔值、空、未定义会被忽略:

{/*JSX输出数据类型:布尔值,空或未定义*/}
const App3 = (
    <div>
        true:{true}
        <br/>
        undefined:{undefined}
        <br/>
        空:{}
    </div>
);

ReactDOM.render(
    App3,
    document.querySelector("#app")
);

结果:

7.3在属性上使用表达式

JSX中的表达式也可以使用在属性上,但是使用的时候需要注意

  • 当在属性中使用{}的时候,不要使用引号包含

jsx:

let id = 'kaikeba';
// 错误
const App = (
    <div id="{id}"></div>
);
// 正确
const App = (
    <div id={id}></div>
);
  • JSX更偏向JavaScript, 所以对于一些特殊的属性,使用的是JavaScript中的属性名风格。如className

jsx:

// 错误
const App = (
    <div class="box1"></div>
);
// 正确
const App = (
    <div className="box1"></div>
);
  • 为了更加方便的操作元素的style,针对style这个属性有特殊的处理方式。style里的多个属性是以对象形式书写
const App = (
    <div style={{width: '100px', height: '100px', color:'red'}}></div>
);

注意:这里的两个{{}} ,外部的大括号表示的是前面说的表达式语法中的大括号里面的大括号是表示对象的大括号

注意:在属性上使用表达式时,可以直接输出对象格式的数据,但是直接在表达式中输出对象会报错

也可以使用以下方式:

let skin = {width: '100px', height: '100px', color:'red'};
const App = (
    <div style={skin}></div>
);

8.JSX列表渲染

列表渲染如果需要渲染一组数据,我们可以通过遍历(数组遍历、对象变量……)等操作,返回一组JSX。

**数据**:

let zMouse = {
  name: '子鼠',
  gender: '男',
  skills: ['JavaScript', 'Node.js'],
  interests: ['音乐', '足球', '编程']
};

8.1数组

function getSkills() {
  return (
    <ul>
      {zMouse.skills.map(skill => <li>{skill}</li>)}
    </ul>
  );
}
const App = (
    <div>{getSkills()}</div>
);

或者

const App = (
    <div>
       <ul>
          {zMouse.skills.map(skill => <li>{skill}</li>)}
       </ul>
    </div>
);

8.2对象

需要将对象转为数组

//JSX对象不能直接输出,需要转为数组后才能输出
let obj = { name: 'lmf', age: 23 };
let zMouse = {
    name: '子鼠',
    gender: '男',
    skills: ['JavaScript', 'Node.js'],
    interests: ['音乐', '足球', '编程']
};

function getObj(obj){
    let arr = [];
    for(let k in obj){
    arr.push(<li key={k}>{k}:{
        Array.isArray(obj[k]) ? Object.keys(obj[k]).map(item => {
            return <ul><li key={item}>{obj[k][item]}</li></ul>
        }) : obj[k]
    }</li>)//注意此处使用了JSX语法,所以取值必须使用{k}
    }
    return arr;
}

const AppCont = (
    <div>
        <p>对象转为数组输出:{Object.keys(obj).map((k, v) => { return k + ': ' + obj[k] + '; ' })}</p>
        对象转为数组输出(先通过方法生成列表循环数组,再调用方法(注意也需要在{}中进行调用)进行显示):
        {getObj(zMouse)}

        对象循环列表输出:
        {/*注意:不能使用数组作为唯一key,['JavaScript', 'Node.js']没有可作为key的,[name:'JavaScript', remark:'较难']可将arr.name或arr.remark作为唯一key*/}
        <ul>
            {Object.keys(zMouse).map((k) => {
                return <li key={k}>{k}:{
                    Array.isArray(zMouse[k]) ? Object.keys(zMouse[k]).map(item => {
                        return <ul><li key={item}>{zMouse[k][item]}</li></ul>
                    }) : zMouse[k]
                }</li>

            })}
        </ul>
    </div>
);

ReactDOM.render(
    AppCont,
    document.querySelector("#app")
);

或者

const App = (
    <div>
       <ul>
          {Object.keys(zMouse).map(key => <li>{key}</li>)}
       </ul>
    </div>
);

8.3key

默认情况下,React 从性能上考虑,会尽可能的复用结构,针对同组可变列表结构,为了避免出现某些方面的问题,通常会给每一个列表添加一个唯一的 key。这个key一般使用数据中的唯一标识id。

<ul>
  {[{id:1,name:'zMouse',id:2,name:'MT'}].map(user => <li key={user.id}>{user.name}</li>)}
</ul>

注意:key 的值不推荐使用数组的下标,因为数组下标没有和数据进行绑定。

9.JSX条件渲染

function moreInterests() {
    if (zMouse.interests.length > 2) {
        return <a href="#">更多</a>
    }
}

const App = (
    <div>
            爱好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {moreInterests()}
    </div>
);

9.1三元运算符

const App = (
        <div>
           爱好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {zMouse.interests.length > 2 ? <a href="#">更多</a> : null}
    </div>
);

9.2与或运算符

const App = (
        <div>
            爱好:{zMouse.interests.map(interest=>{
            return <span style={{marginRight:"10px"}}>{interest}</span>
        })}
        {zMouse.interests.length > 2 && <a href="#">更多</a>}
        {zMouse.interests.length < 4 || <a href="#">更多</a>}

    </div>

);
发布了95 篇原创文章 · 获赞 115 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_34569497/article/details/101444287