网站的验证码怎么做,互联网宣传推广的基础架构,营销策划公司企业文化,怎样在百度上发布作品前置知识 类的回顾
通过class关键字定义一个类
类名首字母大写
class类有constructor构造器
new 一个类得到一个实例
类还有方法#xff0c;该方法也会在其原型上
static静态数据#xff0c;访问静态属性通过 类名.id
getter和setter getter#xff1a;定义一个属性该方法也会在其原型上
static静态数据访问静态属性通过 类名.id
getter和setter getter定义一个属性必须返回一个值通过 实例.属性 去进行访问相当于Vue中的computed即计算属性。在 react 的类组件中计算属性就是 getter 的写法 setter属性可以通过该属性去修改值 class Animal {static id 1;constructor(name){this.name name;}getName() {return this.name;}//getter获取类的名字get computedName() {return this.name Animal.id;}// setterset computedName(name){this.name name;}
}console.log(Animal.id); // 1let animal new Animal(zs);
console.log(animal); // zs
console.log(animal.getName()); // zs
console.log(animal.computedName); // zs1
animal.computedName ls;
console.log(animal.name); // ls
console.log(animal.computedName); // ls1
类的继承通过 extends、super 子类可以继承父类子类就会拥有父类的方法和属性等同时子类也可以重写父类的方法和定义属于自己的属性和方法
class Animal {static id 1;constructor(name){this.name name;}getName() {return this.name;}//getter获取类的名字get computedName() {return this.name Animal.id;}// setterset computedName(name){this.name name;}
}class Dog extends Animal {constructor(name){super(name)}getName(){return this.name 123}
}let dog new Dog(泰迪);
console.log(dog.name); // 泰迪
console.log(dog.getName()); // 泰迪 -- 泰迪123
dog.computedName 柯基;
console.log(dog.computedName);// 柯基1
console.log(dog.computedName);// 柯基1 this 指向
在普通函数中this指向window如果是严格模式则指向undefined
在类的构造函数中this指向实例对象
在对象的方法里this指向调用这个方法的对象
箭头函数中的this指向外层(父级)
改变this指向call、apply、bind call改变this指向后会立即执行直接传参 apply改变this指向后会立即执行通过数组传参 bind改变this指向后不会立即执行而是返回一个函数需手动调用直接传参
示例1
const obj {name: zs,getName(){return this.name}
}const obj1 {name: ls
}console.log(obj.name); // zs
console.log(obj.getName()); // zs
console.log(obj.getName.call(obj1)); // ls
console.log(obj.getName.apply(obj1)); // ls
console.log(obj.getName.bind(obj1)()); // lsconst obj {name: zs,getName(num,age){return this.name num age}
}const obj1 {name: ls
}console.log(obj.name); // zs
console.log(obj.getName()); // zs
console.log(obj.getName.call(obj1, 2,6)); // ls26
console.log(obj.getName.apply(obj1, [5,0])); // ls50
console.log(obj.getName.bind(obj1)(3,18)); // ls318 示例2
function Cat() {let showName function () {console.log(1);}return this;
}Cat.showName function(){console.log(2);
}Cat.prototype.showName function(){console.log(3);
}var showName function () {console.log(4);
}function showName() {console.log(5);
}Cat.showName(); // 2 访问的是函数的静态属性
showName(); // 4 函数优先提升var变量提升后赋值将原来的函数覆盖掉了
Cat().showName(); // 4 Cat()函数返回了this指向的是window全局var定义的变量是在window上的
new Cat.showName(); // 2 new 实例化的是Cat里面的静态属性 showName
new Cat().showName(); // 3 实例化的是 Cat 实例访问的是cat实例的方法showName() React 概述
官网地址React 官方中文文档目前前端最流行的是三大框架Vue、React、Angular React 简介 react是一个用于构建用户界面的 JavaScript 库
react官网(React)
react中文网(React 官方中文文档) React 是一个用于构建用户界面UI对咱们前端来说简单理解为HTML 页面的 JavaScript 库
Vue 是一个渐进式的 JavaScript 框架
如果从mvc的角度来看React仅仅是视图层V的解决方案。也就是只负责视图的渲染并非提供了完整了M和C的功能
react/react-dom/react-router/redux: 框架
React 起源于 Facebook 内部项目News Feed2011后又用来架设 Instagram 的网站2012并于 2013 年 5 月开源react介绍
React 是最流行的前端开发框架之一其他Vue、Angular 等等框架对比 react特点
声明式UI
你只需要描述UIHTML看起来是什么样的就跟写HTML一样
const jsx div classNameapph1Hello React! 动态数据变化:{count}/h1
/div
声明式对应的是命令式声明式关注的是what命令式关注的是how 组件化开发
组件是react中最重要的内容
组件用于表示页面中的部分内容
组合、复用多个组件就可以实现完整的页面功能 学习一次随处使用多平台适配
使用react/rect-dom可以开发Web应用
使用react/react-native可以开发移动端原生应用react-native RN 安卓 和 ios应用 flutter也可以做到
使用react可以开发VR虚拟现实应用react360 总结
声明式设计react采用声明范式能够轻松的描述应用
高效 react提供了虚拟DOM最大程度地减少了与DOM之间的交互
灵活react可以和任意的库进行搭配使用 虚拟DOM
在 react 中每个DOM对象都会有一个对应的虚拟DOM以js对象的方式描述的真实的DOM对象
div classNamecontainerh312/h3p45/p
/div{type: div,props: { className: container },children: [{type: h3,props: null,children: [{type: text,props: {textContent 12},}]
},{type: p,props: null,children: [{type: text,props: {textContent 45},}]}]
} 虚拟DOM如何提升效率
精准找出发生变化的DOM只更新变化的部分
在第一次创建DOM时就会给每个DOM对象创建虚拟DOM更新时就会更新虚DOM然后将更新的前后的虚拟DOM进行对比从而找到发生变化的部分将发生变化的部分更新到真实的DOM对象中从而达到性能提升 React 使用方式 原始方式使用
使用 react 必须要包含以下几个包
reactreact核心包react-dom与操作DOM相关功能的核心包(babel)babel-standalone由babel编译器提供的js文件可以将es6代码转换成es5代码babeljs官网Babel 中文文档 | Babel中文网 · Babel 中文文档 | Babel中文网jsx最终会转换成React.createElement的方式去创建模板jsx只是降低了开发难度 引入方式
CDN方式
直接下载到本地在引入
通过 npm 进行管理脚手架创建 基本示例
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlescript src./node_modules/react/umd/react.production.min.js/scriptscript src./node_modules/react-dom/umd/react-dom.production.min.js/scriptscript src./node_modules/babel-standalone/babel.min.js/script
/head
bodydiv idroot/divscriptlet template React.createElement(h1, null, hello react);let template2 React.createElement(h2, null, hello react2)let template3 React.createElement(h3, null, hello react3);let container React.createElement(div, null, [template, template2, template3]);// react18之前ReactDOM.render(template, document.getElementById(root));// react18之后// const root ReactDOM.createRoot(document.getElementById(root));// root.render(template2);/script
/body
/html
React.createElement创建react模板
ReactDOM.render将模板渲染到哪个标签上去 优化示例
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlescript src./node_modules/react/umd/react.production.min.js/scriptscript src./node_modules/react-dom/umd/react-dom.production.min.js/scriptscript src./node_modules/babel-standalone/babel.min.js/script
/head
bodydiv idroot/divscript typetext/babellet message hello world;function handlerMsg(){meaashe hello world2;// 在react中修改后默认不会重新自动渲染界面rootRender();}// react18之前ReactDOM.render(rootRender(), document.getElementById(root));// react18之后// const root ReactDOM.createRoot(document.getElementById(root));// root.render(rootRender());// 创建多个18以后// const root ReactDOM.createRoot(document.getElementById(app));// root.render(rootRender())function rootRender() {const container (divh1hello/h1h2hello2/h2h3 onClick{handlerMsg}{message}/h3/div);}// rootRender();/script
/body
/html 通过对比我们发现jsx的写法比上面写法更加的直观层次结构更加清晰写法更简单 组件化示例
!DOCTYPE html
html langen
headmeta charsetUTF-8meta http-equivX-UA-Compatible contentIEedgemeta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/titlescript src./node_modules/react/umd/react.production.min.js/scriptscript src./node_modules/react-dom/umd/react-dom.production.min.js/scriptscript src./node_modules/babel-standalone/babel.min.js/script
/head
bodydiv idroot/divscript typetext/babel// 类组件class App extends React.Component {// 数据constructor() {super()this.state {message: hello world}// this绑定this.handlerMsg this.handlerMsg.bind(this)}// 方法handlerMsg(){this.setState({message: hello world2,})}// 渲染render() {const { message } this.state;return {div// h3 onClick{this.handlerMsg.bind(this)}{message}/h3 // this绑定h3 onClick{this.handlerMsg}{message}/h3/div}}}// react18之前ReactDOM.render(App/, document.getElementById(root));// react18之后// const root ReactDOM.createRoot(document.getElementById(root));// root.render(App/);// 创建多个18以后// const root ReactDOM.createRoot(document.getElementById(app));// root.render(App/)/script
/body
/html 基本步骤
使用步骤
- 导入react和react-dom
- 创建react元素(虚拟DOM)
- 渲染react元素到页面中 导入react和react-dom
// 导入react和react-dom
import React from react
import ReactDOM from react-dom 创建react元素
// 创建元素
const title React.createElement(h1, null, hello react) 渲染react元素到页面
// 渲染react元素
ReactDOM.render(title, document.getElementById(root)) 脚手架方式使用 React 脚手架的介绍
脚手架为了保证各施工过程顺利进行而搭设的工作平台
对于前端项目开发来说脚手架是为了保证前端项目开发过程顺利进行而搭设的开发平台
脚手架的意义 现代的前端开发日趋成熟需要依赖于各种工具比如webpack、babel、eslint、sass/less/postcss等 工具配置繁琐、重复各项目之间的配置大同小异 开发阶段、项目发布配置不同 项目开始前帮你搭好架子省去繁琐的 webpack 配置 项目开发时热更新、格式化代码、git 提交时自动校验代码格式等 项目发布时一键自动打包包括代码压缩、优化、按需加载等 使用 React 脚手架创建项目
首先确保已经安装了 nodejs
其次 npm 版本要大于 5.2
然后通过 npm 安装 npm i -g create-react-app create-react-app --version 检测安装的版本 create-react-app 项目名称 安装react项目需要注意的是在创建react项目给项目命名的时候不允许有大写字母
或者直接通过以下命令npx create-react-app react-basic(项目名称)创建react项目 npx create-react-app react-demo --template typescript npx create-react-app 是固定命令create-react-app 是 React 脚手架的名称 react-basic 表示项目名称可以修改 npm create vitelatest my-react-app -- --template react-ts参考地址https://cn.vitejs.dev/guide/ 安装好react项目后可以运行以下命令npm i prettier eslint-config-prettier esli nt-plugin-prettier --save-dev 来安装 prettier 和 eslint 来进行管理代码安装完成后需要做以下配置
// .eslinttrc.js
extends: [plugin:prettier/recommended // 新增并且在 vscode 里安装 prettier 插件
]// 在 package.json 文件里新增以下代码并且运行 npm format
scripts: {format: prettier --write src/**/*.(js|ts|jsx|tsx)
},// 在项目根目录下新建 .vscode 目录在该目录下新建 settings.json
// 目的就是告诉vscode在我保存文件的时候就去帮我自动运行 npm format而不用自己每次都去手动运行{editor.codeActionsOnSave: {source.fixAll.eslint: true,}}// 在项目根目录下新建 .prettierrc.js 进行配置自己的一些规则
module.exports {// 箭头函数只有一个参数的时候可以忽略括号arrowParens: avoid,// 括号内部不要出现空格bracketSpacing: true,// 行结束符使用 Unix 格式endOfLine: lf,// true: Put on the last line instead of at a new linejsxBracketSameLine: false,// 行宽printWidth: 100,// 换行方式proseWrap: preserve,// 分号semi: false,// 使用单引号singleQuote: true,// 缩进tabWidth: 2,// 使用 tab 缩进useTabs: false,// 后置逗号多行对象、数组在最后一行增加逗号trailingComma: es5,parser: typescript,
}
启动项目yarn start or npm start
npx 是 npm v5.2 版本新添加的命令用来简化 npm 中工具包的使用 原始1 全局安装npm i -g create-react-app 2 再通过脚手架的命令来创建 React 项目 现在npx 调用最新的 create-react-app 直接创建 React 项目 项目目录结构说明和调整
README.md说明文档
package.json对整个应用程序的描述包括应用名称、版本号、一些依赖包、以及项目的启动、打包等
public favicon.ico应用程序顶部的icon图标 index.html相当于html模板文件react最终会将模板挂载到html中的div元素上即应用程序的入口文件 logo192.png被在mainfest.json中使用 logo512.png被在mainfest.json中使用 mainfest.json和 web app 配置相关 robots.txt指定搜索引擎可以或者无法爬取哪些文件
src assets存放一些静态资源比如css、图片等 components存放项目中的一些自定义组件 App.cssApp组件相关的样式 App.js项目的根组件相当于vue中的app.vue App.test.jsApp组件的测试代码文件 Index.css全局样式文件 index.js项目的入口文件相当于vue中的main.js logo.svg启动项目所看到的图标 reportWebVitals.js setupTests.js测试初始化文件
npm run start启动项目开服
npm run build项目打包生产包
npm run eject项目中的一些配置被隐藏起来了通过这个命令可以将配置文件反编译到项目中从而获得配置的权利这个操作是不可逆的一旦编译出来就无法编译回去一般来说不会执行这个命令我们会通过其他方式去修改配置。
说明 src 目录是我们写代码进行项目开发的目录 查看 package.json 两个核心库react、react-dom脚手架已经帮我们安装好我们直接用即可
调整参考 删除 src 目录下的所有文件创建 index.js 文件作为项目的入口文件在这个文件中写 React 代码即可 PWA
PWA全称 Progressive Web App即渐进式WEB应用一个PWA应用首先的一个网页可以通过Web技术编写出一个网页应用随后添加上App Manifest和Service Worker来实现PWA安装和离线等功能这种Web存在的形式我们称之为Web App PWA解决了哪些问题
可以添加至主屏幕点击主屏幕图标可以实现启动动画以及隐藏地址栏
实现离线缓存功能即使用户手机没有网络依然可以使用一些离线功能
实现了消息推送
等等一系列类似于 Native App 相关的功能 安装调试工具
方式1
打开github获取到插件项目并现在到本地。 插件的地址为https://github.com/facebook/react-devtools/tree/v3从这个地址里面找到DownloadZIP将项目现在到本地。 解压项目并安装依赖。 下载的zip文件解压到本地的目类里面。接着进入react-devtools-3目录在控制台使用npm install命令将当前工程的依赖现在到本地。
指定命令打包生成插件 再进入到react-devtools-3\shells\chrome切换到chrome目录下运行node build.js当前目录下会生成build目录 这个build目录下的unpacked目录就是chrome中所需react-devtools的工具扩展程序包。 打开chrome浏览器配置插件 打开谷歌浏览器网址输入chrome://extensions/选择加载已解压的程序选择我们上一步生成的unpacked文件夹这样就把插件安装成功。 这个时候你在chrome加载插件栏里面就可以看到React Developer Tools插件。 接着我们运行代码就可以在浏览器中选择react来查看组件。 方式2
克隆代码到本地
git clone https://github.com/facebook/react-devtools.git 切换到v3分支
git checkout -b v3 origin/v3 安装依赖
yarn 进入shells\chrome下
node build 在谷歌浏览器的扩展程序中添加shells\chrome\build\unpacked文件夹 方式3
如果可以访问外网的话可以在谷歌浏览器的谷歌商店里直接进行下载安装即可 VSCode代码片段配置
我们在前面练习React的过程中有些代码片段是需要经常写的我们在VSCode中我们可以生成一个代码片段方便我们快速生成 VSCode中的代码片段有固定的格式所以我们一般会借助于一个在线工具来完成 具体的步骤如下
第一步复制自己需要生成代码片段的代码
第二步https://snippet-generator.app/在该网站中生成代码片段
第三步在VSCode中配置代码片段 JSX语法
时下虽然接入 JSX 语法的框架React、Vue越来越多但与之缘分最深的毫无疑问仍然是 React。2013 年当 React 带着 JSX 横空出世时社区曾对 JSX 有过不少的争议但如今越来越多的人面对 JSX 都要说上一句“真香”典型的“真香”系列。 什么是 JSX
JSX 是一个 JavaScript 的语法扩展类似于模板语法或者说是一个类似于 XML 的 ECMAScript 语法扩展并且具备 JavaScript 的全部功能。网络标签语言有两种HTML、XML
HTML是网页的布局更多的用语内容的呈现
XML可扩展的标签原因可以写任意的标签核心功能是用于数据的传输
JSXJavaScriptXML是JavaScript和XML的结合可以说是JavaScript的一种扩展语法可以在jsx中写js代码也可以写html中DOM元素在jsx中拥有js的所有的语法。
不同于Vue中的模块语法无需去专门学习模块语法的一些指令比如v-for、v-if、v-else、v-bind...
与javascript的语法很接近 使用jsx语法的特点
jsx执行更快因为它在编译成JavaScript代码后进行了优化
jsx是类型安全的在编译过程中就可以发现错误可以防止注入攻击
使用jsx编写代码更加的简单快捷
只能有一个根元素 JSX的基本使用 JSX 语法是如何在 JavaScript 中生效的
React
在 React 框架中JSX 的语法是如何在 JavaScript 中生效的呢React 官网给出的解释是JSX 会被编译为 React.createElement() React.createElement() 将返回一个叫作“React Element”的 JS 对象
对于 JSX 的编译是由 Babel 来完成的。
Babel 是一个工具链主要用于将采用 ECMAScript 2015 语法编写的代码转换为向后兼容的 JavaScript 语法以便能够运行在当前和旧版本的浏览器或其他环境中。
当然 Babel 也具备将 JSX 转换为 JS 的能力
其实如果仔细看发现 JSX 更像是一种语法糖通过类似模板语法的描述方式描述函数对象。
其实在 React 中并不会强制使用 JSX 语法我们也可以使用 React.createElement 函数 在采用 JSX 之后这段代码会这样写 通过对比发现在实际功能效果一致的前提下JSX 代码层次分明、嵌套关系清晰而 React.createElement 代码则给人一种非常混乱的“杂糅感”这样的代码不仅读起来不友好写起来也费劲。
JSX 语法写出来的代码更为的简洁而且代码结构层次更加的清晰。
JSX 语法糖允许我们开发人员像写 HTML 一样来写我们的 JS 代码。在降低学习成本的同时还提升了我们的研发效率和研发体验。 Vue
当然在 Vue 框架中也不例外的可以使用 JSX 语法虽然 Vue 默认推荐的还是模板。
为什么默认推荐的模板语法引用一段 Vue 官网的原话如下
任何合乎规范的 HTML 都是合法的 Vue 模板这也带来了一些特有的优势
对于很多习惯了 HTML 的开发者来说模板比起 JSX 读写起来更自然。这里当然有主观偏好的成分但如果这种区别会导致开发效率的提升那么它就有客观的价值存在。基于 HTML 的模板使得将已有的应用逐步迁移到 Vue 更为容易。这也使得设计师和新人开发者更容易理解和参与到项目中。你甚至可以使用其他模板预处理器比如 Pug 来书写 Vue 的模板。
有些开发者认为模板意味着需要学习额外的 DSL (Domain-Specific Language 领域特定语言) 才能进行开发——我们认为这种区别是比较肤浅的。首先JSX 并不是没有学习成本的——它是基于 JS 之上的一套额外语法。同时正如同熟悉 JS 的人学习 JSX 会很容易一样熟悉 HTML 的人学习 Vue 的模板语法也是很容易的。最后DSL 的存在使得我们可以让开发者用更少的代码做更多的事比如 v-on 的各种修饰符在 JSX 中实现对应的功能会需要多得多的代码。
更抽象一点来看我们可以把组件区分为两类一类是偏视图表现的 (presentational)一类则是偏逻辑的 (logical)。我们推荐在前者中使用模板在后者中使用 JSX 或渲染函数。这两类组件的比例会根据应用类型的不同有所变化但整体来说我们发现表现类的组件远远多于逻辑类组件。
例如有这样一段模板语法。 使用 JSX 语法会写成这样。 转换为 createElement 转换的 JS 就变成了这样。 但是不管是模板语法还是 JSX 语法都不会得到浏览器纯天然的支持这些语法最后都会被编译成相应的 h 函数createElement函数不泛指所有版本在不同版本有差异最后变成 JS 对象这里的编译也是和 React 一样使用的 Babel 插件来完成的。
不管是 React 推崇的 JSX 语法还是 Vue 默认的模板语法目的都是为了让我们写出来的代码更为的简洁而且代码接口层次更加的清晰。在降低学习成本的同时还提升了我们的研发效率和研发体验。
读到这里相信你已经充分理解了“JSX 是 JavaScript 的一种语法扩展它和模板语言很接近并且具备 JavaScript 的全部功能。”这一定义背后的深意。
不管是 React 还是 Vue 我们都提到了一个函数 createElement这个函数就是将我们的 JSX 映射为 DOM的。 JSX 是如何映射为 DOM 的起底 createElement 源码
对于 creatElement 源码的分析我们也分 React 和 Vue 来为大家解读。
源码分析的具体版本没有必要去过于详细的讨论因为不管是 React 还是 Vue 对于在实现 createElement 上在不同版本差别不大。
React createElement 函数有 3 个入参这 3 个入参包含了我们在创建一个 React 元素的全部信息。
type用于标识节点的类型。可以是原生态的 div 、span 这样的 HTML 标签也可以是 React 组件还可以是 React fragment空元素。config一个对象组件所有的属性不包含默认的一些属性都会以键值对的形式存储在 config 对象中。children泛指第二个参数后的所有参数它记录的是组件标签之间嵌套的内容也就是所谓的“子节点”“子元素”。 从源码角度来看createElement 函数就是将开发时研发人员写的数据、属性、参数做一层格式化转化为 React 好理解的参数然后交付给 ReactElement 来实现元素创建。
接下来我们来看看 ReactElement 函数 源码异常的简单也就是对 createElement 函数转换的参数在进行一次处理包装进 element 对象中返给开发者。如果你试过将这个返回 ReactElement 进行输出你会发现有没有很熟悉的感觉没错这就是我们老生常谈的「虚拟 DOM」JavaScript 对象对 DOM 的描述。
最后通过 ReactDOM.render 方法将虚拟DOM 渲染到指定的容器里面。 Vue
vue2
我们在来看看 Vue 是如何映射 DOM 的。 createElement 函数就是对 _createElement 函数的一个封装它允许传入的参数更加灵活在处理这些参数后调用真正创建 VNode 的函数 _createElement _createElement 方法有 5 个参数:
context 表示 VNode 的上下文环境。tag 表示标签它可以是一个字符串也可以是一个 Component。data 表示 VNode 的数据。children 表示当前 VNode 的子节点它是任意类型的它接下来需要被规范为标准的 VNode 数组。normalizationType 表示子节点规范的类型类型不同规范的方法也就不一样它主要是参考 render 函数是编译生成的还是用户手写的。
_createElement 实现内容略多这里就不详细分析了反正最后都会创建一个 VNode 每个 VNode 有 childrenchildren 每个元素也是一个 VNode这样就形成了一个 VNode Tree它很好的描述了我们的 DOM Tree。 当 VNode 创建好之后就下来就是把 VNode 渲染成一个真实的 DOM 并渲染出来。这个过程是通过 vm._update 完成的。Vue 的 _update 是实例的一个私有方法它被调用的时机有 2 个一个是首次渲染一个是数据更新的时候我们这里只看首次渲染当调用 _update 时核心就是调用 vm.patch 方法。
patch这个方法实际上在不同的平台比如 web 和 weex 上的定义是不一样的
引入一段代码来看看具体实现。 在 vm._update 的方法里是这么调用 patch 方法的 首次渲染:
$el 对应的就是 id 为 app 的 DOM 元素。vnode 对应的是 render 函数通过 createElement 函数创建的 虚拟 DOM。hydrating 在非服务端渲染情况下为 false。
确认首次渲染的参数之后我们再来看看 patch 的执行过程。一段又臭又长的源码。 在首次渲染时由于我们传入的 oldVnode id 为 app 的 DOM 元素 实际上是一个 DOM container接下来又通过 emptyNodeAt 方法把 oldVnode 转换成 VNode 对象然后再调用 createElm 方法通过虚拟节点创建真实的 DOM 并插入到它的父节点中。 通过起底 React 和 Vue 的 createElement 源码分析了 JSX 是如何映射为真实 DOM 的实现思路的整体方向都是一样的。所以说优秀的框架大家都在相互借鉴相互学习。 总结
React 的设计初衷是「关注点分离」React 本身的关注基本单位是组件在组件内部高内聚组件之间低耦合。而模板语法做不到。并且 JSX 并不会引入太多的新的概念。 也可以看出 React 代码更简洁更具有可读性更贴近 HTML。通过对比多种方案发现 JSX 本身具备他独享的优势JSX 语法写出来的代码更为的简洁而且代码结构层次更加的清晰。JSX 语法糖允许我们开发人员像写 HTML 一样来写我们的 JS 代码。在降低学习成本的同时还提升了我们的研发效率和研发体验。并且JSX 本身没有太多的语法也不期待引入更多的标准。实际上在 16 年的时候JSX 公布过 2.0 的建设计划与小部分新特性但很快被 Facebook 放弃掉了。整个计划在公布不到两个月的时间里便停掉了。其中一个原因是 JSX 的设计初衷即并不希望引入太多的标准也不期望 JSX 加入浏览器或者 ECMAScript 标准。 createElement的问题
繁琐不简洁
不直观无法一眼看出所描述的结构
不优雅开发体验不好 类组件
App.js
import ClassHello from ./components/classHellofunction App() {return (div classNameAppClassHello //div);
}export default App; classHello.jsx
import React, { Component } from reactexport default class classHello extends Component {// 定义变量constructor(props){super(props)this.state {message: hello}}// 方法--更改变量handlerMsg () {this.setState({message: hello react})}// 渲染函数render() {return (divp{this.state.message}/pbutton onClick{this.handlerMsg}更改/button/div)}
} JSX注意点
只有在脚手架中才能使用jsx语法 因为JSX需要经过babel的编译处理才能在浏览器中使用。脚手架中已经默认有了这个配置。
JSX必须要有一个根节点 / React.Fragment/React.Fragment只有一个根节点
JSX可以是单标签页可以是双标签单标签节点的元素需要使用/结束
JSX中语法更接近与JavaScript class className for htmlFor
JSX可以换行如果JSX有多行推荐使用()包裹JSX防止自动插入分号的bug
import React, { PureComponent } from reactexport default class demoClassComponent extends PureComponent {constructor() {super()this.state {}}render() {return (divp/p/div)}
} 使用prettier插件格式化react代码
安装插件 添加prettier的配置
// 保存到额时候用使用prettier进行格式化
editor.formatOnSave: true,
// 不要有分号
prettier.semi: false,
// 使用单引号
prettier.singleQuote: true,
// 默认使用prittier作为格式化工具
editor.defaultFormatter: esbenp.prettier-vscode, 嵌入JavaScript语句
在jsx中可以在{}来使用插入js表达式
在jsx中要嵌入js表达式使用单花括号{} 那么也就意味着在单花括号中可以写js表达式
let title 我是标题;function App() {return (div{title}/div);
}export default App; JSX嵌入变量作为子元素 当变量是Number、String、Array类型时可以直接使用
当变量是null、Boolean、undefined类型时内容为空。如果希望可以显示null、Boolean、undefined那么需要转换成字符串可以利用toString、空字符串拼接的方式等
Object类型不能直接作为子元素会报错 Objects are not valid as a React可以通过 p{obj.message}/p
p{Objct.keys(obj)[0]}/p
... 嵌入算数表达式
可以在jsx嵌入表达式中写算数表达式包括加减乘除
let num1 1;
let num2 2;function App() {return (div{num1 num2}/div);
}export default App; 嵌入条件表达式
在jsx的嵌入表达式中条件判断语句只能写三目运算符不能写if/else、switch/case条件判断语句一旦写上条件判断语句后会报错
let age 18function App() {return (div{age 18 ? 成年 : 未成年}/div);
}export default App; 嵌入函数表达式
在jsx中可以将函数直接运行。
let age 17function isAdult() {if (age 18) {return 成年} else {return 未成年}
}function App() {return (div{isAdult()}/div);
}export default App; 嵌入对象表达式
实例1
let user {name: 张三,age: 20
}function App() {return (div{user}/div);
}export default App;
在jsx嵌入表达式中直接渲染对象数据会报错报错如下 正确方式应该将对象中的每个数据进行渲染而不是渲染整个对象
let user {name: 张三,age: 20
}function App() {return (div姓名{user.name}br /年龄{user.age}/div);
}
export default App; 实例2
import React, { Component } from react;export default class demo extends Component {constructor(props) {super(props);this.state {message: welcome,obj: {name: zs,age: 14,},};}handleMsg () {this.setState({message: welcome to react18,});};render() {return (divp姓名{this.state.obj.name}/pp年龄{this.state.obj.age}/pp{this.state.message}/pbutton onClick{this.handleMsg}更改/button/div);}
} 嵌入数组表达式
数组有点特殊可以直接放入进行渲染通常在元素中循环渲染一个数组用.map相当于vue中的v-for 实例1(推荐写法)
// let students [p张三/p, p李四/p, p王五/p];
let students [张三, 李四, 王五]function App() {return (div{students.map(item {return p key{item}{item}/p})}/div);
}export default App; 实例2
你也可以用其他方式去实现
// let students [p张三/p, p李四/p, p王五/p];
let students [张三, 李四, 王五]function getStudents() {let res [];students.forEach(item {res.push(p key{item}{item}/p);});return res;
}function App() {return (div{getStudents()}/div);
}export default App;
但是我们推荐使用.map方式 实例3
import React, { Component } from react;export default class demo extends Component {constructor(props) {super(props);this.state {array: [张三, 李四, 王五],array2: [{ id: 1, name: Item 1 },{ id: 2, name: Item 2 },{ id: 3, name: Item 3 }]};}// 方式一handleArrayInfo () {// setState 方法只能用于更新对象中的属性而不能直接更新数组中的某个元素const newArray [...this.state.array]; // 创建一个新的数组newArray[0] 星期二;this.state.array newArray;this.forceUpdate(); // 强制重新渲染组件};// 方式二updateArrayItem (id, newName) {// 复制原数组const newArray [...this.state.array2];// 查找要更新的元素索引const index newArray.findIndex(item item.id id);// 更新元素的属性值if (index ! -1) {newArray[index].name newName;// 使用 setState 更新组件状态this.setState({ array2: newArray });}};render() {return (divdiv{this.state.array.map((item) {return p key{item}{item}/p;})}/divbutton onClick{this.handleArrayInfo}更改值/buttondiv{this.state.array2.map((item) {return p key{item.id}{item.name}/p;})}/divbutton onClick{() this.updateArrayItem(2, New Item 2)}Update Item 2/button/div);}
} 防止注入攻击
let str p我是p标签/plet value {__html: str
}function App() {return (div dangerouslySetInnerHTML{value}/div);
}export default App;
在jsx中字符串里面的标签不会被解析成真实的DOM元素而是当做字符串进行渲染如果你要将字符串中的标签解析成真实的DOM元素你需要创建一个对象
let value {__html: str
}
其中__html字段是固定的
创建完毕后需要在元素上给一个属性dangerouslySetInnerHTML去进行解析 JSX中的注释
{/* 这是jsx中的注释 */} 推荐快键键 ctrl /
不要出现语句比如if for
div classNamecolor bg-color{/* {title} */}
/div JSX中的属性绑定
比如元素会有 title 属性
比如 img 元素的 src属性
比如 a 元素的 href 属性
比如元素的 class(className) 属性或者是 style 属性
......
import React, { PureComponent } from reactexport default class demoClassComponent extends PureComponent {constructor() {super()this.state {title: hello world,imgUrl: https://xxxx,alttitle: 图片,hrefUrl: https://www.baidu.com/,isActive: true,}}render() {const { title, imgUrl, alttitle, hrefUrl, isActive } this.stateconst className adc vdc ${isActive ? active1 : }const classList [adc, fvb]if (isActive) classList.push(active2)return (divh2 title{title}{title}/h2img src{imgUrl} alt{alttitle} /a href{hrefUrl}百度一下/a{/* 动态class */}p className{abc cba ${isActive ? active : }}我是p标签/pp className{className}我是p1标签/pp className{classList.join( )}我是p2标签/p{/* 动态style */}p style{{ color: red, fontSize: 30px }}哈哈哈/p/div)}
} 条件渲染
在react中一切都是javascript所以条件渲染完全是通过js来控制的 if/else
通过判断if/else控制
const isLoding false
const loadData () {if (isLoding) {return div数据加载中...../div} else {return div数据加载完成此处显示加载后的数据/div}
}const title div条件渲染{loadData()}/div 三元运算符
通过三元运算符控制
const isLoding false
const loadData () {return isLoding ? (div数据加载中...../div) : (div数据加载完成此处显示加载后的数据/div)
} 逻辑运算符
逻辑运算符
const isLoding false
const loadData () {return isLoding div加载中.../div
}const title div条件渲染{loadData()}/div
# 应用场景当某个值有可能为 undefined 时使用 进行条件判断 模拟v-show
模拟v-show
import React, { Component } from react;class classHello extends Component {constructor(){super()this.state {msg: hello,isShow: true}}changeShow () {this.setState({isShow: !this.state.isShow})}render() {const {isShow, msg} this.statereturn (divh3类组件/h3button onClick{() this.changeShow()}切换/buttondiv{isShow h2{msg}/h2}p style{{display: isShow ? block : none}}123/p/div/div);}
}export default classHello; vscode配置自动补全
// 当按tab键的时候会自动提示
emmet.triggerExpansionOnTab: true,
emmet.showAbbreviationSuggestions: true,
// jsx的提示
emmet.includeLanguages: {javascript: javascriptreact
} 列表渲染
我们经常需要遍历一个数组来重复渲染一段结构
在react中通过map方法进行列表的渲染 for循环
for循环
const songs [温柔, 倔强, 私奔到月球]
const songItems []
for(let i 0; i songs.length; i){const movie songs[i]const liEl li{movie}/lisongItems.push(liEl)
}const dv (divul{songItems}/ul/div
) map
map方式---推荐
const songs [温柔, 倔强, 私奔到月球]const list songs.map(song li{song}/li)const dv (divul{list}/ul/div
) map--直接在JSX中渲染--推荐
const songs [温柔, 倔强, 私奔到月球]const dv (divul{songs.map(song li{song}/li)}/ul/div
) key属性的使用
key属性的使用
const dv (divul{songs.map(song (li key{song}{song}/li))}/ul/div
)
注意
列表渲染时应该给重复渲染的元素添加key属性key属性的值要保证唯一
key值避免使用index下标因为下标会发生改变 JSX的本质
实际上jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖
所有的jsx最终都会被转换成React.createElement的函数调用
可以在babel官网中快速查看转换的过程Babel · The compiler for next generation JavaScript createElement需要传递三个参数
参数一type
当前ReactElement的类型
如果是标签元素那么就使用字符串表示 “div”
如果是组件元素那么就直接使用组件的名称 参数二config
所有jsx中的属性都在config中以对象的属性和值的形式存储
比如传入className作为元素的class 参数三children
存放在标签中的内容以children数组的方式进行存储
当然如果是多个元素呢React内部有对它们进行处理处理的源码在下方 购物车案例
import React, { PureComponent } from reactexport default class demoClassComponent extends PureComponent {constructor() {super()this.state {books: [{id: 1,name: 《算法导论》,date: 2023-10-21,price: 65.0,count: 3,},{id: 2,name: 《javaScript编程艺术》,date: 2023-10-21,price: 138.0,count: 2,},{id: 3,name: 《数学之美》,date: 2023-10-21,price: 88.0,count: 6,},{id: 4,name: 《编程珠玑》,date: 2023-10-21,price: 39.0,count: 9,},],}}// 格式化价格formatePrice(price) {return Number(price).toFixed(2)}// 总计getTotalPrice() {// 方式一// let totalPrice 0// for (let i 0; i this.state.books.length; i) {// const book books[i]// totalPrice book.price * book.count// }// 方式二const totalPrice this.state.books.reduce((preValue, item) {return preValue item.count * item.price}, 0)return totalPrice}// 加// increment(index) {// const newBooks [...this.state.books]// newBooks[index].count 1// this.setState({// books: newBooks,// })// }// 减// decrement(index) {// const newBooks [...this.state.books]// newBooks[index].count - 1// this.setState({// books: newBooks,// })// }// 加减逻辑合并changeCount(index, count) {const newBooks [...this.state.books]newBooks[index].count countthis.setState({books: newBooks,})}// 删除removeItem(index) {const newBooks [...this.state.books]newBooks.splice(index, 1)this.setState({books: newBooks,})}renderBooks() {const { books } this.statereturn (divtable border1 collapsenonetheadtrth序号/thth书籍名称/thth出版日期/thth价格/thth购买数量/thth操作/th/tr/theadtbody{books.map((item, index) {return (tr key{item.id}td{index 1}/tdtd{item.name}/tdtd{item.date}/tdtd{this.formatePrice(item.price)}/tdtdbuttondisabled{item.count 1}onClick{() this.changeCount(index, -1)}-/button{item.count}button onClick{() this.changeCount(index, 1)}/button/tdtdbutton onClick{() this.removeItem(index)}删除/button/td/tr)})}/tbody/tableh4总价格{this.formatePrice(this.getTotalPrice())}/h4/div)}renderBookEmpty() {return (divh4购物车为空请添加书籍/h4/div)}render() {const { books } this.statereturn books.length ? this.renderBooks() : this.renderBookEmpty()}
}