react的超详细讲解

create-react-app
项目目录
在HTML中使用react
1
2
3基础
React的注意事项
模拟的React 和 render
React组件
函数组件
类组件
React 的数据源(props(外部传入,不可修改) ,state(内部自带,可修改))
React 生命周期(钩子函数)
React Event 中的this问题
prop-types
受控与非受控组件
React 是单向数据流
4 超详细讲解
React高性能的体现:虚拟DOM
React Fiber
编写第一个react应用程序
函数组件
es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:
在16以前的版本还支持这样创建组件, 但现在的项目基本上不用
组件的组合、嵌套
React.createElement
create-react-app
脚手架工具create-react-app
基于webpack的一个工具,帮助我们快速创建一个项目 webpack gulp

npm install create-react-app -g yarn create-react-app -V 查看脚手架工具的版本 create-react-app 项目名字 创建项目 npm run start 开发环境运行 npm run build 打包 npm run eject 解开大礼包 在git仓库做一个commit操作

项目目录
config(vue.config.js) 默认不存在 解开大礼包才会出现 对项目做一些配置 代理 public 资源路径根vue中的public一样 scripts 文件 项目启动文件项目打包文件 src 源码文件 index.js === main.js 入口文件

create-react-app官方的一个生成react项目,安装时后面跟一个项目名称 需要在一个空的文件夹下安装 create-react-app 安装的时候会自动帮我们下载react(需要的react),react-dom(主要是渲染),react-script(可以认为继承了webpack的脚手架) 加-g是全局安装 npm install create-react-app myApp //mac 安装需要加 sudo sudo npm install create-react-app myApp

启动服务 npm start 开启本地服务 npm build 打包 npm test jest进行单元测试 npm eject 可以把webpack命令打包出来,方便我们修改webpack文件,但此操作不能回退

cmd
“–exact” “react” "react-dom"dom 渲染 "react-scripts"继承了webpack的脚手架 “cra-template” “–cwd”

react-scripts > jest > jest-cli > jest-config > jest-environment-jsdom > jsdom > left-pad
react-scripts > workbox-webpack-plugin > workbox-build > strip-comments > babel-plugin-transform-object-rest-spread > babel-runtime > [email protected]: core-js@❤️
“react-scripts > [email protected]” has incorrect peer dependency “[email protected]”.
warning “react-scripts > @typescript-eslint/eslint-plugin > [email protected]” has unmet peer dependency “typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta”.
在HTML中使用react

// 创建组件
/*
1.通过React crateClass 方法创建组件
2. 配置项里固定有一个render函数
3. render函数里要求return页面模板
4. 组件也是一个虚拟dom
*/

/*
React.createElement(‘div’,{id:‘test’},[
React.creatElement(‘h1’,{class:‘red’,text:‘jsx语法(vue中的模板)’},[])
React.createElenent(‘p’,{text:123},[
React.craeteElement(‘span’,{text:1})
])
])
语法 糖 class 简化代码少写点
jsx javascript xhtml
可以让我们在js里写html标签
1.标签必须闭合
2.必须有一个根元素
正常的js代码不能直接写标签 jsx 也不行
想使用需要将jsx的语法进行解析
type=‘text/babel’ 是告诉浏览器该标签的内部需要解析jsx
*/

// 注释方式 {/要注释的内容/}
// 控制一个元素的渲染 ||
// 2个元素切换 三元表达式
// 渲染的东西比较多 用函数

/*
react 不允许直接将对象绑定在页面
react 绑定数组到页面回将数组的每一项拆分
*/

/*
事件绑定 原生事件用驼峰命名法 注意传参不能能加() bind

方法一直接调用处理函数
react 中的事件和原生类似 将原生事件使用变成驼峰命名法 onclick->onClick
默认参数是事件对象
传递参数不能写() 所以通过bind 进行传参 默认参数放到最后
方法二
在事件的函数里 调用目标处理函数
注意 需要手动传递事件对象
*/

/*
setState 通知组件重新渲染一遍
setState 是一个异步的函数
参数1 表示要修改的数据 参数2是一个回调 当数据修改结束后执行
1-2-3-4-1
setState 同步中 修改数据不会直接更新页面 将同一个事件循环所有的setState 合并 更新一次页面
setState 如果在异步中 每一次都会触发页面刷新
*/

/*
使用方式2 通过ref 绑定组件
可以获取组件对象 获取绑定组件的相关方法
*/

/*
组件标签中写的内容不会被渲染
但是可以在组件内部通过 props.childer 获取使用
/
/

组件通信
父子 props 将父组件的数据传递给子组件 ref 获取子组件的方法 由父组件调用
子父 props 将父组件的方法传给子组件调用
兄弟 状态提升 上下文 全局状态管理 redux

父子通信 1 父组件控制子组件元素的渲染
将 控制div显示的state 放到子组件上
子组件有一个修改 state值的方法
通过ref 将父组件调用子组件的方法
/
/

父子通信 2 父组件控制子组件元素的渲染
直接传递数据
1.控制元素渲染的数据放在父组件上
2.修改的方法放在父组件上
3.通过props 将数据传递给子组件
4.父组件调用自己的方法修改
*/

/*
子父通信 子组件控制父组件
1数据在父组件上
2.修改数据的方法在父组件
3.将父组件的方法传给子组件调用
*/

/*
亲兄弟通信
1.子元素控制另一个子元素的div显示
2.控制变量放在父组件
3.控制变量的方法也在父组件上
4.结合父子和子父通信
*/
let Son = React.createClass({
sonfun(){
console.log(‘子组件的方法’)
},
toggle(num1,num2){
console.log(num1,num2)
this.setState({show:!this.state.show})
},
render(){
return(


子组件

子组件:{this.props.children}

    {!this.props.show||
}
)

}
})
let Son2 = React.createClass({

render(){
return(


子组件2


)
}
})

let Component = React.createClass({
getInitialState(){
console.log(‘初始化state值’) //类似于vue中的data
return {
name:‘韩梅梅’,
hide:true,
num:1,
string:‘呵呵’,
arr:[“呢”,‘he’,‘sdf’],
obj:{us:123,ps:123},
null:null,
undef:undefined,
boolean:true,
tabs:[‘动作’,‘恐怖’,‘动漫’,‘喜剧’],
// tabs:[‘

  • 动作
  • ’,‘
  • 恐怖
  • ’,‘
  • 动漫
  • ’]
    // tabs:[
  • 动作
  • ,
  • 恐怖
  • ,
  • 动漫
  • ]
    color:false,

    }
    

    },
    renderDiv(){
    console.log(‘渲染div’)
    if(this.state.hide){

    }else{
    
    return ()
    }
    

    },
    test(num1,num2,event){
    console.log(‘点到我了’,num1,num2,event)
    },
    toggle(){
    // this.state.color=!this.state.color
    console.log(this.state.color)
    this.setState({color:!this.state.color})
    },
    render(){
    return (


    hehe


    hehe


    {this.props.hehe}
    {/* {this.state.show?
    div
    :

    p

    } /}
    {/
    { this.state.hide||
    div
    }*/}
    {this.renderDiv()}

    数据绑定


    {this.state.num}

    {this.state.string}

    {this.state.null?‘a’:‘b’}

    {this.state.undefined?‘c’:‘d’}

    {this.state.boolean?‘真’:‘假’}

    {this.state.obj.us}

    {this.state.arr}

        
      {this.state.tabs.map((item,index)=>{ return (
    • {item}
    • ) })}
    {/**/}
    // this.setState({num:5},()=>{ // console.log('赋值结束',this.state.num) // }) // console.log('bottom',this.state.num) setTimeout(()=>{ this.setState({num:2}) this.setState({num:3}) this.setState({num:4}) this.setState({num:5}) },1000)
    你买到票了没 toggle(num1,num2){ console.log(num1,num2) this.setState({show:!this.state.show})

    },
    render() {
    return (


    这里是父组件


    {!this.state.show||
    }

          toggle(){
    this.setState({show:!this.state.show})
    

    },
    render() {
    return (


    这里是父组件

          
          
      
    )

    }
    })

    // 将组件挂载到 app元素上 参数1 要挂载的组件 参数2 要挂载的元素
    // 组件名当成标签名使用 组件名必须大写
    ReactDOM.render(,document.getElementById(‘app’))
    // ReactDOM.render(,app)

    1 https://blog.csdn.net/qq_36824244/article/details/103003640

    用于构建用户界面的javascript库

    16之前采用diff算法,之后采用fiber算法,分成小块,异步渲染

    import React from “react”
    //只要使用jsx的语法都需要引入react,这是顶级api
    import ReactDOM from “react-dom”
    //render是react dom提供的一个方法,这个方法通常只会渲染一次
    import { render } from ‘react-dom’

    const app=

    Welconme


    //函数式组件
    //使用箭头函数,但名字要大写开始
    const createApp = (props) => {
    //在jsx里面写js语法需要加{},只有这一种语法
    return

    Welconme{props.title}


    }
    const app = createApp({
    title: ‘16.8’
    })
    //类组件
    class App extends React.Component {
    render () {
    return

    类组件!!!


    }
    }
    //new一个实例
    //类组件渲染的原理
    // 因为app不是一个element所以必须要调实例的render方法
    const app = new App({
    desc:‘类组件是继承React.Component的1’
    }).render()
    //表示一个虚拟dom树
    const appVDom = {
    tag: ‘div’,
    attrs: {
    className: ‘app’,
    id: ‘appRoot’
    },
    children: [
    {
    tag: ‘h3’,
    attrs: {
    className: ‘title’
    },
    children: [
    ‘类组件!!!’
    ]
    },{
    tag: ‘p’,
    attrs: null,
    children: [
    ‘类组件是继承React.Component的’
    ]
    }
    ]
    }
    //所以react在真正渲染的时候会把上面的代码成下面这个样子,这是合法的js代码
    class App extends Component {
    render () {
    return (
    // React.createElement是一个方法,用于创建元素,可以有很多参数,但前两个是固定的
    //第一个为标签名
    //第二个为标签的属性
    React.createElement(
    ‘div’,
    {
    className: ‘app’,
    id: ‘appRoot’
    }
    ),
    React.createElement(
    ‘h3’,
    {
    className: ‘title’,
    },
    ‘类组件’
    ),
    React.createElement(
    ‘p’,
    null,
    ‘类组件是继承React.Component的’
    )
    )
    }
    }
    //下载class包 npm i classnames --save

    ReactDOM.render(app,querySelector("#toot")

    //在react6以前使用的是这种方式来创建一个类组件
    React.createClass({
    render

    类组件!!!


    })
    2
    https://blog.csdn.net/halations/article/details/84389261

    3基础
    https://blog.csdn.net/qq_30523685/article/details/85621598

    React的注意事项
    一般采用import的方式引入React,React首字母规定大些,因为jsx会默认使用大写的React

    会根据尖括号(<)来判断是一个html,根据花括号({)来判断是一个js js中的保留字 关键字会进行转化 class=>className for=>htmlFor react相邻的jsx元素,react元素,必须被一个标签包裹 <> style标签 必须是一个对象 style={{}} //{}表示js里面的{}表示是一个对象 注释 要用{}包裹 dangerouslySetInnerHTML 危险的,解析html用innerHtml的方式把内容塞进元素中

    你好"}}>
    可以在页面中使用三元运算 事件方法 之前的οnclick=> onClick …

    模拟的React 和 render
    react渲染的流程

    react会把jsx语法渲染成React.createElement()格式 React.createElement() 会转为 vnode(虚拟节点) vnode 渲染到页面上

    let React = {
    createElement(type,props,…children){//可以组成一个对象,用来描述dom元素
    return {type,props,children};//虚拟dom
    }
    }
    let ele =

    哈哈

    ;
    console.log(ele);//返回一个对象
    let render=(obj,container)=>{
    if(typeof obj === “string”) return container.appenChild(document.createTextNode(obj));
    let {type,props,children} = obj;
    let ele = document.createElement(type);
    for(let key in props){
    ele.setAtteributte(key,props[key])
    }
    children.forEach(item=>{
    render(item,ele);//递归,渲染子节点
    })
    children.appendChild(ele);
    }
    React组件
    函数组件
    函数就是组件 组件名称规定首字母大写,小写认为是一个标签元素 组件在元素中应用<组件名/> or <组件名> 组件传递的属性或方法(<组件名 title={“222”}>)会把传入的属性包成一个对象({title:“222”})传给这个组件函数props,在组件内取值时就是,{props.title}

    函数组件会在内部添加一个render方法,把函数的返回结果作为render方法的返回结果
    函数组件的不足

    没有状态 新版本有增加 没有生命周期的钩子 新版本有增加 函数组件中没有this

    类组件
    类组件在渲染时会默认调用render方法 类组件内有状态和钩子函数 需要继承React.Component React.Component 是一个基类,有生命周期,更改状态的方法 继承React.Component 之后才算是一个React类。

    import React from “react”;
    import ReactDOM from “react-dom”;
    class Clcok extends React.Component{
    constructor(props){//会接受组件传入的属性or方法
    super(props);
    //this.state 是规定死的,表示给这个组件生命状态
    this.state={ }
    }
    //es7语法 简单粗暴 和上面的一样
    // state={}
    render(){
    return

    哈哈


    }
    }
    React 的数据源(props(外部传入,不可修改) ,state(内部自带,可修改))
    props 会把组件传入的属性or方法放在this上 ---- 取值时:this.props.name1 this.state 状态 ---- 取值时:this.state.name1 this.setState

    是父类提供的,用于修改状态,这种更新状态的方式,不会覆盖之前的,只会进行比较把更新的状态进行合并 this.setState 会刷新页面,如果不用this.setState。直接修改state 会改状态还是页面不会刷新 需要改属性的话只能把属性(props)变为状态(state) this.setState 可以执行多次么? 面试题

    React 生命周期(钩子函数)
    componentDidMount(){} 当前组件挂在完成,在render方法加载完之后执行 unmountComponentAtNode() 卸载组件 //用法 ReactDOM.unmountComponentAtNode(window.root) componentWillUnmount(){} 将要卸载,在此阶段中删掉所有的监听和卸载异步方法 componentDidMount(){ this.itemer = setInterval=()=>{ //this.setState 可以导致页面刷新 this.setState({time:new Date().toLocalString()}) } } componetWillUnmount(){ clearInterval(this.timer); }

    React Event 中的this问题
    this问题

    通常在元素中给事件绑定一个函数 (onClick = this.btnclick) this是undefined的 在es6 类中,如果把原型上的方法拿出来,这是一个错误的操作,this是undefined btnclick(){} 1 如果解决this指向问题

    在元素中绑定时加入bind(onClick = this.btnclick.bind(this)) 每次点击都产生一个新的函数 在constructor中设置一下,然后在元素中用(οnclick={this.btnclick}) 官网推荐 consttuctor(){ super(); this.btnclick = this.btnclick.bind(this); //这样每次点击的时候都是用的一个函数。 }

    采用箭头函数可以完美解决,只要是在原型中的方法采用箭头函数就可以 在元素中直接用(οnclick=this.btnclick) es7方式 btnclick=()=>{} //这里采用箭头函数方式

    prop-types
    React 内置了类型检测的功能,在组件中检测,可以赋值propTypes属性

    格式校验 需下载 propTypes 属性 .array 数组 .bool 布尔值 .func 函数 .number 数字 .object 对象 .string 字符串 .symbol 符号 .node 任何东西都可以被渲染:numbers, strings, elements,或者是包含这些类型的数组(或者是片段)。 .element React元素 .instanceOf(Message) 类的一个实例 .oneOf([‘News’, ‘Photos’]) 枚举值 .oneOfType([PropTypes.string,PropTypes.number,PropTypes.instanceOf(Message)]) 多种类型其中之一 .arrayOf(PropTypes.number) 某种类型的数组 .objectOf(PropTypes.number) 某种类型的对象 .shape({color: PropTypes.string,fontSize: PropTypes.number}) 特定形式的对象 .func.isRequired 可以使用 isRequired’ 链接上述任何一个,以确保在没有提供 prop 的情况下显示警告 .any.isRequired 任何数据类型的值 function(props, propName, componentName) { return new Error()} 自定义的验证器 .arrayOf(function(propValue, key, componentName, location, propFullName) {} import React from ‘react’; import ReactDOM from ‘react-dom’; import PropTypes from ‘prop-types’; class Person extends React.Component{ static defaultProps = { name:‘Stranger’ } static propTypes={ name: PropTypes.string.isRequired, age: PropTypes.number.isRequired, gender: PropTypes.oneOf([‘male’,‘famale’]), hobby: PropTypes.array, postion: PropTypes.shape({ x: PropTypes.number, y:PropTypes.number }), age(props,propName,componentName) { let age=props[propName]; if (age <0 || age>120) { return new Error(Invalid Prop ${propName} supplied to ${componentName}`) } } } render() { let {name,age,gender,hobby,position}=this.props; return (
    姓名 年龄 性别 爱好 位置
    {name} {age} {gender} {hobby.join(’,’)} {position.x+’ '+position.y}
    ) } } let person={ age: 100, gender:‘male’, hobby: [‘basketball’,‘football’], position: {x: 10,y: 10}, } ReactDOM.render(, document.getElementById(‘root’));

    受控与非受控组件
    在表单中有受(状态)控组件和非受控组件

    受控组件就是需要添加 onChange

    受控好处:- 可以给输入框赋予默认值 - 实时校验

    受控坏处:- 每次输入都会调用setState

    非受控

    非受控好处:- 简单,也不写状态

    非受控坏处:- 不能实时校验

    ref 相当于别名

    ref设值or取值 import React,{Component} from “react”; import ReactDOM from “react-dom”; class Control extends Component{ password = React.createRef();//新版本 16.3采用的 handleClick=()=>{ //取值 console.log(this.username.value);// console.log(this.refs.aaa)// 废弃的 //this.password.current 才是真实的dom console.log(this.password.current.value); } render(){ return

    {this.username = dom}} /> //新版本
    } }
    React 是单向数据流
    方法1 Q:子辈不能修改父的值,那如果修改呢? A:通过由父辈传递给子辈一个函数,函数回调里放的就是修改的功能,当子辈执行这个函数的时候就会触发父辈的回调就可以更改这个值在传入下去。

    方法2 context Api React提供的,定义一些数据,由子孙直接消费,不必一层层下传

    4 超详细讲解
    https://blog.csdn.net/xuwei1215225/article/details/90180252

    React高性能的体现:虚拟DOM
    每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B,B-A,React会认为A变成B,然后又从B变成A UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。

    React Fiber
    的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

    编写第一个react应用程序
    把通过CRA创建的工程目录下的src目录清空,然后在里面重新创建一个index.js.

    函数组件
    app({ name: ‘react’ }),

    // React组件的调用方式 ,

    es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:
    import React from ‘react’
    import ReactDOM from ‘react-dom’
    class App extends React.Component {
    render () {
    return (

    欢迎进入{this.props.name}的世界


    )
    }
    }
    const app = new App({
    name: ‘react’
    }).render()
    ReactDOM.render(
    app,
    document.getElementById(‘root’)
    )
    在16以前的版本还支持这样创建组件, 但现在的项目基本上不用
    React.createClass({ render () { return (

    组件的组合、嵌套
    将一个组件渲染到某一个节点里的时候,会将这个节点里原有内容覆盖 组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系

    React.createElement
    会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为

    React.createElement(
    type,
    [props],
    […children]
    )
    JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()—>DOM元素 —>插入页面 #组件中DOM样式

    行内样式 想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现: // 注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号
    Hello world

    行内样式需要写入一个样式对象,而这个样式对象的位置可以放在很多地方,例如render函数里、组件原型上、外链js文件中

    使用class React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体 其实我们大多数情况下还是大量的在为元素添加类名,但是需要注意的是,class需要写成className(因为毕竟是在写类js代码,会收到js规则的现在,而class是关键字)
    Hello world

    不同的条件添加不同的样式 有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classnames这个包: css-in-js styled-components是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接 #TodoList

    组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的:
    /your-project

    src

    components
    YourComponentOne
    index.js/YourComponentOne.js
    YourComponentTwo
    index.js/YourComponentTwo.js
    index.js 用于导出组件
    注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate
    React的超详细讲解
    原创 搞前端的正则妈 最后发布于2019-05-13 20:02:43 阅读数 248 收藏
    发布于2019-05-13 20:02:43
    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/xuwei1215225/article/details/90180252
    展开

    React React的重点

    webpack
    webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle
    其它相似打包工具还有rollup.js 、 parcel、FIS等
    按照webpack的指南**(注意是指南不是概念不是api)**进行针对性的讲解即可,需要被充一下工程化的知识

    工程化
    这个部分的内容可以做为一些思想给学员讲解,不需要学员掌握。可以理解为扩展的内容

    什么是JS项目工程化
    版本控制
    自动化持续继承、持续交付(CI/CD)
    代码质量控制(QA)
    工具
    模块化
    文档
    demo
    编译过程
    自动化处理每次push, tag, release的任务队列

    安装
    安装 : npm命令行工具
    安全审计:npm audit
    Lint
    格式检查: eslint/stylelint
    格式化: prettier
    测试
    测试套装: jest / mocha / ava / kamar
    代码覆盖量: nyc / codecov / coveralls
    构建
    转换器: babel / TS / flow
    预处理器: sass / less / postcss
    代码混淆: uglify-js / terser
    打包及tree shaking: webpack / rollup / parcel
    压缩(gzip等)
    复制 / 删除 / 移动文件
    检查打包文件的大小
    移除无用的代码
    push
    交付: git
    发布: npm
    部署
    服务器
    Pages: git pages
    云服务器: aliyun / qcloud / aws
    Story Book
    create-react-app
    全局安装create-react-app

    $ npm install -g create-react-app
    1
    创建一个项目

    $ create-react-app your-app 注意命名方式
    Creating a new React app in /dir/your-app.
    Installing packages. This might take a couple of minutes. 安装过程较慢,可以推荐学员使用yarn
    Installing react, react-dom, and react-scripts…
    1
    2
    3
    4
    如果不想全局安装,可以直接使用npx

    $ npx create-react-app your-app 也可以实现相同的效果
    1
    这需要等待一段时间,这个过程实际上会安装三个东西

    react: react的顶级库
    react-dom: 因为react有很多的运行环境,比如app端的react-native, 我们要在web上运行就使用react-dom
    react-scripts: 包含运行和打包react应用程序的所有脚本及配置
    出现下面的界面,表示创建项目成功:
    Success! Created your-app at /dir/your-app
    Inside that directory, you can run several commands:
    npm start
    Starts the development server.
    npm run build
    Bundles the app into static files for production.
    npm test
    Starts the test runner.
    npm run eject
    Removes this tool and copies build dependencies, configuration files
    and scripts into the app directory. If you do this, you can’t go back!
    We suggest that you begin by typing:
    cd your-app
    npm start
    Happy hacking!
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    根据上面的提示,通过cd your-app命令进入目录并运行npm start即可运行项目。
    生成项目的目录结构如下:

    ├── README.md 使用方法的文档
    ├── node_modules 所有的依赖安装的目录
    ├── package-lock.json 锁定安装时的包的版本号,保证团队的依赖能保证一致。
    ├── package.json
    ├── public 静态公共目录
    └── src 开发用的源代码目录
    1
    2
    3
    4
    5
    6
    常见问题:

    npm安装失败
    切换为npm镜像为淘宝镜像
    使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内
    如果还没有办法解决,请删除node_modules及package-lock.json然后重新执行npm install命令
    再不能解决就删除node_modules及package-lock.json的同时清除npm缓存npm cache clean --force之后再执行npm install命令
    关于React
    React部分的内容包含了所有授课的思路

    React的起源和发展
    React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。

    React与传统MVC的关系
    轻量级的视图层库!A JavaScript library for building user interfaces
    React不是一个完整的MVC框架,最多可以认为是MVC中的V(View),甚至React并不非常认可MVC开发模式;React 构建页面 UI 的库。可以简单地理解为,React 将将界面分成了各个独立的小块,每一个块就是组件,这些组件之间可以组合、嵌套,就成了我们的页面。

    React高性能的体现:虚拟DOM
    React高性能的原理:
    在Web开发中我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。
    React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A-B,B-A,React会认为A变成B,然后又从B变成A UI不发生任何变化,而如果通过手动控制,这种逻辑通常是极其复杂的。
    尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,部而对实际DOM进行操作的仅仅是Diff分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要关心在任意一个数据状态下,整个界面是如何Render的。

    React Fiber:
    在react 16之后发布的一种react 核心算法,React Fiber是对核心算法的一次重新实现(官网说法)。之前用的是diff算法。
    在之前React中,更新过程是同步的,这可能会导致性能问题。
    当React决定要加载或者更新组件树时,会做很多事,比如调用各个组件的生命周期函数,计算和比对Virtual DOM,最后更新DOM树,这整个过程是同步进行的,也就是说只要一个加载或者更新过程开始,中途不会中断。因为JavaScript单线程的特点,如果组件树很大的时候,每个同步任务耗时太长,就会出现卡顿。
    React Fiber的方法其实很简单——分片。把一个耗时长的任务分成很多小片,每一个小片的运行时间很短,虽然总时间依然很长,但是在每个小片执行完之后,都给其他任务一个执行的机会,这样唯一的线程就不会被独占,其他任务依然有运行的机会。

    React的特点和优势
    虚拟DOM
    我们以前操作dom的方式是通过document.getElementById()的方式,这样的过程实际上是先去读取html的dom结构,将结构转换成变量,再进行操作
    而reactjs定义了一套变量形式的dom模型,一切操作和换算直接在变量中,这样减少了操作真实dom,性能真实相当的高,和主流MVC框架有本质的区别,并不和dom打交道
    组件系统
    react最核心的思想是将页面中任何一个区域或者元素都可以看做一个组件 component
    那么什么是组件呢?
    组件指的就是同时包含了html、css、js、image元素的聚合体
    使用react开发的核心就是将页面拆分成若干个组件,并且react一个组件中同时耦合了css、js、image,这种模式整个颠覆了过去的传统的方式
    单向数据流
    其实reactjs的核心内容就是数据绑定,所谓数据绑定指的是只要将一些服务端的数据和前端页面绑定好,开发者只关注实现业务就行了
    JSX 语法
    在vue中,我们使用render函数来构建组件的dom结构性能较高,因为省去了查找和编译模板的过程,但是在render中利用createElement创建结构的时候代码可读性较低,较为复杂,此时可以利用jsx语法来在render中创建dom,解决这个问题,但是前提是需要使用工具来编译jsx
    编写第一个react应用程序
    react开发需要引入多个依赖文件:react.js、react-dom.js,分别又有开发版本和生产版本,create-react-app里已经帮我们把这些东西都安装好了。把通过CRA创建的工程目录下的src目录清空,然后在里面重新创建一个index.js. 写入以下代码:

    // 从 react 的包当中引入了 React。只要你要写 React.js 组件就必须引入React, 因为react里有一种语法叫JSX,稍后会讲到JSX,要写JSX,就必须引入React
    import React from ‘react’
    // ReactDOM 可以帮助我们把 React 组件渲染到页面上去,没有其它的作用了。它是从 react-dom 中引入的,而不是从 react 引入。
    import ReactDOM from ‘react-dom’
    // ReactDOM里有一个render方法,功能就是把组件渲染并且构造 DOM 树,然后插入到页面上某个特定的元素上
    ReactDOM.render(
    // 这里就比较奇怪了,它并不是一个字符串,看起来像是纯 HTML 代码写在 JavaScript 代码里面。语法错误吗?这并不是合法的 JavaScript 代码, “在 JavaScript 写的标签的”语法叫 JSX- JavaScript XML。

    欢迎进入React的世界

    , // 渲染到哪里 document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 元素与组件 如果代码多了之后,不可能一直在render方法里写,所以就需要把里面的代码提出来,定义一个变量,像这样:

    import React from ‘react’
    import ReactDOM from ‘react-dom’
    // 这里感觉又不习惯了?这是在用JSX定义一下react元素
    const app =

    欢迎进入React的世界


    ReactDOM.render(
    app,
    document.getElementById(‘root’)
    )
    1
    2
    3
    4
    5
    6
    7
    8
    函数式组件
    由于元素没有办法传递参数,所以我们就需要把之前定义的变量改为一个方法,让这个方法去return一个元素:

    import React from ‘react’
    import ReactDOM from ‘react-dom’
    // 特别注意这里的写法,如果要在JSX里写js表达式(只能是表达式,不能流程控制),就需要加 {},包括注释也是一样,并且可以多层嵌套
    const app = (props) =>

    欢迎进入{props.name}的世界


    ReactDOM.render(
    app({
    name: ‘react’
    }),
    document.getElementById(‘root’)
    )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    这里我们定义的方法实际上也是react定义组件的第一种方式-定义函数式组件,这也是无状态组件。但是这种写法不符合react的jsx的风格,更好的方式是使用以下方式进行改造

    import React from ‘react’
    import ReactDOM from ‘react-dom’
    const App = (props) =>

    欢迎进入{props.name}的世界


    ReactDOM.render(
    // React组件的调用方式
    ,
    document.getElementById(‘root’)
    )
    1
    2
    3
    4
    5
    6
    7
    8
    这样一个完整的函数式组件就定义好了。但要注意!注意!注意!组件名必须大写,否则报错。

    class组件
    ES6的加入让JavaScript直接支持使用class来定义一个类,react的第二种创建组件的方式就是使用的类的继承,ES6 class是目前官方推荐的使用方式,它使用了ES6标准语法来构建,看以下代码:

    import React from ‘react’
    import ReactDOM from ‘react-dom’
    class App extends React.Component {
    render () {
    return (
    // 注意这里得用this.props.name, 必须用this.props

    欢迎进入{this.props.name}的世界

    ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 运行结果和之前完全一样,因为JS里没有真正的class,这个class只是一个语法糖, 但二者的运行机制底层运行机制不一样。

    函数式组件是直接调用, 在前面的代码里已经有看到
    es6 class组件其实就是一个构造器,每次使用组件都相当于在实例化组件,像这样:
    import React from ‘react’
    import ReactDOM from ‘react-dom’
    class App extends React.Component {
    render () {
    return (

    欢迎进入{this.props.name}的世界


    )
    }
    }
    const app = new App({
    name: ‘react’
    }).render()
    ReactDOM.render(
    app,
    document.getElementById(‘root’)
    )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    更老的一种方法
    在16以前的版本还支持这样创建组件, 但现在的项目基本上不用

    React.createClass({
    render () {
    return (

    {this.props.xxx}
    ) } }) 1 2 3 4 5 6 7 组件的组合、嵌套 将一个组件渲染到某一个节点里的时候,会将这个节点里原有内容覆盖 组件嵌套的方式就是将子组件写入到父组件的模板中去,且react没有Vue中的内容分发机制(slot),所以我们在一个组件的模板中只能看到父子关系

    // 从 react 的包当中引入了 React 和 React.js 的组件父类 Component
    // 还引入了一个React.js里的一种特殊的组件 Fragment
    import React, { Component, Fragment } from ‘react’
    import ReactDOM from ‘react-dom’
    class Title extends Component {
    render () {
    return (

    欢迎进入React的世界

    ) } } class Content extends Component { render () { return (

    React.js是一个构建UI的库

    ) } } /** 由于每个React组件只能有一个根节点,所以要渲染多个组件的时候,需要在最外层包一个容器,如果使用div, 会生成多余的一层dom class App extends Component { render () { return (
    ) } } **/ // 如果不想生成多余的一层dom可以使用React提供的Fragment组件在最外层进行包裹 class App extends Component { render () { return ( ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 JSX 原理 要明白JSX的原理,需要先明白如何用 JavaScript 对象来表现一个 DOM 元素的结构? 看下面的DOM结构 <div class="app" id="appRoot"> <h1 class="title">欢迎进入React的世界</h1> <p> React.js 是一个帮助你构建页面 UI 的库 </p> </div> 1 2 3 4 5 6 上面这个 HTML 所有的信息我们都可以用 JavaScript 对象来表示: <p>{<br/> tag: ‘div’,<br/> attrs: { className: ‘app’, id: ‘appRoot’},<br/> children: [<br/> {<br/> tag: ‘h1’,<br/> attrs: { className: ‘title’ },<br/> children: [‘欢迎进入React的世界’]<br/> },<br/> {<br/> tag: ‘p’,<br/> attrs: null,<br/> children: [‘React.js 是一个构建页面 UI 的库’]<br/> }<br/> ]<br/> }<br/> 1<br/> 2<br/> 3<br/> 4<br/> 5<br/> 6<br/> 7<br/> 8<br/> 9<br/> 10<br/> 11<br/> 12<br/> 13<br/> 14<br/> 15<br/> 16<br/> 但是用 JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。<br/> 于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接在 JavaScript 代码里面编写类似 HTML 标签结构的语法,这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。<br/> 下面代码:</p> <p>import React from ‘react’<br/> import ReactDOM from ‘react-dom’<br/> class App extends React.Component {<br/> render () {<br/> return (</p> <div id="appRoot"> <h1>欢迎进入React的世界</h1> <p> React.js 是一个构建页面 UI 的库 </p> </div> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 编译之后将得到这样的代码: <p>import React from ‘react’<br/> import ReactDOM from ‘react-dom’<br/> class App extends React.Component {<br/> render () {<br/> return (<br/> React.createElement(<br/> “div”,<br/> {<br/> className: ‘app’,<br/> id: ‘appRoot’<br/> },<br/> React.createElement(<br/> “h1”,<br/> { className: ‘title’ },<br/> “欢迎进入React的世界”<br/> ),<br/> React.createElement(<br/> “p”,<br/> null,<br/> “React.js 是一个构建页面 UI 的库”<br/> )<br/> )<br/> )<br/> }<br/> }<br/> ReactDOM.render(<br/> React.createElement(App),<br/> document.getElementById(‘root’)<br/> )<br/> 1<br/> 2<br/> 3<br/> 4<br/> 5<br/> 6<br/> 7<br/> 8<br/> 9<br/> 10<br/> 11<br/> 12<br/> 13<br/> 14<br/> 15<br/> 16<br/> 17<br/> 18<br/> 19<br/> 20<br/> 21<br/> 22<br/> 23<br/> 24<br/> 25<br/> 26<br/> 27<br/> 28<br/> 29<br/> React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等, 语法为</p> <p>React.createElement(<br/> type,<br/> [props],<br/> […children]<br/> )<br/> 1<br/> 2<br/> 3<br/> 4<br/> 5<br/> 所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:</p> <p>JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()—>DOM元素 —>插入页面<br/> #组件中DOM样式</p> <p>行内样式<br/> 想给虚拟dom添加行内样式,需要使用表达式传入样式对象的方式来实现:<br/> // 注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号</p> <p>使用class<br/> React推荐我们使用行内样式,因为React觉得每一个组件都是一个独立的整体<br/> 其实我们大多数情况下还是大量的在为元素添加类名,但是需要注意的是,class需要写成className(因为毕竟是在写类js代码,会收到js规则的现在,而class是关键字)</p> <p>Hello world</p> 1 不同的条件添加不同的样式 有时候需要根据不同的条件添加不同的样式,比如:完成状态,完成是绿色,未完成是红色。那么这种情况下,我们推荐使用classnames这个包: css-in-js styled-components是针对React写的一套css-in-js框架,简单来讲就是在js中写css。npm链接 #TodoList 组件化开发React todolist, 项目开发中的组件的基本目录结构基本上是这样的: /your-project <p>src<br/> …<br/> components<br/> YourComponentOne<br/> index.js/YourComponentOne.js<br/> YourComponentTwo<br/> index.js/YourComponentTwo.js<br/> index.js 用于导出组件<br/> 注意:一个组件只干一件事情 ,所以TodoList和TodoItem要做成两个组件,这样也方便于后期理解shouldComponentUpdate<br/> 组件的数据挂载方式<br/> 属性(props)<br/> props是正常是外部传入的,组件内部也可以通过一些方式来初始化的设置,属性不能被组件自己更改,但是你可以通过父组件主动重新渲染的方式来传入新的 props<br/> 属性是描述性质、特点的,组件自己不能随意更改。<br/> 之前的组件代码里面有props的简单使用,总的来说,在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为组件 props 对象的键值。通过箭头函数创建的组件,需要通过函数的参数来接收props:</p> <p>import React, { Component, Fragment } from ‘react’<br/> import ReactDOM from ‘react-dom’<br/> class Title extends Component {<br/> render () {<br/> return (<br/> <h1>欢迎进入{this.props.name}的世界</h1><br/> )<br/> }<br/> }<br/> const Content = (props) => {<br/> return (</p> <p>{props.name}是一个构建UI的库</p> ) } class App extends Component { render () { return ( <title/> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 设置组件的默认props import React, { Component, Fragment } from 'react' import ReactDOM from 'react-dom' class Title extends Component { // 使用类创建的组件,直接在这里写static方法,创建defaultProps static defaultProps = { name: 'React' } render () { return ( <h1>欢迎进入{this.props.name}的世界</h1> ) } } const Content = (props) => { return ( <p>{props.name}是一个构建UI的库</p> ) } // 使用箭头函数创建的组件,需要在这个组件上直接写defaultProps属性 Content.defaultProps = { name: 'React.js' } class App extends Component { render () { return ( {/* 由于设置了defaultProps, 不传props也能正常运行,如果传递了就会覆盖defaultProps的值 */} <title/> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 props.children 我们知道使用组件的时候,可以嵌套。要在自定义组件的使用嵌套结构,就需要使用 props.children 。在实际的工作当中,我们几乎每天都需要用这种方式来编写组件。 <p>import React, { Component, Fragment } from ‘react’<br/> import ReactDOM from ‘react-dom’<br/> class Title extends Component {<br/> render () {<br/> return (<br/> <h1>欢迎进入{this.props.children}的世界</h1><br/> )<br/> }<br/> }<br/> const Content = (props) => {<br/> return (</p> <p>{props.children}</p> ) } class App extends Component { render () { return ( <title>React <i>React.js</i>是一个构建UI的库 ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 使用prop-types检查props React其实是为了构建大型应用程序而生, 在一个大型应用中,根本不知道别人使用你写的组件的时候会传入什么样的参数,有可能会造成应用程序运行不了,但是不报错。为了解决这个问题,React提供了一种机制,让写组件的人可以给组件的props设定参数检查,需要安装和使用prop-types: <p>$ npm i prop-types -S<br> 1<br> 状态(state)<br> 状态就是组件描述某种显示情况的数据,由组件自己设置和更改,也就是说由组件自己维护,使用状态的目的就是为了在不同的状态下使组件的显示不同(自己管理)</p> <p>定义state<br> 第一种方式</p> <p>import React, { Component } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> state = {<br> name: ‘React’,<br> isLiked: false<br> }<br> render () {<br> return (</p> <div> <h1>欢迎来到{this.state.name}的世界</h1> { this.state.isLiked ? '❤️取消' : '?收藏' } </div> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 另一种方式(推荐) <p>import React, { Component } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> constructor() {<br> super()<br> this.state = {<br> name: ‘React’,<br> isLiked: false<br> }<br> }<br> render () {<br> return (<br> </p> <div></div> <p></p> <h1>欢迎来到{this.state.name}的世界</h1> { this.state.isLiked ? '❤️取消' : '?收藏' } ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 this.props和this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的,更改​data的数据的时候会触发数据的getter和setter,但是React中没有做这样的处理,如果直接更改的话,react是无法得知的,所以,需要使用特殊的更改状态的方法setState。 ###setState isLiked 存放在实例的 state 对象当中,组件的 render 函数内,会根据组件的 state 的中的isLiked不同显示“取消”或“收藏”内容。下面给 button 加上了点击的事件监听。 <p>import React, { Component } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> constructor() {<br> super()<br> this.state = {<br> name: ‘React’,<br> isLiked: false<br> }<br> }<br> handleBtnClick = () => {<br> this.setState({<br> isLiked: !this.state.isLiked<br> })<br> }<br> render () {<br> return (</p> <div> <h1>欢迎来到{this.state.name}的世界</h1> { this.state.isLiked ? '❤️取消' : '?收藏' } </div> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 setState有两个参数 第一个参数可以是对象,也可以是方法return一个对象,我们把这个参数叫做updater <p>参数是对象<br> this.setState({<br> isLiked: !this.state.isLiked<br> })<br> 1<br> 2<br> 3<br> 参数是方法<br> this.setState((prevState, props) => {<br> return {<br> isLiked: !prevState.isLiked<br> }<br> })<br> 1<br> 2<br> 3<br> 4<br> 5<br> 注意的是这个方法接收两个参数,第一个是上一次的state, 第二个是props<br> setState是异步的,所以想要获取到最新的state,没有办法获取,就有了第二个参数,这是一个可选的回调函数</p> <p>this.setState((prevState, props) => {<br> return {<br> isLiked: !prevState.isLiked<br> }<br> }, () => {<br> console.log(‘回调里的’,this.state.isLiked)<br> })<br> console.log(‘setState外部的’,this.state.isLiked)<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 属性vs状态<br> 相似点:都是纯js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)<br> 不同点:</p> <p>属性能从父组件获取,状态不能<br> 属性可以由父组件修改,状态不能<br> 属性能在内部设置默认值,状态也可以<br> 属性不在组件内部修改,状态要改<br> 属性能设置子组件初始值,状态不可以<br> 属性可以修改子组件的值,状态不可以<br> state 的主要作用是用于组件保存、控制、修改自己的可变状态。state 在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state 是一个局部的、只能被组件自身控制的数据源。state 中状态可以通过 this.setState方法进行更新,setState 会导致组件的重新渲染。<br> props 的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props,否则组件的 props 永远保持不变。<br> 如果搞不清 state 和 props 的使用场景,记住一个简单的规则:尽量少地用 state,多用 props。<br> 没有 state 的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。<br> ##状态提升<br> 如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理<br> 受控组件与非受控组件<br> React组件的数据渲染是否被调用者传递的props完全控制,控制则为受控组件,否则非受控组件。</p> <p>渲染数据<br> 条件渲染<br> {<br> condition ? ‘❤️取消’ : ‘?收藏’<br> }<br> 1<br> 2<br> 3<br> 列表渲染<br> // 数据<br> const people = [{<br> id: 1,<br> name: ‘Leo’,<br> age: 35<br> }, {<br> id: 2,<br> name: ‘XiaoMing’,<br> age: 16<br> }]<br> // 渲染列表<br> {<br> people.map(person => {<br> return (</p> <dl> <dt> {person.name} </dt> <dd> age: {person.age} </dd> </dl> ) }) } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 React的高效依赖于所谓的 Virtual-DOM,尽量不碰 DOM。对于列表元素来说会有一个问题:元素可能会在一个列表中改变位置。要实现这个操作,只需要交换一下 DOM 位置就行了,但是React并不知道其实我们只是改变了元素的位置,所以它会重新渲染后面两个元素(再执行 Virtual-DOM ),这样会大大增加 DOM 操作。但如果给每个元素加上唯一的标识,React 就可以知道这两个元素只是交换了位置,这个标识就是key,这个 key 必须是每个元素唯一的标识 <p>dangerouslySetHTML<br> 对于富文本创建的内容,后台拿到的数据是这样的:<br> content = “</p> <p>React.js是一个构建UI的库</p>” <br> 1 <br> 处于安全的原因,React当中所有表达式的内容会被转义,如果直接输入,标签会被当成文本。这时候就需要使用dangerouslySetHTML属性,它允许我们动态设置innerHTML <p>import React, { Component } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> constructor() {<br> super()<br> this.state = {<br> content : “</p> <p>React.js是一个构建UI的库</p>” <br> } <br> } <br> render () { <br> return ( <br> <div <br> // 注意这里是两个下下划线 __html <br> dangerouslySetInnerHTML={{__html: this.state.content}} <br> /> <br> ) <br> } <br> } <br> ReactDOM.render( <br> , <br> document.getElementById(‘root’) <br> ) <br> 1 <br> 2 <br> 3 <br> 4 <br> 5 <br> 6 <br> 7 <br> 8 <br> 9 <br> 10 <br> 11 <br> 12 <br> 13 <br> 14 <br> 15 <br> 16 <br> 17 <br> 18 <br> 19 <br> 20 <br> 21 <br> 22 <br> 事件处理 <br> 绑定事件 <br> 采用on+事件名的方式来绑定一个事件,注意,这里和原生的事件是有区别的,原生的事件全是小写onclick, React里的事件是驼峰onClick,React的事件并不是原生事件,而是合成事件。 <p>事件handler的写法<br> 直接在render里写行内的箭头函数(不推荐)<br> 在组件内使用箭头函数定义一个方法(推荐)<br> 直接在组件内定义一个非箭头函数的方法,然后在render里直接使用onClick={this.handleClick.bind(this)}(不推荐)<br> 直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)<br> Event 对象<br> 和普通浏览器一样,事件handler会被自动传入一个 event 对象,这个对象和普通的浏览器 event 对象所包含的方法和属性都基本一致。不同的是 React中的 event 对象并不是浏览器提供的,而是它自己内部所构建的。它同样具有event.stopPropagation、event.preventDefault 这种常用的方法</p> <p>事件的参数传递<br> 在render里调用方法的地方外面包一层箭头函数<br> 在render里通过this.handleEvent.bind(this, 参数)这样的方式来传递<br> 通过event传递<br> 比较推荐的是做一个子组件, 在父组件中定义方法,通过props传递到子组件中,然后在子组件件通过this.props.method来调用<br> ##处理用户输入<br> import React, { Component } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> constructor() {<br> super()<br> this.state = {<br> xing: ‘’,<br> ming: ‘’<br> }<br> }<br> handleInputChange = (e) => {<br> this.setState({<br> [e.target.name]: e.target.value<br> })<br> }<br> render () {<br> const {<br> xing,<br> ming<br> } = this.state<br> return (<br> </p> <div> <br> <br> <span>姓:</span> <br> <br> <br> <br> <span>名:</span> <br> <br> </div> <p></p> <p>欢迎您: {xing}{ming}</p> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 组件的生命周期 React中组件也有生命周期,也就是说也有很多钩子函数供我们使用, 组件的生命周期,我们会分为四个阶段,初始化、运行中、销毁、错误处理(16.3之后) <p>初始化<br> 在组件初始化阶段会执行</p> <p>constructor<br> static getDerivedStateFromProps()<br> componentWillMount() / UNSAFE_componentWillMount()<br> render()<br> componentDidMount()<br> 更新阶段<br> props或state的改变可能会引起组件的更新,组件重新渲染的过程中会调用以下方法:</p> <p>componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()<br> static getDerivedStateFromProps()<br> shouldComponentUpdate()<br> componentWillUpdate() / UNSAFE_componentWillUpdate()<br> render()<br> getSnapshotBeforeUpdate()<br> componentDidUpdate()<br> 卸载阶段<br> componentWillUnmount()<br> 错误处理<br> componentDidCatch()<br> 各生命周期详解<br> 1.constructor(props)<br> React组件的构造函数在挂载之前被调用。在实现React.Component构造函数时,需要先在添加其他内容前,调用super(props),用来将父组件传来的props绑定到这个类中,使用this.props将会得到。<br> 官方建议不要在constructor引入任何具有副作用和订阅功能的代码,这些应当使用componentDidMount()。<br> constructor中应当做些初始化的动作,如:初始化state,将事件处理函数绑定到类实例上,但也不要使用setState()。如果没有必要初始化state或绑定方法,则不需要构造constructor,或者把这个组件换成纯函数写法。<br> 当然也可以利用props初始化state,在之后修改state不会对props造成任何修改,但仍然建议大家提升状态到父组件中,或使用redux统一进行状态管理。</p> <p>constructor(props) {<br> super(props);<br> this.state = {<br> isLiked: props.isLiked<br> };<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 2.static getDerivedStateFromProps(nextProps, prevState)<br> getDerivedStateFromProps 是react16.3之后新增,在组件实例化后,和接受新的props后被调用。他必须返回一个对象来更新状态,或者返回null表示新的props不需要任何state的更新。<br> 如果是由于父组件的props更改,所带来的重新渲染,也会触发此方法。<br> 调用steState()不会触发getDerivedStateFromProps()。<br> 之前这里都是使用constructor+componentWillRecieveProps完成相同的功能的</p> <ol start="3"> <li>componentWillMount() / UNSAFE_componentWillMount()<br> componentWillMount()将在React未来版本(官方说法 17.0)中被弃用。UNSAFE_componentWillMount()在组件挂载前被调用,在这个方法中调用setState()不会起作用,是由于他在render()前被调用。<br> 为了避免副作用和其他的订阅,官方都建议使用componentDidMount()代替。这个方法是用于在服务器渲染上的唯一方法。这个方法因为是在渲染之前被调用,也是惟一一个可以直接同步修改state的地方。</li> </ol> <p>4.render()<br> render()方法是必需的。当他被调用时,他将计算this.props和this.state,并返回以下一种类型:</p> <p>React元素。通过jsx创建,既可以是dom元素,也可以是用户自定义的组件。<br> 字符串或数字。他们将会以文本节点形式渲染到dom中。<br> Portals。react 16版本中提出的新的解决方案,可以使组件脱离父组件层级直接挂载在DOM树的任何位置。<br> null,什么也不渲染<br> 布尔值。也是什么都不渲染。<br> 当返回null,false,ReactDOM.findDOMNode(this)将会返回null,什么都不会渲染。<br> render()方法必须是一个纯函数,他不应该改变state,也不能直接和浏览器进行交互,应该将事件放在其他生命周期函数中。<br> 如果shouldComponentUpdate()返回false,render()不会被调用。<br> 5. componentDidMount<br> componentDidMount在组件被装配后立即调用。初始化使得DOM节点应该进行到这里。<br> 通常在这里进行ajax请求<br> 如果要初始化第三方的dom库,也在这里进行初始化。只有到这里才能获取到真实的dom.</p> <p>6.componentWillReceiveProps()/UNSAFE_componentWillReceiveProps(nextProps)<br> 官方建议使用getDerivedStateFromProps函数代替componentWillReceiveProps。当组件挂载后,接收到新的props后会被调用。如果需要更新state来响应props的更改,则可以进行this.props和nextProps的比较,并在此方法中使用this.setState()。<br> 如果父组件会让这个组件重新渲染,即使props没有改变,也会调用这个方法。<br> React不会在组件初始化props时调用这个方法。调用this.setState也不会触发。</p> <p>7.shouldComponentUpdate(nextProps, nextState)<br> 调用shouldComponentUpdate使React知道,组件的输出是否受state和props的影响。默认每个状态的更改都会重新渲染,大多数情况下应该保持这个默认行为。<br> 在渲染新的props或state前,shouldComponentUpdate会被调用。默认为true。这个方法不会在初始化时被调用,也不会在forceUpdate()时被调用。返回false不会阻止子组件在state更改时重新渲染。<br> 如果shouldComponentUpdate()返回false,componentWillUpdate,render和componentDidUpdate不会被调用。</p> <p>官方并不建议在shouldComponentUpdate()中进行深度查询或使用JSON.stringify(),他效率非常低,并且损伤性能。</p> <p>8.UNSAFE_componentWillUpdate(nextProps, nextState)<br> 在渲染新的state或props时,UNSAFE_componentWillUpdate会被调用,将此作为在更新发生之前进行准备的机会。这个方法不会在初始化时被调用。<br> 不能在这里使用this.setState(),也不能做会触发视图更新的操作。如果需要更新state或props,调用getDerivedStateFromProps。</p> <p>9.getSnapshotBeforeUpdate()<br> 在react render()后的输出被渲染到DOM之前被调用。它使您的组件能够在它们被潜在更改之前捕获当前值(如滚动位置)。这个生命周期返回的任何值都将作为参数传递给componentDidUpdate()。</p> <p>10.componentDidUpdate(prevProps, prevState, snapshot)<br> 在更新发生后立即调用componentDidUpdate()。此方法不用于初始渲染。当组件更新时,将此作为一个机会来操作DOM。只要您将当前的props与以前的props进行比较(例如,如果props没有改变,则可能不需要网络请求),这也是做网络请求的好地方。<br> 如果组件实现getSnapshotBeforeUpdate()生命周期,则它返回的值将作为第三个“快照”参数传递给componentDidUpdate()。否则,这个参数是undefined。</p> <p>11.componentWillUnmount()<br> 在组件被卸载并销毁之前立即被调用。在此方法中执行任何必要的清理,例如使定时器无效,取消网络请求或清理在componentDidMount中创建的任何监听。</p> <p>12.componentDidCatch(error, info)<br> 错误边界是React组件,可以在其子组件树中的任何位置捕获JavaScript错误,记录这些错误并显示回退UI,而不是崩溃的组件树。错误边界在渲染期间,生命周期方法以及整个树下的构造函数中捕获错误。<br> 如果类组件定义了此生命周期方法,则它将成错误边界。在它中调用setState()可以让你在下面的树中捕获未处理的JavaScript错误,并显示一个后备UI。只能使用错误边界从意外异常中恢复; 不要试图将它们用于控制流程。<br> 错误边界只会捕获树中下面组件中的错误。错误边界本身不能捕获错误。</p> <p>PureComponent<br> PureComponnet里如果接收到的新属性或者是更改后的状态和原属性、原状态相同的话,就不会去重新render了<br> 在里面也可以使用shouldComponentUpdate,而且。是否重新渲染以shouldComponentUpdate的返回值为最终的决定因素。</p> <p>import React, { PureComponent } from ‘react’<br> class YourComponent extends PureComponent {<br> ……<br> }<br> 1<br> 2<br> 3<br> 4<br> ref<br> React提供的这个ref属性,表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例,ref可以挂载到组件上也可以是dom元素上。</p> <p>挂到组件(class声明的组件)上的ref表示对组件实例的引用。不能在函数式组件上使用 ref 属性,因为它们没有实例:<br> 挂载到dom元素上时表示具体的dom元素节点。<br> 在React 最新的版本中,要使用ref, 需要使用React.createRef方法先生成一个ref。<br> import React, { Component, createRef } from ‘react’<br> import ReactDOM from ‘react-dom’<br> class App extends Component {<br> constructor() {<br> super()<br> // 创建inputRef<br> this.inputRef=createRef()<br> }<br> componentDidMount () {<br> console.log(this.inputRef.current) // <br> }<br> render () {<br> return (<br> </p> <div> <br> {/* 关联ref和dom */} <br> </div> <p></p> ) } } ReactDOM.render( , document.getElementById('root') ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 React Hooks React Hooks 是 React 16.7.0-alpha 版本推出的新特性, 有了React Hooks,在 react 函数组件中,也可以使用类组件(classes components)的 state 和 组件生命周期。通过下面几个例子来学习React Hooks。 <p>State Hook<br> // useState是react包提供的一个方法<br> import React, { useState } from “react”;<br> import ReactDOM from “react-dom”;<br> const Counter = () => {<br> // useState 这个方法可以为我们的函数组件拥有自己的state,它接收一个用于初始 state 的值,返回一对变量。这里我们把计数器的初始值设置为0, 方法都是以set开始<br> const [count, setCount] = useState(0);<br> return (</p> <div> <p>你点击了{count}次</p> </div> <p>父组件将自己的状态传递给子组件,子组件当做属性来接收,当父组件更改自己状态的时候,子组件接收到的属性就会发生改变<br> 父组件利用ref对子组件做标记,通过调用子组件的方法以更改子组件的状态,也可以调用子组件的方法…<br> 子组件与父组件通信<br> 父组件将自己的某个方法传递给子组件,在方法里可以做任意操作,比如可以更改状态,子组件通过this.props接收到父组件的方法后调用。<br> 跨组件通信<br> 在react没有类似vue中的事件总线来解决这个问题,我们只能借助它们共同的父级组件来实现,将非父子关系装换成多维度的父子关系。react提供了context api来实现跨组件通信, React 16.3之后的contextapi较之前的好用。<br> 实例,使用context 实现购物车中的加减功能<br> // counterContext.js<br> import React, { Component, createContext } from ‘react’<br> const {<br> Provider,<br> Consumer: CountConsumer<br> } = createContext()<br> class CountProvider extends Component {<br> constructor () {<br> super()<br> this.state = {<br> count: 1<br> }<br> }<br> increaseCount = () => {<br> this.setState({<br> count: this.state.count + 1<br> })<br> }<br> decreaseCount = () => {<br> this.setState({<br> count: this.state.count - 1<br> })<br> }<br> render() {<br> return (<br> <Provider value={{<br> count: this.state.count,<br> increaseCount: this.increaseCount,<br> decreaseCount: this.decreaseCount<br> }}</p> <blockquote></blockquote> <p>{this.props.children}<br> <br> )<br> }<br> }<br> export {<br> CountProvider,<br> CountConsumer<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 24<br> 25<br> 26<br> 27<br> 28<br> 29<br> 30<br> 31<br> 32<br> 33<br> 34<br> 35<br> 36<br> 37<br> 38<br> 39<br> 40<br> // 定义CountButton组件<br> const CountButton = (props) => {<br> return (<br> <br> // consumer的children必须是一个方法<br> {<br> ({ increaseCount, decreaseCount }) => {<br> const { type } = props<br> const handleClick = type === ‘increase’ ? increaseCount : decreaseCount<br> const btnText = type === ‘increase’ ? ‘+’ : ‘-’<br> return {btnText}<br> }<br> }<br> <br> )<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> // 定义count组件,用于显示数量<br> const Count = (prop) => {<br> return (<br> <br> {<br> ({ count }) => {<br> return <span>{count}</span><br> }<br> }<br> <br> )<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> // 组合<br> class App extends Component {<br> render () {<br> return (<br> <br> <br> <br> <br> <br> )<br> }<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 复杂的非父子组件通信在react中很难处理,多组件间的数据共享也不好处理,在实际的工作中我们会使用flux、redux、mobx来实现</p> <p>HOC(高阶组件)<br> Higher-Order Components就是一个函数,传给它一个组件,它返回一个新的组件。</p> <p>const NewComponent = higherOrderComponent(YourComponent)<br> 1<br> 比如,我们想要我们的组件通过自动注入一个版权信息。</p> <p>// withCopyright.js 定义一个高阶组件<br> import React, { Component, Fragment } from ‘react’<br> const withCopyright = (WrappedComponent) => {<br> return class NewComponent extends Component {<br> render() {<br> return (<br> <br> </p> <div> 好好学习,天天向上 </div> ) } } } export default withCopyright 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 使用方式 import withCopyright from './withCopyright' class App extends Component { render () { return ( <div> <h1>Awesome React</h1> <p>React.js是一个构建用户界面的库</p> </div> ) } } const CopyrightApp = withCopyright(App) 1 2 3 4 5 6 7 8 9 10 11 12 13 这样只要我们有需要用到版权信息的组件,都可以直接使用withCopyright这个高阶组件包裹即可。 在这里要讲解在CRA 中配置装饰器模式的支持。 #状态管理 ##传统MVC框架的缺陷 什么是MVC? <p>MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。<br> V即View视图是指用户看到并与之交互的界面。<br> M即Model模型是管理数据 ,很多业务逻辑都在模型中完成。在MVC的三个部件中,模型拥有最多的处理任务。<br> C即Controller控制器是指控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后再确定用哪个视图来显示返回的数据。<br> MVC只是看起来很美<br> MVC框架的数据流很理想,请求先到Controller, 由Controller调用Model中的数据交给View进行渲染,但是在实际的项目中,又是允许Model和View直接通信的</p> <p>Flux<br> 在2013年,Facebook让React亮相的同时推出了Flux框架,React的初衷实际上是用来替代jQuery的,Flux实际上就可以用来替代Backbone.js,Ember.js等一系列MVC架构的前端JS框架。<br> 其实Flux在React里的应用就类似于Vue中的Vuex的作用,但是在Vue中,Vue是完整的mvvm框架,而Vuex只是一个全局的插件。<br> React只是一个MVC中的V(视图层),只管页面中的渲染,一旦有数据管理的时候,React本身的能力就不足以支撑复杂组件结构的项目,在传统的MVC中,就需要用到Model和Controller。Facebook对于当时世面上的MVC框架并不满意,于是就有了Flux, 但Flux并不是一个MVC框架,他是一种新的思想。</p> <p>View: 视图层<br> ActionCreator(动作创造者):视图层发出的消息(比如mouseClick)<br> Dispatcher(派发器):用来接收Actions、执行回调函数<br> Store(数据层):用来存放应用的状态,一旦发生变动,就提醒Views要更新页面<br> Flux的流程:<br> 组件获取到store中保存的数据挂载在自己的状态上<br> 用户产生了操作,调用actions的方法<br> actions接收到了用户的操作,进行一系列的逻辑代码、异步操作<br> 然后actions会创建出对应的action,action带有标识性的属性<br> actions调用dispatcher的dispatch方法将action传递给dispatcher<br> dispatcher接收到action并根据标识信息判断之后,调用store的更改数据的方法<br> store的方法被调用后,更改状态,并触发自己的某一个事件<br> store更改状态后事件被触发,该事件的处理程序会通知view去获取最新的数据<br> Redux<br> React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案。有两个方面,它没涉及。</p> <p>代码结构<br> 组件之间的通信<br> 2013年 Facebook 提出了 Flux 架构的思想,引发了很多的实现。2015年,Redux 出现,将 Flux 与函数式编程结合一起,很短时间内就成为了最热门的前端架构。<br> 如果你不知道是否需要 Redux,那就是不需要它<br> 只有遇到 React 实在解决不了的问题,你才需要 Redux<br> 简单说,如果你的UI层非常简单,没有很多互动,Redux 就是不必要的,用了反而增加复杂性。<br> 用户的使用方式非常简单<br> 用户之间没有协作<br> 不需要与服务器大量交互,也没有使用 WebSocket<br> 视图层(View)只从单一来源获取数据<br> 需要使用Redux的项目:<br> 用户的使用方式复杂<br> 不同身份的用户有不同的使用方式(比如普通用户和管理员)<br> 多个用户之间可以协作<br> 与服务器大量交互,或者使用了WebSocket<br> View要从多个来源获取数据<br> 从组件层面考虑,什么样子的需要Redux:<br> 某个组件的状态,需要共享<br> 某个状态需要在任何地方都可以拿到<br> 一个组件需要改变全局状态<br> 一个组件需要改变另一个组件的状态<br> Redux的设计思想:<br> Web 应用是一个状态机,视图与状态是一一对应的。<br> 所有的状态,保存在一个对象里面(唯一数据源)。<br> 注意:flux、redux都不是必须和react搭配使用的,因为flux和redux是完整的架构,在学习react的时候,只是将react的组件作为redux中的视图层去使用了。<br> Redux的使用的三大原则:</p> <p>Single Source of Truth(唯一的数据源)<br> State is read-only(状态是只读的)<br> Changes are made with pure function(数据的改变必须通过纯函数完成)<br> 自己实现Redux<br> 这个部分,可以根据班级情况看是否讲解。对于学生使用redux有很大的帮助。不使用react,直接使用原生的html/js来写一个简易的的redux<br> 基本的状态管理及数据渲染</p> Redux principle 01 <h1>redux principle</h1> <div class="counter"> <span class="btn">-</span> <span class="count" id="count"></span> <span class="btn" id="add">+</span> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 创建createStore方法 Redux principle 02 <h1>redux principle</h1> <div class="counter"> <span class="btn">-</span> <span class="count" id="count"></span> <span class="btn" id="add">+</span> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 让changeState方法变为一个纯函数 Redux principle 03 <h1>redux principle</h1> <div class="counter"> <span class="btn">-</span> <span class="count" id="count"></span> <span class="btn" id="add">+</span> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 合并state和changeState(最终版) Redux principle 04 <h1>redux principle</h1> <div class="counter"> <span class="btn">-</span> <span class="count" id="count"></span> <span class="btn" id="add">+</span> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 使用Redux框架 Redux的流程: <p>1.store通过reducer创建了初始状态<br> 2.view通过store.getState()获取到了store中保存的state挂载在了自己的状态上<br> 3.用户产生了操作,调用了actions 的方法<br> 4.actions的方法被调用,创建了带有标示性信息的action<br> 5.actions将action通过调用store.dispatch方法发送到了reducer中<br> 6.reducer接收到action并根据标识信息判断之后返回了新的state<br> 7.store的state被reducer更改为新state的时候,store.subscribe方法里的回调函数会执行,此时就可以通知view去重新获取state<br> Reducer必须是一个纯函数:<br> Reducer 函数最重要的特征是,它是一个纯函数。也就是说,只要是同样的输入,必定得到同样的输出。Reducer不是只有Redux里才有,之前学的数组方法reduce, 它的第一个参数就是一个reducer<br> 纯函数是函数式编程的概念,必须遵守以下一些约束。</p> <p>不得改写参数<br> 不能调用系统 I/O 的API<br> 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果<br> 由于 Reducer 是纯函数,就可以保证同样的State,必定得到同样的 View。但也正因为这一点,Reducer 函数里面不能改变 State,必须返回一个全新的对象,请参考下面的写法。<br> // State 是一个对象<br> function reducer(state = defaultState, action) {<br> return Object.assign({}, state, { thingToChange });<br> // 或者<br> return { …state, …newState };<br> }<br> // State 是一个数组<br> function reducer(state = defaultState, action) {<br> return […state, newItem];<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 最好把 State 对象设成只读。要得到新的 State,唯一办法就是生成一个新对象。这样的好处是,任何时候,与某个 View 对应的 State 总是一个不变(immutable)的对象。<br> 我们可以通过在createStore中传入第二个参数来设置默认的state,但是这种形式只适合于只有一个reducer的时候。<br> 划分reducer:<br> 因为一个应用中只能有一个大的state,这样的话reducer中的代码将会特别特别的多,那么就可以使用combineReducers方法将已经分开的reducer合并到一起</p> <p>注意:</p> <p>分离reducer的时候,每一个reducer维护的状态都应该不同<br> 通过store.getState获取到的数据也是会按照reducers去划分的<br> 划分多个reducer的时候,默认状态只能创建在reducer中,因为划分reducer的目的,就是为了让每一个reducer都去独立管理一部分状态<br> 最开始一般基于计数器的例子讲解redux的基本使用即可。<br> 关于action/reducer/store的更多概念,请查看官网<br> Redux异步<br> 通常情况下,action只是一个对象,不能包含异步操作,这导致了很多创建action的逻辑只能写在组件中,代码量较多也不便于复用,同时对该部分代码测试的时候也比较困难,组件的业务逻辑也不清晰,使用中间件了之后,可以通过actionCreator异步编写action,这样代码就会拆分到actionCreator中,可维护性大大提高,可以方便于测试、复用,同时actionCreator还集成了异步操作中不同的action派发机制,减少编码过程中的代码量<br> 常见的异步库:<br> Redux-thunk(就讲这个)<br> Redux-saga<br> Redux-effects<br> Redux-side-effects<br> Redux-loop<br> Redux-observable<br> …<br> 基于Promise的异步库:<br> Redux-promise<br> Redux-promises<br> Redux-simple-promise<br> Redux-promise-middleware<br> …<br> ###容器组件(Smart/Container Components)和展示组件(Dumb/Presentational Components)</p> <table> <thead> <tr> <th align="right"></th> <th align="left">展示组件</th> <th align="left">容器组件</th> </tr> </thead> <tbody> <tr> <td align="right">作用</td> <td align="left">描述如何展现(骨架、样式)</td> <td align="left">描述如何运行(数据获取、状态更新)</td> </tr> <tr> <td align="right">直接使用 Redux</td> <td align="left">否</td> <td align="left">是</td> </tr> <tr> <td align="right">数据来源</td> <td align="left">props</td> <td align="left">监听 Redux state</td> </tr> <tr> <td align="right">数据修改</td> <td align="left">从 props 调用回调函数</td> <td align="left">向 Redux 派发 actions</td> </tr> <tr> <td align="right">调用方式</td> <td align="left">手动</td> <td align="left">通常由 React Redux 生成</td> </tr> </tbody> </table> <p>使用react-redux<br> 可以先结合context来手动连接react和redux。<br> react-redux提供两个核心的api:</p> <p>Provider: 提供store<br> connect: 用于连接容器组件和展示组件<br> Provider<br> 根据单一store原则 ,一般只会出现在整个应用程序的最顶层。<br> connect<br> 语法格式为<br> connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(component)<br> 一般来说只会用到前面两个,它的作用是:<br> 把store.getState()的状态转化为展示组件的props<br> 把actionCreators转化为展示组件props上的方法<br> 特别强调:</p> <p>官网上的第二个参数为mapDispatchToProps, 实际上就是actionCreators<br> 只要上层中有Provider组件并且提供了store, 那么,子孙级别的任何组件,要想使用store里的状态,都可以通过connect方法进行连接。如果只是想连接actionCreators,可以第一个参数传递为null</p> <p>React Router<br> React Router现在的版本是5, 于2019年3月21日搞笑的发布,搞笑的官网链接, 本来是要发布4.4的版本的,结果成了5。从4开始,使用方式相对于之前版本的思想有所不同。之前版本的思想是传统的思想:路由应该统一在一处渲染, Router 4之后是这样的思想:一切皆组件<br> React Router包含了四个包:</p> <p>包名 Description<br> react-router React Router核心api<br> react-router-dom React Router的DOM绑定,在浏览器中运行不需要额外安装react-router<br> react-router-native React Native 中使用,而实际的应用中,其实不会使用这个。<br> react-router-config 静态路由的配置<br> 主要使用react-router-dom</p> <p>使用方式<br> 正常情况下,直接按照官网的demo就理解 路由的使用方式,有几个点需要特别的强调:</p> <p>Route组件的exact属性<br> exact属性标识是否为严格匹配, 为true是表示严格匹配,为false时为正常匹配。<br> Route组件的render属性而不是component属性<br> 怎么在渲染组件的时候,对组件传递属性呢?使用component的方式是不能直接在组件上添加属性的。所以,React Router的Route组件提供了另一种渲染组件的方式 render, 这个常用于页面组件级别的权限管理。<br> 路由的参数传递与获取<br> Switch组件<br> 总是渲染第一个匹配到的组件<br> 处理404与默认页<br> withRoute高阶组件的使用<br> 管理一个项目路由的方法<br> code spliting<br> HashRouter和BrowserRouter的区别,前端路由和后端路由的区别。这个在Vue里应该有讲过了。<br> React Router基本原理<br> React Router甚至大部分的前端路由都是依赖于history.js的,它是一个独立的第三方js库。可以用来兼容在不同浏览器、不同环境下对历史记录的管理,拥有统一的API。</p> <p>老浏览器的history: 通过hash来存储在不同状态下的history信息,对应createHashHistory,通过检测location.hash的值的变化,使用location.replace方法来实现url跳转。通过注册监听window对象上的hashChange事件来监听路由的变化,实现历史记录的回退。<br> 高版本浏览器: 利用HTML5里面的history,对应createBrowserHistory, 使用包括pushState, replaceState方法来进行跳转。通过注册监听window对象上的popstate事件来监听路由的变化,实现历史记录的回退。<br> node环境下: 在内存中进行历史记录的存储,对应createMemoryHistory。直接在内存里push和pop状态。<br> Immutable.js<br> JavaScript数据修改的问题<br> 看一段大家熟悉的代码</p> <p>const state = {<br> str: ‘好好学习’,<br> obj: {<br> y: 1<br> },<br> arr: [1, 2, 3]<br> }<br> const newState = state<br> console.log(newState === state) // true<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 由于js的对象和数组都是引用类型。所以newState的state实际上是指向于同一块内存地址的, 所以结果是newState和state是相等的。<br> 尝试修改一下数据</p> <p>const state = {<br> str: ‘好好学习’,<br> obj: {<br> y: 1<br> },<br> arr: [1, 2, 3]<br> }<br> const newState = state<br> newState.str = ‘好好学习,天天向上’<br> console.log(state.str, newState.str)<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 可以看到,newState的修改也会引起state的修改。要解决这个问题,js中提供了另一种修改数据的方式,要修改一个数据之前先制作一份数据的拷贝,像这样</p> <p>const state = {<br> str: ‘好好学习’,<br> obj: {<br> y: 1<br> },<br> arr: [1, 2, 3]<br> }<br> const newState = Object.assign({}, state)<br> newState.str = ‘好好学习,天天向上’<br> console.log(state.str, newState.str)<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 我们可以使用很多方式在js中复制数据,比如…, Object.assign, Object.freeze, slice, concat, map, filter, reduce等方式进行复制,但这些都是浅拷贝,就是只拷贝第一层数据,更深层的数据还是同一个引用,比如:</p> <p>const state = {<br> str: ‘好好学习’,<br> obj: {<br> y: 1<br> },<br> arr: [1, 2, 3]<br> }<br> const newState = Object.assign({}, state)<br> newState.obj.y = 2<br> newState.arr.push(4)<br> console.log(state, newState)<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 可以看到,当在更改newState更深层次的数据的时候,还是会影响到state的值。如果要深层复制,就得一层一层的做递归拷贝,这是一个复杂的问题。虽然有些第三方的库已经帮我们做好了,比如lodash的cloneDeep方法。深拷贝是非常消耗性能的。</p> <p>import { cloneDeep } from ‘lodash’<br> const state = {<br> str: ‘好好学习’,<br> obj: {<br> y: 1<br> },<br> arr: [1, 2, 3]<br> }<br> const newState = cloneDeep(state)<br> newState.obj.y = 2<br> newState.arr.push(4)<br> console.log(state, newState)<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 什么是不可变数据<br> 不可变数据 (Immutable Data )就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是持久化数据结构( Persistent Data Structure),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的s性能损耗,Immutable 使用了 结构共享(Structural Sharing),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。</p> <p>immutable.js的优缺点<br> 优点:</p> <p>降低mutable带来的复杂度<br> 节省内存<br> 历史追溯性(时间旅行):时间旅行指的是,每时每刻的值都被保留了,想回退到哪一步只要简单的将数据取出就行,想一下如果现在页面有个撤销的操作,撤销前的数据被保留了,只需要取出就行,这个特性在redux或者flux中特别有用<br> 拥抱函数式编程:immutable本来就是函数式编程的概念,纯函数式编程的特点就是,只要输入一致,输出必然一致,相比于面向对象,这样开发组件和调试更方便。推荐一本函数式编程的在线免费书《JS 函数式编程指南》, 此书可以推荐给学生做为课外补充阅读。<br> 缺点:<br> 需要重新学习api<br> 资源包大小增加(源码5000行左右)<br> 容易与原生对象混淆:由于api与原生不同,混用的话容易出错。<br> 使用Immutable.js<br> 参考官网重点讲解数据不可变数据的创建、更新及比较方式 。对于就业班来说,掌握以下知识点即可。</p> <p>Map<br> import { Map } from ‘immutable’<br> const map = Map({<br> a: 1,<br> b: 2,<br> c: 3<br> })<br> const newMap = map.set(‘b’, 20) // immutable数据每次都是生成新的再重新调用set进行修改,所以需要 重新赋值给一个新的变量<br> console.log(map, newMap) // immutable.Map不是原生的对象<br> console.log(map.b, newMap.b) // immutable.Map不是原生的对象, 所以是undefined<br> console.log(map.get(‘b’), newMap.get(‘b’)) // 要取值,需要调用get(key)方法,可以看到,两个值不一样<br> const obj = {<br> a: 1,<br> b: 2,<br> c: 3<br> }<br> console.log(Map.isMap(map), Map.isMap(obj)) // true false, 使用Map.isMap来判断是否是一个immutable.Map类型<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> List<br> import { List } from ‘immutable’<br> const list = List([1, 2, 3, 4])<br> const newList = list.push(5)<br> console.log(list, newList)<br> console.log(list[4], newList[4]) // undefined undefined<br> console.log(list.get(4), newList.get(4)) // undefined 5<br> console.log(list.size, newList.size) // 4 5<br> const arr = [1, 2, 3, 4]<br> console.log(List.isList(list), List.isList(arr)) // true false<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> equals & is<br> import { Map, is } from ‘immutable’<br> const map = Map({<br> a: 1,<br> b: 2,<br> c: 3<br> })<br> const anotherMap = Map({<br> a: 1,<br> b: 2,<br> c: 3<br> })<br> console.log(map == anotherMap) // false<br> console.log(map === anotherMap) // false<br> console.log(map.equals(anotherMap)) // 使用equals进行比较 true<br> console.log(is(map, anotherMap)) // 使用is进行比较 true<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> List常用api<br> import { List } from ‘immutable’<br> const list = List([1, 2, 3, 4])<br> const list1 = list.push(5)<br> const list2 = list1.unshift(0)<br> const list3 = list.concat(list1, list2)<br> const list4 = list.map(v => v * 2)<br> console.log(list.size, list1.size, list2.size, list3.size, list4.toJS()) // 4 5 6 15, [2, 4, 6, 8]<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> Map常用api<br> import { Map } from ‘immutable’<br> const alpha = Map({<br> a: 1,<br> b: 2,<br> c: 3<br> })<br> const objKeys = alpha.map((v, k) => k)<br> console.log(objKeys.join()) // a, b, c<br> const map1 = Map({<br> a: 1,<br> b: 2<br> })<br> const map2 = Map({<br> c: 3,<br> d: 4<br> })<br> const obj = {<br> d: 400,<br> e: 50<br> }<br> const mergedMap = map1.merge(map2, obj)<br> console.log(mergedMap.toObject())<br> console.log(mergedMap.toJS())<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> 16<br> 17<br> 18<br> 19<br> 20<br> 21<br> 22<br> 23<br> 嵌套数据结构<br> const { fromJS } = require(‘immutable’);<br> const nested = fromJS({ a: { b: { c: [ 3, 4, 5 ] } } });<br> const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } });<br> // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } }<br> console.log(nested2.getIn([ ‘a’, ‘b’, ‘d’ ])); // 6<br> const nested3 = nested2.updateIn([ ‘a’, ‘b’, ‘d’ ], value => value + 1);<br> console.log(nested3);<br> // Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } }<br> const nested4 = nested3.updateIn([ ‘a’, ‘b’, ‘c’ ], list => list.push(6));<br> // Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 在redux中使用immutable.js<br> redux官网推荐使用redux-immutable进行redux和immutable的集成。几个注意点:<br> redux中,利用combineReducers来合并多个reduce, redux自带的combineReducers只支持原生js形式的,所以需要使用redux-immutable提供的combineReducers来代替</p> <p>// 使用redux-immutable提供的combineReducers方法替换redux里的combineReducers<br> import {combineReducers} from ‘redux-immutable’<br> import reducerOne from ‘./reducerOne’<br> import reducerTwo from ‘./reducerTwo’<br> const rootReducer = combineReducers({<br> reducerOne,<br> reducerTwo<br> });<br> export default rootReducer;<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> reducer中的initialState也需要初始化成immutable类型, 比如一个counter的reducer</p> <p>import { Map } from ‘immutable’<br> import ActionTypes from ‘…/actions’<br> const initialState = Map({<br> count: 0<br> })<br> export default (state = initialState, action) => {<br> switch (action.type) {<br> case ActionTypes.INCREAMENT:<br> return state.set(‘count’, state.get(‘count’) + 1) // 使用set或setIn来更改值, get或者getIn来取值<br> case ActionTypes.DECREAMENT:<br> return state.set(‘count’, state.get(‘count’) - 1)<br> default:<br> return state<br> }<br> }<br> 1<br> 2<br> 3<br> 4<br> 5<br> 6<br> 7<br> 8<br> 9<br> 10<br> 11<br> 12<br> 13<br> 14<br> 15<br> state成为了immutable类型,connect的mapStateToProp也需要相应的改变</p> <p>const mapStateToProps = state => ({<br> count: state.getIn([‘counter’, ‘count’]) // 永远不要在mapStateToProps里使用<code>toJS</code>方法,因为它永远返回一个新的对象<br> })<br> 1<br> 2<br> 3<br> 在shouldComponentUpdate里就可以使用immutable.is或者instance.equals来进行数据的对比了。</p> <p>Mobx<br> Mobx是一个功能强大,上手非常容易的状态管理工具。redux的作者也曾经向大家推荐过它,在不少情况下可以使用Mobx来替代掉redux。</p> <p>这张图来自于官网,把这张图理解清楚了。基本上对于mobx的理解就算入门了。<br> 官网有明确的核心概念使用方法,并配有egghead的视频教程。这里就不一一赘述了。<br> 要特别注意当使用 mobx-react 时可以定义一个新的生命周期钩子函数 componentWillReact。当组件因为它观察的数据发生了改变,它会安排重新渲染,这个时候 componentWillReact 会被触发。这使得它很容易追溯渲染并找到导致渲染的操作(action)。</p> <p>componentWillReact 不接收参数<br> componentWillReact 初始化渲染前不会触发 (使用 componentWillMount 替代)<br> componentWillReact 对于 mobx-react@4+, 当接收新的 props 时并在 setState 调用后会触发此钩子<br> 要触发componentWillReact必须在render里面用到被观察的变量<br> 使用Mobx之后不会触发componentWillReceiveProps</p> <div class="more-toolbox"> <div class="left-toolbox"> <ul class="toolbox-list"> <pre><code> <li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#csdnc-thumbsup"></use> </svg><span class="name">点赞</span> <span class="count"></span> </a></li> <li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{"mod":"popu_824"}"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-Collection-G"></use> </svg><span class="name">收藏</span></a></li> <li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"> <use xlink:href="#icon-csdnc-fenxiang"></use> </svg>分享</a></li> <!--打赏开始--> <!--打赏结束--> <li class="tool-item tool-more"> <a> <svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg> </a> <ul class="more-box"> <li class="item"><a class="article-report">文章举报</a></li> </ul> </li> </ul> </div> </div> <div class="person-messagebox"> <div class="left-message"><a href="https://blog.csdn.net/xuwei1215225"> <img src="https://profile.csdnimg.cn/0/1/B/3_xuwei1215225" class="avatar_pic" username="xuwei1215225"> <img src="https://g.csdnimg.cn/static/user-reg-year/2x/1.png" class="user-years"> </a></div> <div class="middle-message"> <div class="title"><span class="tit"><a href="https://blog.csdn.net/xuwei1215225" data-report-click="{"mod":"popu_379"}" target="_blank">搞前端的正则妈</a></span> </div> <div class="text"><span>发布了23 篇原创文章</span> · <span>获赞 17</span> · <span>访问量 2691</span></div> </div> <div class="right-message"> <a href="https://im.csdn.net/im/main.html?userName=xuwei1215225" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-letter">私信 </a> <a class="btn btn-sm bt-button personal-watch" data-report-click="{"mod":"popu_379"}">关注</a> </div> </div> </div> </code></pre> </ul> </div> </div> </div> </div> </div> </div> </div> </div> <!--PC和WAP自适应版--> <div id="SOHUCS" sid="1293178664355176448"></div> <script type="text/javascript" src="/views/front/js/chanyan.js"></script> <!-- 文章页-底部 动态广告位 --> <div class="youdao-fixed-ad" id="detail_ad_bottom"></div> </div> <div class="col-md-3"> <div class="row" id="ad"> <!-- 文章页-右侧1 动态广告位 --> <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_1"> </div> </div> <!-- 文章页-右侧2 动态广告位 --> <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_2"></div> </div> <!-- 文章页-右侧3 动态广告位 --> <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad"> <div class="youdao-fixed-ad" id="detail_ad_3"></div> </div> </div> </div> </div> </div> </div> <div class="container"> <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(React)</h4> <div id="paradigm-article-related"> <div class="recommend-post mb30"> <ul class="widget-links"> <li><a href="/article/1835492740536823808.htm" title="node.js学习" target="_blank">node.js学习</a> <span class="text-muted">小猿L</span> <a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/vim/1.htm">vim</a> <div>node.js学习实操及笔记温故node.js,node.js学习实操过程及笔记~node.js学习视频node.js官网node.js中文网实操笔记githubcsdn笔记为什么学node.js可以让别人访问我们编写的网页为后续的框架学习打下基础,三大框架vuereactangular离不开node.jsnode.js是什么官网:node.js是一个开源的、跨平台的运行JavaScript的运行</div> </li> <li><a href="/article/1835448111909138432.htm" title="react-intl——react国际化使用方案" target="_blank">react-intl——react国际化使用方案</a> <span class="text-muted">苹果酱0567</span> <a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95%E9%A2%98%E6%B1%87%E6%80%BB%E4%B8%8E%E8%A7%A3%E6%9E%90/1.htm">面试题汇总与解析</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E9%97%B4%E4%BB%B6/1.htm">中间件</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a> <div>国际化介绍i18n:internationalization国家化简称,首字母+首尾字母间隔的字母个数+尾字母,类似的还有k8s(Kubernetes)React-intl是React中最受欢迎的库。使用步骤安装#usenpmnpminstallreact-intl-D#useyarn项目入口文件配置//index.tsximportReactfrom"react";importReactDOMf</div> </li> <li><a href="/article/1835411044768509952.htm" title="字节二面" target="_blank">字节二面</a> <span class="text-muted">Redstone Monstrosity</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a> <div>1.假设你是正在面试前端开发工程师的候选人,面试官让你详细说出你上一段实习过程的收获和感悟。在上一段实习过程中,我获得了宝贵的实践经验和深刻的行业洞察,以下是我的主要收获和感悟:一、专业技能提升框架应用熟练度:通过实际项目,我深入掌握了React、Vue等前端框架的使用,不仅提升了编码效率,还学会了如何根据项目需求选择合适的框架。问题解决能力:在实习期间,我遇到了许多预料之外的技术难题。通过查阅文</div> </li> <li><a href="/article/1835398064727224320.htm" title="前端代码上传文件" target="_blank">前端代码上传文件</a> <span class="text-muted">余生逆风飞翔</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>点击上传文件import{ElNotification}from'element-plus'import{API_CONFIG}from'../config/index.js'import{UploadFilled}from'@element-plus/icons-vue'import{reactive}from'vue'import{BASE_URL}from'../config/index'i</div> </li> <li><a href="/article/1835133874892533760.htm" title="前端使用react-intl-universal进行国际化" target="_blank">前端使用react-intl-universal进行国际化</a> <span class="text-muted">Stephy_Yy</span> <a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/%E8%B0%83%E7%A0%94/1.htm">调研</a><a class="tag" taget="_blank" href="/search/reactjs/1.htm">reactjs</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a> <div>一、国际化/i18n目前国际化,就是开发者写对象,一个key关联若干语种的翻译。相比于浏览器自带的翻译功能,语义更加准确。“国际化”的简称:i18n(其来源是英文单词internationalization的首末字符i和n,18为中间的字符数)二、react项目国际化react-intl是业界最受欢迎的软件包之一:React-intl是雅虎的语言国际化开源项目FormatJS的一部分,通过其提供的</div> </li> <li><a href="/article/1835101722159181824.htm" title="VUE实现大小缩放轮播图" target="_blank">VUE实现大小缩放轮播图</a> <span class="text-muted">书边事.</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>效果图import{ref,computed,reactive,watch,onMounted}from'vue';exportdefault{props:{/***轮播数据来源*/source:{type:Array,default:()=>[{img:require('@/assets/imgs/test/1.png')},{img:require('@/assets/imgs/test/1.</div> </li> <li><a href="/article/1835089183857799168.htm" title="react里的index.js是怎么跟index.html结合起来的?" target="_blank">react里的index.js是怎么跟index.html结合起来的?</a> <span class="text-muted">SherrinfordL</span> <div>image.pngcreate-react-app把webpack、babel等配置都封装到了依赖项目react-script中,所以你无法直观的看到这些配置。你可以在项目下运行npmruneject,被隐藏的配置文件就会暴露到项目根路径下。把请求转发到index.html原因是,你执行npmrunstart时,启动的webpack-dev-server,会加载react-script项目conf</div> </li> <li><a href="/article/1835085841114951680.htm" title="Taro实现微信小程序自定义拍照截图识别" target="_blank">Taro实现微信小程序自定义拍照截图识别</a> <span class="text-muted">书边事.</span> <a class="tag" taget="_blank" href="/search/taro/1.htm">taro</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a> <div>效果图:代码:>请对准框内拍摄题目重新拍照文件处理中...开始识别definePageConfig({navigationStyle:"custom",navigationBarTitleText:"",//启用页面分享//enableShareAppMessage:true,//启动朋友圈分享//enableShareTimeline:true});import{reactive,toRefs,</div> </li> <li><a href="/article/1835053432449363968.htm" title="(小白入门)Windows环境下搭建React Native Android开发环境" target="_blank">(小白入门)Windows环境下搭建React Native Android开发环境</a> <span class="text-muted">码农老黑</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/Native/1.htm">Native</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a> <div>ReactNative(简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架React在原生移动应用平台的衍生产物,目前支持iOS和Android两大平台。RN的环境搭建在RN的中文社区有所介绍,但是对于小白来说还是有些太过简略了。RN中文社区详见参考,本文不涉及的问题也许在其中能够有所解答。ReactNative思想底层引擎是JavaSc</div> </li> <li><a href="/article/1834965176286277632.htm" title="react中如何获取并使用usestate声明的变量的值" target="_blank">react中如何获取并使用usestate声明的变量的值</a> <span class="text-muted">小华0000</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>1.函数式更新当需要根据当前状态来更新状态时,可以使用函数式更新。setState(在类组件中)和setCount(在useState中)都可以接受一个函数作为参数,这个函数接收当前的状态作为参数,并返回新的状态。functionExampleComponent(){const[count,setCount]=useState(0);//使用函数式更新functionhandleClick(){s</div> </li> <li><a href="/article/1834963412711469056.htm" title="【Vue3源码实现】Ref isRef unRef proxyRefs实现" target="_blank">【Vue3源码实现】Ref isRef unRef proxyRefs实现</a> <span class="text-muted">ZhaiMou</span> <a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>前言在上篇文章中我们了解了响应式原理,并在最后实现了reactive。上文链接Vue3响应式原理实现与track和trigger依赖收集和触发依赖在我们的日常业务中,我们有可能需要将一个基础数据类型的值也转换成响应式的,而reactive只能代理对象,我们需要对基础数据类型的值也进行读写操作的拦截,但Proxy无法实现对基础数据类型值读写操作的拦截。所以Vue设计了Ref,以及相关api本篇文章实</div> </li> <li><a href="/article/1834963034653683712.htm" title="React 前端应用结合 Nginx 部署指南及常见错误排查" target="_blank">React 前端应用结合 Nginx 部署指南及常见错误排查</a> <span class="text-muted">蜗牛去旅行吧</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/nginx/1.htm">nginx</a> <div>在现代Web开发中,React已成为构建用户界面的流行选择,而Nginx则是一个高性能的Web服务器,广泛用于静态文件的托管和负载均衡。在本篇博客中,我们将详细介绍如何将一个React应用部署到Nginx上,并探讨在部署过程中可能遇到的常见错误及其解决方案。部署步骤1.准备React应用首先,确保你已经创建了一个React应用。如果还没有,可以使用CreateReactApp快速生成一个基础项目:</div> </li> <li><a href="/article/1834961772746993664.htm" title="vue3 响应性API" target="_blank">vue3 响应性API</a> <span class="text-muted">weixin_44747590</span> <a class="tag" taget="_blank" href="/search/vue3/1.htm">vue3</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/js/1.htm">js</a> <div>toRef可以用来为源响应式对象上的property性创建一个ref。然后可以将ref传递出去,从而保持对其源property的响应式连接。本质类似指针引用。举例:conststate=reactive({foo:1,bar:2})constfooRef=toRef(state,'foo')fooRef.value++console.log(state.foo)//2state.foo++cons</div> </li> <li><a href="/article/1834957860375719936.htm" title="手撸vue3核心源码——响应式原理(isRef和unRef)" target="_blank">手撸vue3核心源码——响应式原理(isRef和unRef)</a> <span class="text-muted">前端不是渣男</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a> <div>今天来实现一下ref的功能函数,isRef与unRefisRefisRef和isReactive一样,都是用于检测数据类型,isRef是检测是不是一个ref对象,跟isReactive函数实现起来一样,我们先来写一个单元测试这里要实现的功能是,检测ref对象肯定就通过返回true,检测普通类型数据以及reactive对象都是falseit("itshouldreturnaboolean",()=></div> </li> <li><a href="/article/1834957104239177728.htm" title="vue3 | isRef、unref、toRef、toRefs" target="_blank">vue3 | isRef、unref、toRef、toRefs</a> <span class="text-muted">杨贵妃会飞飞飞</span> <a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a> <div>isRef检查某个值是否是ref。是返回true,否则返回false。constnum=ref(10)constnum1=20constnum2=reactive({data:30})console.log(isRef(num))//trueconsole.log(isRef(num1))//falseconsole.log(isRef(num2))//falseunref()如果参数是ref,则</div> </li> <li><a href="/article/1834953567916617728.htm" title="vue学习笔记——关于对Vue3 ref(), toRef(), toRefs(), unref(), isRef(), reactive()方法的理解。" target="_blank">vue学习笔记——关于对Vue3 ref(), toRef(), toRefs(), unref(), isRef(), reactive()方法的理解。</a> <span class="text-muted">chen_sir_sh</span> <a class="tag" taget="_blank" href="/search/vue%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/1.htm">vue学习笔记</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a> <div>VUE3出现了很多新的API,下面是自己的一些理解进行的总结。欢迎大家一起交流补充。ref()使用ref创建一个数据类型,ref有value这个属性constname1={age:"14",name:"bob1"};constname2=ref({name:"bob2"});//使用ref创建一个数据类型相对于reactive,ref有value属性name2.value="bob3"consol</div> </li> <li><a href="/article/1834951677422170112.htm" title="React项目的开发前准备 以及 JSX 的基本使用" target="_blank">React项目的开发前准备 以及 JSX 的基本使用</a> <span class="text-muted">渡鸦七</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a> <div>React项目的开发前准备以及JSX的基本使用React项目创建create-react-appnpxcreate-react-appmy-appcdmy-appnpmstartyarncreatereact-appyarncreatereact-appmy-appcdmy-appyarnstartcreate-react-app和yarncreatereact-app都可以快速创建一个React</div> </li> <li><a href="/article/1834950166029889536.htm" title="react 函数组件useState异步变同步" target="_blank">react 函数组件useState异步变同步</a> <span class="text-muted">MIKE-zi</span> <a class="tag" taget="_blank" href="/search/react%E5%85%A5%E9%97%A8/1.htm">react入门</a><a class="tag" taget="_blank" href="/search/setstate%E5%BC%82%E6%AD%A5%E9%97%AE%E9%A2%98/1.htm">setstate异步问题</a><a class="tag" taget="_blank" href="/search/%E5%87%BD%E6%95%B0%E7%BB%84%E4%BB%B6%E5%AE%9E%E7%8E%B0%E5%88%86%E9%A1%B5/1.htm">函数组件实现分页</a><a class="tag" taget="_blank" href="/search/%E5%87%BD%E6%95%B0%E7%BB%84%E4%BB%B6%E4%B8%8A%E6%8B%89%E5%8A%A0%E8%BD%BD/1.htm">函数组件上拉加载</a> <div>需求函数组件实现一个下拉上拉的列表,列表支持分页。最开始我们使用setstate的方式去报错当前页数。这样做的问题,就是有一个异步的延迟。上代码const[pageNo,setpageNo]=useState(1)constonPullUpRefresh=()=>{console.log("上拉加载内容")console.log("上一次的pageNo",pageNo)setpageNo(page</div> </li> <li><a href="/article/1834844033856401408.htm" title="Netty权威指南:Netty总结-高性能与可靠性" target="_blank">Netty权威指南:Netty总结-高性能与可靠性</a> <span class="text-muted">Ty_1106</span> <a class="tag" taget="_blank" href="/search/Netty/1.htm">Netty</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/rpc/1.htm">rpc</a> <div>第二十二章高性能之道22.1RPC调用性能模型分析22.1.1传统RPC调用性能差三宗罪:网络传输采用同步阻塞I/O导致经常性阻塞序列化性能差线程模型问题22.1.2I/O通信性能三要素传输:BIO、NIO或者AIO协议:HTTP公有协议,内部私有协议线程:数据报如何读取,Reactor线程模型22.2Netty高性能之道22.2.1异步非阻塞通信I/O多路复用技术22.2.2高效的Reactor</div> </li> <li><a href="/article/1834835713846243328.htm" title="Vue 和 React 的对比" target="_blank">Vue 和 React 的对比</a> <span class="text-muted">淘淘是只狗</span> <a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>React和Vue有许多相似之处:使用VirtualDOM提供了响应式(Reactive)和组件化(Composable)的视图组件。将注意力集中保持在核心库,而将其他功能如路由和全局状态管理交给相关的库。运行时性能React在React应用中,当某个组件的状态发生变化时,它会以该组件为根,重新渲染整个组件子树。如要避免不必要的子组件的重渲染,你需要在所有可能的地方使用PureComponent,</div> </li> <li><a href="/article/1834832435699871744.htm" title="一文让你彻底弄懂Redux的基本原理以及其如何在React中使用!" target="_blank">一文让你彻底弄懂Redux的基本原理以及其如何在React中使用!</a> <span class="text-muted">tabzzz</span> <a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a> <div>文章目录什么是Redux?它有什么用Redux基本原理Redux在React中具体使用的方法ReduxToolkit(RTK)createSlice函数参数返回值示例configureStore函数参数返回值示例React-ReduxProvider组件示例React组件使用store中的数据useSelector钩子函数示例connect组件mapStateToPropsmapDispatchT</div> </li> <li><a href="/article/1834831738988228608.htm" title="react 更新元素状态" target="_blank">react 更新元素状态</a> <span class="text-muted">叶绿素yls</span> <div>所有的react元素都是immutable不可变的。当元素被创建之后,我们无法修改他的内容或属性。根据我们现在所学的react的知识,我们要更新元素的内容,我们必须重新渲染这个元素,也就是重新创建这个元素。看一个例子:functiontick(){constelement=Hello,worldItis{newDate().toLocaleString()}.;ReactDOM.render(el</div> </li> <li><a href="/article/1834817300432252928.htm" title="Reactive 编程-Vert.x" target="_blank">Reactive 编程-Vert.x</a> <span class="text-muted">Flying_Fish_Xuan</span> <a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a> <div>Reactive编程与Vert.x:高效异步Java微服务框架一、什么是Reactive编程?Reactive编程是一种异步编程范式,专注于数据流和事件的传播处理。与传统的阻塞式编程不同,Reactive编程能够更好地处理高并发和异步操作,特别适合实时系统、流处理以及需要快速响应的场景。Reactive编程的核心原则包括:响应性(Responsive):系统能够快速响应用户请求,并保持低延迟。弹性</div> </li> <li><a href="/article/1834793357197537280.htm" title="生成一个完整的App代码通常不会仅仅通过单一的文件或几种语言的简单组合来完成,因为App的开发涉及前端用户界面、后端逻辑处理、数据库管理以及可能的第三方服务集成等多个方面。不过,我可以为你提供一个概念" target="_blank">生成一个完整的App代码通常不会仅仅通过单一的文件或几种语言的简单组合来完成,因为App的开发涉及前端用户界面、后端逻辑处理、数据库管理以及可能的第三方服务集成等多个方面。不过,我可以为你提供一个概念</a> <span class="text-muted">NewmanEdwarda2</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a> <div>前端(用户界面)yinanjinying.comHTML/CSS/JavaScript(原生Web开发)对于简单的WebApp,你可以直接使用HTML来构建页面结构,CSS来设置样式,JavaScript来添加交互性。React(JavaScript/TypeScript)对于更复杂的单页应用(SPA),React是一个流行的选择。它允许你构建可复用的UI组件。Flutter(Dart)如果你想要</div> </li> <li><a href="/article/1834722761373741056.htm" title="react native ScrollView实现滑动锚定,滑动到指定位置" target="_blank">react native ScrollView实现滑动锚定,滑动到指定位置</a> <span class="text-muted">君君yui</span> <a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/native/1.htm">native</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a> <div>实现ScrollView滑动视图组件滑动到指定位置,实现tab与具体位置相锚定给需要锚定的组件加上onLayout属性//event.nativeEvent.layout.x是水平方向值,event.nativeEvent.layout.y是数值方向值//this.layoutList用于存储组件位置onLayout={(event)=>{this.layoutList.push(event.na</div> </li> <li><a href="/article/1834722508675313664.htm" title="reactnative 获取定位_React-native实现定位的功能" target="_blank">reactnative 获取定位_React-native实现定位的功能</a> <span class="text-muted">weixin_39644915</span> <a class="tag" taget="_blank" href="/search/reactnative/1.htm">reactnative</a><a class="tag" taget="_blank" href="/search/%E8%8E%B7%E5%8F%96%E5%AE%9A%E4%BD%8D/1.htm">获取定位</a> <div>1、在React-native中实现定位的功能的几种方式。(1).使用rn中的自带的Geolocation实现定位。(2).用第三放库react-native-location实现定位。2.用rn中自带的Geolocation实现定位的详细步骤:(1).如果是android进行定位手下是需要权限的通过以下代码设置权限:(2).直接通过navigator.geolocation来进行定位,示例代码如</div> </li> <li><a href="/article/1834711914299617280.htm" title="React Native动画的锚点anchorPoint" target="_blank">React Native动画的锚点anchorPoint</a> <span class="text-muted">沉默的依恋</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/Native/1.htm">Native</a> <div>在RN动画开发的过程中,有需求让图片绕中心点以外的其它点旋转,本以为是一个简单的问题,猜想Facebook应该有提供类似的API.然而在官网找了一圈没有anchorPoint这个API,后来想了想,RN与H5非常像,应该有transformOrigin这个属性,然而,还是没有,在github的issues中有人提问过什么时候更新这个属性,但是官网仍旧没有计划;为了达到这种效果,其实有一种间接的方法</div> </li> <li><a href="/article/1834705361693667328.htm" title="基于react native的锚点" target="_blank">基于react native的锚点</a> <span class="text-muted">miao_zz</span> <a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react-native/1.htm">react-native</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/native/1.htm">native</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a> <div>基于reactnative的锚点效果示例图示例代码效果示例图示例代码/*eslint-disablereact-native/no-inline-styles*/importReact,{useEffect,useRef,useState}from'react';import{Image,ImageBackground,ScrollView,StyleSheet,Text,TouchableOpa</div> </li> <li><a href="/article/1834673478599536640.htm" title="vue2与vue3的区别" target="_blank">vue2与vue3的区别</a> <span class="text-muted">longfan_</span> <a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a> <div>1.vue2和vue3响应式原理发生了改变vue2的响应式原理是利⽤es5的⼀个API,Object.defineProperty()对数据进⾏劫持结合发布订阅模式的⽅式来实现的。vue3中使⽤了es6的proxyAPI对数据代理,通过reactive()函数给每⼀个对象都包⼀层Proxy,通过Proxy监听属性的变化,从⽽实现对数据的监控。这⾥是引相⽐于vue2版本,使⽤proxy的优势如下1.</div> </li> <li><a href="/article/1834617504568274944.htm" title="前后端分离,Asp.net core webapi 如何配置跨域" target="_blank">前后端分离,Asp.net core webapi 如何配置跨域</a> <span class="text-muted">代码掌控者</span> <a class="tag" taget="_blank" href="/search/C%23/1.htm">C#</a><a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a><a class="tag" taget="_blank" href="/search/core/1.htm">core</a><a class="tag" taget="_blank" href="/search/%E7%BB%8F%E9%AA%8C%E5%88%86%E4%BA%AB/1.htm">经验分享</a><a class="tag" taget="_blank" href="/search/c%23/1.htm">c#</a> <div>前言可以说,前后端分离已经成为当今信息系统项目开发的主流软件架构模式,微服务的出现,让前后端分离发展更是迅速,大量优秀的前端框架如vue.js、react的出现,也让前后端分离趋势加快。所谓的前后端分离软件架构模式,就是指将前端和后端的开发完全分离,后端负责提供API接口和数据处理,而前端通过各种现代的JavaScript技术如AJAX或者Fetch等,来调用后端提供的API接口获取数据,从而构建</div> </li> <li><a href="/article/83.htm" title="java线程的无限循环和退出" target="_blank">java线程的无限循环和退出</a> <span class="text-muted">3213213333332132</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>最近想写一个游戏,然后碰到有关线程的问题,网上查了好多资料都没满足。 突然想起了前段时间看的有关线程的视频,于是信手拈来写了一个线程的代码片段。 希望帮助刚学java线程的童鞋 package thread; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date</div> </li> <li><a href="/article/210.htm" title="tomcat 容器" target="_blank">tomcat 容器</a> <span class="text-muted">BlueSkator</span> <a class="tag" taget="_blank" href="/search/tomcat/1.htm">tomcat</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/servlet/1.htm">servlet</a> <div>Tomcat的组成部分 1、server A Server element represents the entire Catalina servlet container. (Singleton) 2、service service包括多个connector以及一个engine,其职责为处理由connector获得的客户请求。   3、connector 一个connector</div> </li> <li><a href="/article/337.htm" title="php递归,静态变量,匿名函数使用" target="_blank">php递归,静态变量,匿名函数使用</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a><a class="tag" taget="_blank" href="/search/%E9%80%92%E5%BD%92%E5%87%BD%E6%95%B0/1.htm">递归函数</a><a class="tag" taget="_blank" href="/search/%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0/1.htm">匿名函数</a><a class="tag" taget="_blank" href="/search/%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F/1.htm">静态变量</a><a class="tag" taget="_blank" href="/search/%E5%BC%95%E7%94%A8%E4%BC%A0%E5%8F%82/1.htm">引用传参</a> <div>  <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Current To-Do List</title> </head> <body></div> </li> <li><a href="/article/464.htm" title="属性颜色字体变化" target="_blank">属性颜色字体变化</a> <span class="text-muted">周华华</span> <a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a> <div>function changSize(className){ var diva=byId("fot") diva.className=className; } </script> <style type="text/css"> .max{ background: #900; color:#039; </div> </li> <li><a href="/article/591.htm" title="将properties内容放置到map中" target="_blank">将properties内容放置到map中</a> <span class="text-muted">g21121</span> <a class="tag" taget="_blank" href="/search/properties/1.htm">properties</a> <div>代码比较简单: private static Map<Object, Object> map; private static Properties p; static { //读取properties文件 InputStream is = XXX.class.getClassLoader().getResourceAsStream("xxx.properti</div> </li> <li><a href="/article/718.htm" title="[简单]拼接字符串" target="_blank">[简单]拼接字符串</a> <span class="text-muted">53873039oycg</span> <a class="tag" taget="_blank" href="/search/%E5%AD%97%E7%AC%A6%E4%B8%B2/1.htm">字符串</a> <div>         工作中遇到需要从Map里面取值拼接字符串的情况,自己写了个,不是很好,欢迎提出更优雅的写法,代码如下:           import java.util.HashMap; import java.uti</div> </li> <li><a href="/article/845.htm" title="Struts2学习" target="_blank">Struts2学习</a> <span class="text-muted">云端月影</span> <div>最近开始关注struts2的新特性,从这个版本开始,Struts开始使用convention-plugin代替codebehind-plugin来实现struts的零配置。 配置文件精简了,的确是简便了开发过程,但是,我们熟悉的配置突然disappear了,真是一下很不适应。跟着潮流走吧,看看该怎样来搞定convention-plugin。 使用Convention插件,你需要将其JAR文件放</div> </li> <li><a href="/article/972.htm" title="Java新手入门的30个基本概念二" target="_blank">Java新手入门的30个基本概念二</a> <span class="text-muted">aijuans</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E6%96%B0%E6%89%8B/1.htm">新手</a><a class="tag" taget="_blank" href="/search/java+%E5%85%A5%E9%97%A8/1.htm">java 入门</a> <div>基本概念:  1.OOP中唯一关系的是对象的接口是什么,就像计算机的销售商她不管电源内部结构是怎样的,他只关系能否给你提供电就行了,也就是只要知道can or not而不是how and why.所有的程序是由一定的属性和行为对象组成的,不同的对象的访问通过函数调用来完成,对象间所有的交流都是通过方法调用,通过对封装对象数据,很大限度上提高复用率。  2.OOP中最重要的思想是类,类是模板是蓝图,</div> </li> <li><a href="/article/1099.htm" title="jedis 简单使用" target="_blank">jedis 简单使用</a> <span class="text-muted">antlove</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/redis/1.htm">redis</a><a class="tag" taget="_blank" href="/search/cache/1.htm">cache</a><a class="tag" taget="_blank" href="/search/command/1.htm">command</a><a class="tag" taget="_blank" href="/search/jedis/1.htm">jedis</a> <div>jedis.RedisOperationCollection.java package jedis; import org.apache.log4j.Logger; import redis.clients.jedis.Jedis; import java.util.List; import java.util.Map; import java.util.Set; pub</div> </li> <li><a href="/article/1226.htm" title="PL/SQL的函数和包体的基础" target="_blank">PL/SQL的函数和包体的基础</a> <span class="text-muted">百合不是茶</span> <a class="tag" taget="_blank" href="/search/PL%2FSQL%E7%BC%96%E7%A8%8B%E5%87%BD%E6%95%B0/1.htm">PL/SQL编程函数</a><a class="tag" taget="_blank" href="/search/%E5%8C%85%E4%BD%93%E6%98%BE%E7%A4%BA%E5%8C%85%E7%9A%84%E5%85%B7%E4%BD%93%E6%95%B0%E6%8D%AE/1.htm">包体显示包的具体数据</a><a class="tag" taget="_blank" href="/search/%E5%8C%85/1.htm">包</a> <div>由于明天举要上课,所以刚刚将代码敲了一遍PL/SQL的函数和包体的实现(单例模式过几天好好的总结下再发出来);以便明天能更好的学习PL/SQL的循环,今天太累了,所以早点睡觉,明天继续PL/SQL总有一天我会将你永远的记载在心里,,,   函数; 函数:PL/SQL中的函数相当于java中的方法;函数有返回值 定义函数的 --输入姓名找到该姓名的年薪 create or re</div> </li> <li><a href="/article/1353.htm" title="Mockito(二)--实例篇" target="_blank">Mockito(二)--实例篇</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/1.htm">持续集成</a><a class="tag" taget="_blank" href="/search/mockito/1.htm">mockito</a><a class="tag" taget="_blank" href="/search/%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/1.htm">单元测试</a> <div>        学习了基本知识后,就可以实战了,Mockito的实际使用还是比较麻烦的。因为在实际使用中,最常遇到的就是需要模拟第三方类库的行为。         比如现在有一个类FTPFileTransfer,实现了向FTP传输文件的功能。这个类中使用了a</div> </li> <li><a href="/article/1480.htm" title="精通Oracle10编程SQL(7)编写控制结构" target="_blank">精通Oracle10编程SQL(7)编写控制结构</a> <span class="text-muted">bijian1013</span> <a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/plsql/1.htm">plsql</a> <div>/* *编写控制结构 */ --条件分支语句 --简单条件判断 DECLARE v_sal NUMBER(6,2); BEGIN select sal into v_sal from emp where lower(ename)=lower('&name'); if v_sal<2000 then update emp set</div> </li> <li><a href="/article/1607.htm" title="【Log4j二】Log4j属性文件配置详解" target="_blank">【Log4j二】Log4j属性文件配置详解</a> <span class="text-muted">bit1129</span> <a class="tag" taget="_blank" href="/search/log4j/1.htm">log4j</a> <div>如下是一个log4j.properties的配置   log4j.rootCategory=INFO, stdout , R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appe</div> </li> <li><a href="/article/1734.htm" title="java集合排序笔记" target="_blank">java集合排序笔记</a> <span class="text-muted">白糖_</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a> <div>public class CollectionDemo implements Serializable,Comparable<CollectionDemo>{ private static final long serialVersionUID = -2958090810811192128L; private int id; private String nam</div> </li> <li><a href="/article/1861.htm" title="java导致linux负载过高的定位方法" target="_blank">java导致linux负载过高的定位方法</a> <span class="text-muted">ronin47</span> <div>定位java进程ID 可以使用top或ps -ef |grep java ![图片描述][1] 根据进程ID找到最消耗资源的java pid 比如第一步找到的进程ID为5431 执行 top -p 5431 -H ![图片描述][2] 打印java栈信息 $ jstack -l 5431 > 5431.log 在栈信息中定位具体问题 将消耗资源的Java PID转</div> </li> <li><a href="/article/1988.htm" title="给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数" target="_blank">给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数</a> <span class="text-muted">bylijinnan</span> <a class="tag" taget="_blank" href="/search/%E5%87%BD%E6%95%B0/1.htm">函数</a> <div> import java.util.ArrayList; import java.util.List; import java.util.Random; public class RandNFromRand5 { /** 题目:给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数。 解法1: f(k) = (x0-1)*5^0+(x1-</div> </li> <li><a href="/article/2115.htm" title="PL/SQL Developer保存布局" target="_blank">PL/SQL Developer保存布局</a> <span class="text-muted">Kai_Ge</span> <div>      近日由于项目需要,数据库从DB2迁移到ORCAL,因此数据库连接客户端选择了PL/SQL Developer。由于软件运用不熟悉,造成了很多麻烦,最主要的就是进入后,左边列表有很多选项,自己删除了一些选项卡,布局很满意了,下次进入后又恢复了以前的布局,很是苦恼。在众多PL/SQL Developer使用技巧中找到如下这段:   &n</div> </li> <li><a href="/article/2242.htm" title="[未来战士计划]超能查派[剧透,慎入]" target="_blank">[未来战士计划]超能查派[剧透,慎入]</a> <span class="text-muted">comsci</span> <a class="tag" taget="_blank" href="/search/%E8%AE%A1%E5%88%92/1.htm">计划</a> <div>       非常好看,超能查派,这部电影......为我们这些热爱人工智能的工程技术人员提供一些参考意见和思想........        虽然电影里面的人物形象不是非常的可爱....但是非常的贴近现实生活....    &nbs</div> </li> <li><a href="/article/2369.htm" title="Google Map API V2" target="_blank">Google Map API V2</a> <span class="text-muted">dai_lm</span> <a class="tag" taget="_blank" href="/search/google+map/1.htm">google map</a> <div>以后如果要开发包含google map的程序就更麻烦咯 http://www.cnblogs.com/mengdd/archive/2013/01/01/2841390.html 找到篇不错的文章,大家可以参考一下 http://blog.sina.com.cn/s/blog_c2839d410101jahv.html 1. 创建Android工程 由于v2的key需要G</div> </li> <li><a href="/article/2496.htm" title="java数据计算层的几种解决方法2" target="_blank">java数据计算层的几种解决方法2</a> <span class="text-muted">datamachine</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/%E9%9B%86%E7%AE%97%E5%99%A8/1.htm">集算器</a> <div>2、SQL     SQL/SP/JDBC在这里属于一类,这是老牌的数据计算层,性能和灵活性是它的优势。但随着新情况的不断出现,单纯用SQL已经难以满足需求,比如: JAVA开发规模的扩大,数据量的剧增,复杂计算问题的涌现。虽然SQL得高分的指标不多,但都是权重最高的。     成熟度:5星。最成熟的。   </div> </li> <li><a href="/article/2623.htm" title="Linux下Telnet的安装与运行" target="_blank">Linux下Telnet的安装与运行</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/telnet/1.htm">telnet</a> <div> Linux下Telnet的安装与运行   linux默认是使用SSH服务的 而不安装telnet服务  如果要使用telnet 就必须先安装相应的软件包  即使安装了软件包 默认的设置telnet 服务也是不运行的 需要手工进行设置 如果是redhat9,则在第三张光盘中找到 telnet-server-0.17-25.i386.rpm </div> </li> <li><a href="/article/2750.htm" title="PHP中钩子函数的实现与认识" target="_blank">PHP中钩子函数的实现与认识</a> <span class="text-muted">dcj3sjt126com</span> <a class="tag" taget="_blank" href="/search/PHP/1.htm">PHP</a> <div>假如有这么一段程序: function fun(){ fun1(); fun2(); }   首先程序执行完fun1()之后执行fun2()然后fun()结束。   但是,假如我们想对函数做一些变化。比如说,fun是一个解析函数,我们希望后期可以提供丰富的解析函数,而究竟用哪个函数解析,我们希望在配置文件中配置。这个时候就可以发挥钩子的力量了。   我们可以在fu</div> </li> <li><a href="/article/2877.htm" title="EOS中的WorkSpace密码修改" target="_blank">EOS中的WorkSpace密码修改</a> <span class="text-muted">蕃薯耀</span> <a class="tag" taget="_blank" href="/search/%E4%BF%AE%E6%94%B9WorkSpace%E5%AF%86%E7%A0%81/1.htm">修改WorkSpace密码</a> <div>EOS中BPS的WorkSpace密码修改 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 蕃薯耀 201</div> </li> <li><a href="/article/3004.htm" title="SpringMVC4零配置--SpringSecurity相关配置【SpringSecurityConfig】" target="_blank">SpringMVC4零配置--SpringSecurity相关配置【SpringSecurityConfig】</a> <span class="text-muted">hanqunfeng</span> <a class="tag" taget="_blank" href="/search/SpringSecurity/1.htm">SpringSecurity</a> <div> SpringSecurity的配置相对来说有些复杂,如果是完整的bean配置,则需要配置大量的bean,所以xml配置时使用了命名空间来简化配置,同样,spring为我们提供了一个抽象类WebSecurityConfigurerAdapter和一个注解@EnableWebMvcSecurity,达到同样减少bean配置的目的,如下:   applicationContex</div> </li> <li><a href="/article/3131.htm" title="ie 9 kendo ui中ajax跨域的问题" target="_blank">ie 9 kendo ui中ajax跨域的问题</a> <span class="text-muted">jackyrong</span> <a class="tag" taget="_blank" href="/search/AJAX%E8%B7%A8%E5%9F%9F/1.htm">AJAX跨域</a> <div>这两天遇到个问题,kendo ui的datagrid,根据json去读取数据,然后前端通过kendo ui的datagrid去渲染,但很奇怪的是,在ie 10,ie 11,chrome,firefox等浏览器中,同样的程序, 浏览起来是没问题的,但把应用放到公网上的一台服务器, 却发现如下情况: 1) ie 9下,不能出现任何数据,但用IE 9浏览器浏览本机的应用,却没任何问题 </div> </li> <li><a href="/article/3258.htm" title="不要让别人笑你不能成为程序员" target="_blank">不要让别人笑你不能成为程序员</a> <span class="text-muted">lampcy</span> <a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a> <div>在经历六个月的编程集训之后,我刚刚完成了我的第一次一对一的编码评估。但是事情并没有如我所想的那般顺利。 说实话,我感觉我的脑细胞像被轰炸过一样。 手慢慢地离开键盘,心里很压抑。不禁默默祈祷:一切都会进展顺利的,对吧?至少有些地方我的回答应该是没有遗漏的,是不是? 难道我选择编程真的是一个巨大的错误吗——我真的永远也成不了程序员吗? 我需要一点点安慰。在自我怀疑,不安全感和脆弱等等像龙卷风一</div> </li> <li><a href="/article/3385.htm" title="马皇后的贤德" target="_blank">马皇后的贤德</a> <span class="text-muted">nannan408</span> <div>   马皇后不怕朱元璋的坏脾气,并敢理直气壮地吹耳边风。众所周知,朱元璋不喜欢女人干政,他认为“后妃虽母仪天下,然不可使干政事”,因为“宠之太过,则骄恣犯分,上下失序”,因此还特地命人纂述《女诫》,以示警诫。但马皇后是个例外。   有一次,马皇后问朱元璋道:“如今天下老百姓安居乐业了吗?”朱元璋不高兴地回答:“这不是你应该问的。”马皇后振振有词地回敬道:“陛下是天下之父,</div> </li> <li><a href="/article/3512.htm" title="选择某个属性值最大的那条记录(不仅仅包含指定属性,而是想要什么属性都可以)" target="_blank">选择某个属性值最大的那条记录(不仅仅包含指定属性,而是想要什么属性都可以)</a> <span class="text-muted">Rainbow702</span> <a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/group+by/1.htm">group by</a><a class="tag" taget="_blank" href="/search/%E6%9C%80%E5%A4%A7%E5%80%BC/1.htm">最大值</a><a class="tag" taget="_blank" href="/search/max/1.htm">max</a><a class="tag" taget="_blank" href="/search/%E6%9C%80%E5%A4%A7%E7%9A%84%E9%82%A3%E6%9D%A1%E8%AE%B0%E5%BD%95/1.htm">最大的那条记录</a> <div>好久好久不写SQL了,技能退化严重啊!!!   直入主题: 比如我有一张表,file_info, 它有两个属性(但实际不只,我这里只是作说明用): file_code, file_version 同一个code可能对应多个version 现在,我想针对每一个code,取得它相关的记录中,version 值 最大的那条记录, SQL如下: select * </div> </li> <li><a href="/article/3639.htm" title="VBScript脚本语言" target="_blank">VBScript脚本语言</a> <span class="text-muted">tntxia</span> <a class="tag" taget="_blank" href="/search/VBScript/1.htm">VBScript</a> <div>  VBScript 是基于VB的脚本语言。主要用于Asp和Excel的编程。   VB家族语言简介   Visual Basic 6.0           源于BASIC语言。           由微软公司开发的包含协助开发环境的事</div> </li> <li><a href="/article/3766.htm" title="java中枚举类型的使用" target="_blank">java中枚举类型的使用</a> <span class="text-muted">xiao1zhao2</span> <a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/enum/1.htm">enum</a><a class="tag" taget="_blank" href="/search/%E6%9E%9A%E4%B8%BE/1.htm">枚举</a><a class="tag" taget="_blank" href="/search/1.5%E6%96%B0%E7%89%B9%E6%80%A7/1.htm">1.5新特性</a> <div>枚举类型是j2se在1.5引入的新的类型,通过关键字enum来定义,常用来存储一些常量.   1.定义一个简单的枚举类型 public enum Sex { MAN, WOMAN }   枚举类型本质是类,编译此段代码会生成.class文件.通过Sex.MAN来访问Sex中的成员,其返回值是Sex类型.   2.常用方法 静态的values()方</div> </li> </ul> </div> </div> </div> <div> <div class="container"> <div class="indexes"> <strong>按字母分类:</strong> <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a> </div> </div> </div> <footer id="footer" class="mb30 mt30"> <div class="container"> <div class="footBglm"> <a target="_blank" href="/">首页</a> - <a target="_blank" href="/custom/about.htm">关于我们</a> - <a target="_blank" href="/search/Java/1.htm">站内搜索</a> - <a target="_blank" href="/sitemap.txt">Sitemap</a> - <a target="_blank" href="/custom/delete.htm">侵权投诉</a> </div> <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved. <!-- <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>--> </div> </div> </footer> <!-- 代码高亮 --> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script> <script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script> <link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/> <script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script> </body> </html><script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>