在教程开端先说些题外话,我喜欢在学习一门新技术或读过一本书后,写一篇教程或总结,既能帮助消化,也能加深印象和发现自己未注意的细节,写的过程其实仍然是一个学习的过程。有个记录的话,在未来需要用到相关知识时,也方便自己查阅。

  React既不是一个MVC框架,也不是一个模板引擎,而是Facebook在2013年推出的一个专注于视图层,用来构建用户界面的JavaScript库。它推崇组件式应用开发,而组件(component)是一段独立的、可重用的、用于完成某个功能的代码,包含了HTML、CSS和JavaScript三部分内容。React为了保持灵活性,只实现了核心功能,提供了少量的API,一些DOM方法都被剥离到了react-dom.js中。这么做虽然轻巧,但有时候要完成特定的业务场景,还是需要与其他库结合,例如Redux、Flux等。React不仅让函数式编程愈加流行,还引入了JSX语法(能把HTML嵌入进JavaScript中)和Virtual DOM技术,大大提升了更新页面时的性能。在React中,每个组件的呈现和行为都由特定的数据所决定,而数据的流动都是单向的,即单向数据流。在编写React时,推荐使用ES6语法,官方的文档也使用了ES6语法,因此,在学习React之前,建议对ES6有所了解,避免不必要的困惑。

  下面是一段较为完整的React代码,本文大部分的示例代码来源于此,阅读下面的代码可以对React有一个感性的认识。

  1. import React, { Component } from 'react';
  2. import ReactDOM from 'react-dom';
  3. import PropTypes from 'prop-types';
  4. class Search extends Component {
  5. //static defaultProps = {
  6. // url: "http://jane.com"
  7. //};
  8. constructor(props) {
  9. super(props);
  10. this.state = {
  11. txt: "请输入关键字"
  12. };
  13. }
  14. componentWillMount() {
  15. console.log("component will mount");
  16. }
  17. componentDidMount() {
  18. console.log("component did mount");
  19. this.refs.txt.addEventListener("blur", (e) => {
  20. this.getValue(e);
  21. });
  22. console.log(this.refs)
  23. }
  24. handle(keyword, e) {
  25. console.log(keyword);
  26. console.log(this);
  27. console.log(this.select.value);
  28. }
  29. getValue(e) {
  30. console.log(e.target.value);
  31. }
  32. refresh(e) {
  33. this.setState({
  34. type: e.target.value
  35. });
  36. }
  37. render() {
  38. console.log("render");
  39. let {type} = this.state;
  40. console.log(type);
  41. return (
  42. <div>
  43. {this.props.children}
  44. <select value={type} onChange={this.refresh.bind(this)}>
  45. <option value="1">标题</option>
  46. <option value="2">内容</option>
  47. </select>
  48. <select defaultValue={2} ref={(select) => this.select = select}>
  49. <option value="1">标题</option>
  50. <option value="2">内容</option>
  51. </select>
  52. <input placeholder={this.state.txt} ref="txt" defaultValue="教程" style={{marginLeft:10, textAlign:"center"}}/>
  53. <button className="btn" data-url={this.props.url} onClick={this.handle.bind(this, "REACT")}>{"<搜索>"}</button>
  54. </div>
  55. );
  56. }
  57. }
  58. Search.defaultProps = {
  59. url: "http://jane.com"
  60. };
  61. ReactDOM.render(
  62. <Search url="http://www.pwstrick.com">
  63. <h1>React扫盲教程</h1>
  64. </Search>,
  65. document.getElementById("container")
  66. );

一、JSX语法

  JSX是对JavaScript语法的一种扩展,它看起来像HTML,同样拥有清晰的DOM树状结构和元素属性,如下代码所示。但与HTML不同的是,为了避免自动插入分号时出现问题,在最外层得用圆括号包裹,并且必须用一个元素包裹(例如下面的<div>元素)其它元素,所有的元素还必须得闭合。

  1. (<div>
  2. <input placeholder={this.state.txt} />
  3. <button className="btn">{"<搜索>"}</button>
  4. </div>)

1)元素

  JSX中的元素分为两种:DOM元素和组件元素(也叫React元素),DOM元素就是HTML文档映射的节点,首字母要小写;而组件元素的首字母要大写。无论是DOM元素还是组件元素,最终都会通过React.createElement()方法转换成JSON对象,如下所示,JSON对象是简化过的。

  1. //React.createElement()方法
  2. React.createElement("div", null, [
  3. React.createElement("input", { placeholder: `${this.state.txt}` }, null),
  4. React.createElement("button", { className: "btn" }, "<搜索>")
  5. ]);
  6. //简化过的JSON对象
  7. {
  8. type: "div",
  9. props: {
  10. children: [
  11. {
  12. type: "input",
  13. props: {
  14. placeholder: `${this.state.txt}`
  15. }
  16. },
  17. {
  18. type: "button",
  19. props: {
  20. className: "btn",
  21. children: "<搜索>"
  22. }
  23. }
  24. ]
  25. }
  26. }

  由于JSX中的元素能够被编译成对象,因此还可以把它们应用到条件、循环等语句中,或者作为一个值应用到变量和参数上。

2)属性

  JSX中的属性要用驼峰的方式表示,例如maxlength要改成maxLength、readonly要改成readOnly。还有两个比较特殊的属性:class和for,由于这两个是JavaScript中的关键字,因此要改名,前者改成className,后者改成htmlFor。

  JSX中的属性值不仅可以是字符串,还可以是表达式。如果是表达式,那么就要用花括号(“{}”)包裹。而在JSX中,任何位置都可以使用表达式。

  有一点要注意,为了防止XSS的攻击,React会把所有要显示到DOM中的字符串进行转义,例如“<搜索>”转义成“&lt;搜索&gt;”。

3)Virtual DOM

  众所周知,DOM操作会引起重绘和重排,而这是非常消耗性能的。React能把元素转换成对象,也就是说可以用对象来表示DOM树,而这个存在于内存中的对象正是Virtual DOM。Virtual DOM相当于一个缓存,当数据更新后,React会重新计算Virtual DOM,再与上一次的Virtual DOM通过diff算法做比对(如下图所示),最后只在页面中更新修改过的DOM。由于大部分的操作都在内存中进行,因此性能将会有很大的提升。

二、组件

  组件的构建方式有3种:React.createClass()、ES6的类和函数。当用ES6的类来构建时,所有的组件都继承自抽象基础类React.Component,该抽象类声明了state、props、defaultProps和displayName等属性,定义了render()、setState()和forceUpdate()等方法。注意,在组件的构造函数constructor()中要调用super()函数,用于初始化this和执行抽象类的构造函数。

  1. import React, { Component } from 'react';
  2. class Search extends Component {
  3. constructor (props) {
  4. super(props);
  5. }
  6. render() {
  7. return ();
  8. }
  9. }

  组件中的render()方法是必须的,它会返回一个元素、数字或字符串等各种值。render()是一个纯函数,即输出(返回值)只依赖输入(参数),并且执行过程中没有副作用(不改变外部状态)。

  组件之间可以相互嵌套,而它们的数据流是自顶向下流动的(如下图所示),即父组件将数据传给子组件。此处传递的数据就是组件的配置参数,由props属性控制,而组件的内部状态保存在state属性中。

1)props

  如果一个组件要做到可复用,那么它应该是可配置的。为此,React提供了props属性,它的使用如下所示。

  1. class Search extends Component {
  2. render() {
  3. return (
  4. <div>
  5. <button className="btn" data-url={this.props.url}>{"<搜索>"}</button>
  6. </div>
  7. );
  8. }
  9. }
  10. <Search url="http://www.pwstrick.com" />

  先给Search组件定义一个名为url的属性,然后在组件内部,可以通过引用props属性来获取url的值。有一点要注意,props是只读属性,因此在组件内部无法修改它。

  React为组件提供了默认的配置,可以调用它的静态属性defaultProps。总共有两种写法实现默认配置,如下代码所示,其中写法一用到了ES6中的static关键字。

  1. //写法一
  2. class Search extends Component {
  3. static defaultProps = {
  4. url: "http://jane.com"
  5. };
  6. }
  7. //写法二
  8. Search.defaultProps = {
  9. url: "http://jane.com"
  10. };
  11. <Search />

  此时,即使组件不定义url属性,在组件内部还是会有值。

  props还有一个特殊的属性:children,它的值是组件内的子元素,如下代码所示,children属性的值为“<h1>React扫盲教程</h1>”。

  1. class Search extends Component {
  2. render() {
  3. return (
  4. <div>
  5. {this.props.children}
  6. </div>
  7. );
  8. }
  9. }
  10. <Search>
  11. <h1>React扫盲教程</h1>
  12. </Search>

2)state

  组件的呈现会随着内部状态和外部配置而改变,通常会在组件的构造函数中初始化需要的内部状态,如下代码所示,为文本框添加默认提示。

  1. class Search extends Component {
  2. constructor (props) {
  3. super(props);
  4. this.state = {
  5. txt: "请输入关键字"
  6. };
  7. }
  8. }

  React还提供了setState()方法,用于更新组件的状态。注意,不要通过直接为state赋值的方式来更新状态,因为setState()方法在更新状态后,还会调用render()方法,重新渲染组件。此外,React为了提升性能,会把多次setState()调用合并成一次,像下面这样写打印出的txt属性的值仍然是前一次的值,因此状态更新是异步的。

  1. this.setState({
  2. txt: "React"
  3. });
  4. console.log(this.state.txt); //"请输入关键字"

3)生命周期

  组件的生命周期(life cycle)可简单的分为4个阶段:初始化(Initialization)、挂载(Mounting)、更新(Updation)和卸载(Unmounting),具体如下图所示。每个阶段都会对应几个方法,其中包含will的方法会在某个方法之前被调用,而包含did的方法会在某个方法之后被调用。

1、在初始化阶段,会设置props、state等属性。

2、在挂载阶段,两个挂载方法将以组件的render()为分界点。

3、更新阶段发生在传递props或执行setState()的时候。

4、当一个组件被移除时,就会调用componentWillUnmount()方法。

当组件在页面中输出时,在控制台将依次输出“will mount”、“render”和“did mount”。

  1. class Search extends Component {
  2. componentWillMount() {
  3. console.log("will mount");
  4. }
  5. componentDidMount() {
  6. console.log("did mount");
  7. }
  8. render() {
  9. console.log("render");
  10. }
  11. }

三、React和DOM

1)ReactDOM

  如果要把组件添加到真实的DOM中,那么就需要使用ReactDOM中的render()方法,如下代码所示,其实在前面已经调用过几次这个方法了。

  1. ReactDOM.render(
  2. <Search />,
  3. document.getElementById("container")
  4. );

  此方法可接收三个参数,第一个是要渲染(即添加)的元素,第二个是容器元素(即添加的位置),第三个是可选的回调函数,会在渲染或更新之后执行。

  ReactDOM还提供了另外两个方法:unmountComponentAtNode()findDOMNode(),具体可参考官方文档。

2)事件

  React实现了一种合成事件(SyntheticEvent),合成事件只有冒泡传播,并且它的注册方式、事件对象和事件处理程序中的this对象都与原生事件不同。

1、合成事件会通过设置元素的属性来注册事件,但与原生事件不同的是,属性的命名要用驼峰的写法而不是全部小写,并且属性值可以是任意类型而不再仅是字符串,如下代码所示。React已经封装好了一系列的事件类型(原生事件类型的一个子集),并且已经处理好它们的兼容性,提供的事件类型可以参考官网

  1. class Search extends Component {
  2. handle(e) {
  3. console.log("click");
  4. }
  5. render() {
  6. return (
  7. <div>
  8. <button onClick={this.handle}>搜索</button>
  9. </div>
  10. );
  11. }
  12. }

2、合成事件中的事件对象(event object)是一个基于W3C标准的SyntheticEvent对象的实例,它不但与原生的事件对象拥有相同的属性和方法(例如cancelable、preventDefault()、stopPropagation()等),还完美解决了兼容性问题。

3、React的事件处理程序中的this对象默认是undefined,因为注册的事件都是以普通函数的方式调用的。如果要让this指向当前组件,那么可以用bind()方法或ES6的箭头函数。

  1. class Search extends Component {
  2. //bind()方法
  3. handle1(e) {
  4. console.log(this);
  5. }
  6. //箭头函数
  7. handle2 = (e) => {
  8. console.log(this);
  9. };
  10. render() {
  11. return (
  12. <div>
  13. <button onClick={this.handle1.bind(this)}>搜索</button>
  14. <button onClick={this.handle2}>搜索</button>
  15. </div>
  16. );
  17. }
  18. }

4、在向事件处理程序传递参数时,要把事件对象放在最后,如下代码所示。

  1. class Search extends Component {
  2. handle(keyword, e) {
  3. console.log(keyword);
  4. console.log(this);
  5. }
  6. render() {
  7. return (
  8. <div>
  9. <button onClick={this.handle1.bind(this, "REACT")}>搜索</button>
  10. </div>
  11. );
  12. }
  13. }

5、如果要为组件中某个元素注册原生事件,那么可以利用元素的ref属性和组件的refs对象实现。例如实现一个文本框在失去焦点时,打印输出它的值,如下代码所示。注意,原生事件的注册要在componentDidMount()方法内执行。

  1. class Search extends Component {
  2. componentDidMount() {
  3. this.refs.txt.addEventListener("blur", (e) => {
  4. this.getValue(e);
  5. });
  6. }
  7. getValue(e) {
  8. console.log(e.target.value);
  9. }
  10. render() {
  11. return (
  12. <div>
  13. <input placeholder={this.state.txt} ref="txt" />
  14. </div>
  15. );
  16. }
  17. }

  在上面的代码中,ref属性的值被设为了“txt”,此时,在refs对象中就会出现一个名为“txt”的属性,关于这个它们的具体用法可以参考官网

3)表单

  HTML中的表单元素(例如<input>、<select>和<radio>等)在React都有相应的组件实现,React还把表单中的组件分为受控和非受控。

  受控组件(controlled component)的状态由React组件控制,它的每个状态的改变都会有一个与之对应的事件处理程序,并且在程序内部会调用setState()方法更新状态。React推荐使用受控组件,下面是一个受控组件,注意,选择框(<select>元素)中的value属性表示选中项。

  1. class Search extends Component {
  2. refresh(e) {
  3. this.setState({
  4. type: e.target.value
  5. });
  6. }
  7. render() {
  8. let {type} = this.state;
  9. return (
  10. <div>
  11. <select value={type} onChange={this.refresh.bind(this)}>
  12. <option value="1">标题</option>
  13. <option value="2">内容</option>
  14. </select>
  15. </div>
  16. );
  17. }
  18. }

  非受控组件(uncontrolled component)的状态不受React组件控制,也不用为每个状态编写对应的事件处理程序,但可以通过元素的ref属性获取它的值,非受控组件的写法更像是传统的DOM操作。在使用非受控组件时,如果要为其设置默认值,可以使用属性defaultValue或defaultChecked,具体如下所示。

  1. class Search extends Component {
  2. handle(e) {
  3. console.log(this.select.value);
  4. }
  5. render() {
  6. return (
  7. <div>
  8. <select defaultValue={2} ref={(select) => this.select = select}>
  9. <option value="1">标题</option>
  10. <option value="2">内容</option>
  11. </select>
  12. <button onClick={this.handle.bind(this)}>搜索</button>
  13. </div>
  14. );
  15. }
  16. }

4)样式

  在React问世的初期,由于它推崇组件模式,因此会要求HTML、CSS和JavaScript混合在一起,这与过去的关注点分离正好相反。React已将HTML用JSX封装,而对CSS的封装,则抛出了CSS in JS的解决方案,即用JavaScript写CSS。

  在React中的元素都包含className和style属性,前者可设置CSS类,后者可定义内联样式。style的属性值是一个对象,其属性就是CSS属性,但属性名要用驼峰的方式命名,例如margin-left改成marginLeft,具体如下所示。

  1. class Search extends Component {
  2. render() {
  3. return (
  4. <div>
  5. <input style={{marginLeft:10, textAlign:"center"}}/>
  6. </div>
  7. );
  8. }
  9. }

  注意,属性名不会自动补全浏览器前缀,并且React会自动给需要单位的数字加上px。在MDN上给出了CSS属性用JavaScript命名的对应关系,可在此处参考

  由于React处理CSS的功能并不强大,因此市面上出现了很多与CSS in JS相关第三方类库,例如classnamespolished.js等,有外国网友还专门搜集了40多种相关的类库。

  虽然这种方式能让组件更方便的模块化,但同时也彻底抛弃了CSS,既不能使用CSS的特性(例如选择器、媒体查询等),也无法再用CSS预处理器(例如SASS、LESS等)。为了解决上述问题,又有人提出了CSS Modules

  如果要在React中制作动画,官方推荐使用React Transition GroupReact Motion。不过,你也可以使用普通的动画库(例如animejs),只要在DOM渲染好以后调用即可。

四、React进阶

1)跨级通信

  React数据流动是单向的,组件之间通信最常见的方式是父组件通过props向子组件传递信息,但这种方式只能逐级传递,如果要跨级通信(即父组件与孙子组件通信),那么可以利用状态提升实现,但这样的话,代码会显得很不优雅并且很臃肿。好在React包含一个Context特性,可以满足刚刚的需求,不过官方不建议大量使用该特性,因为它不但会增加组件之间的耦合性,还会让应用变得混乱不堪,下图演示了两种数据传递的过程。在理解Context特性后,能更合理的使用状态管理容器Redux。

  当一个组件设置了Context后,它的子组件就能直接访问Context中的内容,Context相当于一个全局变量,但作用域仅限于它的子组件中。总共有两种Context的实现方式,都基于生产者消费者模式。首先来看第一种,具体代码如下所示。

  1. import PropTypes from 'prop-types';
  2. class Grandpa extends Component {
  3. getChildContext() {
  4. return { name: "strick" };
  5. }
  6. render() {
  7. return (<Son />);
  8. }
  9. }
  10. Grandpa.childContextTypes = {
  11. name: PropTypes.string
  12. };
  13. class Son extends Component {
  14. render() {
  15. return (<Grandson />);
  16. }
  17. }
  18. class Grandson extends Component {
  19. render() {
  20. let { name } = this.context;
  21. return (<div>爷爷叫{name}</div>);
  22. }
  23. }
  24. Grandson.contextTypes = {
  25. name: PropTypes.string
  26. };

  在上面的代码中,创建了三个组件,Grandpa是最上层的父组件(生产者),Son是中间的子组件,Grandson是最下层的孙子组件(消费者)。首先在Grandpa中,声明了一个静态属性childContextTypes和一个getChildContext()方法,这两个是必须的,否则无法实现数据传递。其中childContextTypes是一个对象,它的属性名就是要传递的变量名,而属性值则通过PropTypes指明了该变量的数据类型,getChildContext()方法返回的对象就是要传递的一组变量和它们的值。然后在Son中渲染Grandson组件。最后为Grandson声明一个静态属性contextTypes,同样是个对象,并且属性名和属性值与childContextTypes中的相同。

  第二种方式是在React 16.3的版本中引入的,比起第一种方式,写法更加简洁,并且Context的生产者和消费者都以组件的方式实现,如下所示。

  1. let NameContext = React.createContext({ name });
  2. class Grandpa extends Component {
  3. render() {
  4. return (
  5. <NameContext.Provider value={{name: "strick"}}>
  6. <Son />
  7. </NameContext.Provider>
  8. );
  9. }
  10. }
  11. class Son extends Component {
  12. render() {
  13. return (<Grandson />);
  14. }
  15. }
  16. class Grandson extends Component {
  17. render() {
  18. return (
  19. <NameContext.Consumer>
  20. {(context) => (
  21. <div>爷爷叫{context.name}</div>
  22. )}
  23. </NameContext.Consumer>
  24. );
  25. }
  26. }

  上面的代码依然创建了三个组件,名字也和第一种方式中的相同。除了中间组件Son之外,另外两个组件的内容发生了变化。首先,通过React.createContext()方法创建一个Context对象,此对象包含两个组件:Provider和Consumer,前者是生产者,后者是消费者。然后在Grandpa的render()方法中设置Provider组件的value属性,此属性相当于getChildContext()方法。最后在Grandson组件中调用Context对象,注意,Consumer组件的子节点只能是一个函数。

2)高阶组件

  高阶组件(higher-order component,简称HOC)不是一个真的组件,而是一个函数,它的参数中包含组件,其返回值是一个功能增强的新组件。高阶组件是一个没有副作用的纯函数,它遵循了装饰者模式的设计思想,不会修改传递进来的原组件,而是对其进行包装和拓展,不仅增强了组件的复用性和灵活性,还保持了组件的易用性。下面演示了高阶组件是如何控制props和state的。

  1. class Button extends Component {
  2. render() {
  3. return (
  4. <div>
  5. <button>{ this.props.txt }</button>
  6. </div>
  7. );
  8. }
  9. }
  10. //高阶组件
  11. function HOC(Mine) {
  12. class Wrapped extends Component {
  13. constructor() {
  14. super();
  15. this.state = {
  16. txt: "提交"
  17. };
  18. }
  19. render() {
  20. return <Mine {...this.state} />;
  21. }
  22. }
  23. return Wrapped;
  24. }
  25. let Wrapped = HOC(Button);

  高阶组件HOC()的函数体中创建了一个名为Wrapped的组件,在它的构造函数中初始化了state状态。然后在其render()方法中使用了{...this.state},这是JSX的一种语法,在state对象前添加扩展运算符,可把它解构成组件的一组属性。最后在Button组件中调用传递进来的属性。

  高阶组件还有迁移重复代码、劫持render()方法和引用refs等功能。

五、后记

  就先整理这些了,如有错误,欢迎指正,后面还会陆续加入漏掉的知识点。

  最后,我想说下,其实自己也是一个React初学者,通过这样的梳理后,对React有了更为深刻的理解,在后续的学习中能容易的吸收新的知识点。

源码下载:

https://github.com/pwstrick/react-demo

参考资料:

React中文文档

深入React技术栈

React.js 小书

React WIKI

深入浅出React和Redux

React入门实例教程 阮一峰

React入门教程

全栈React: 第1天 什么是 React?

深度剖析:如何实现一个 Virtual DOM 算法

從零開始學 ReactJS

react component lifecycle

CSS Modules 入门及 React 中实践

CSS in JS 简介

聊一聊我对 React Context 的理解以及应用

120分钟React快速扫盲教程的更多相关文章

  1. [30分钟]MSSQL快速入门教程

    1.什么是SQL语句 sql语言:结构化的查询语言.(Structured Query Language),是关系数据库管理系统的标准语言. 它是一种解释语言:写一句执行一句,不需要整体编译执行.语法 ...

  2. React快速入门教程

    简介 Facebook官网介绍:React 是一个用来构建用户界面的 JavaScript 库.相当于 MVC 架构的 V 层. React 的核心思想是:封装组件,各个组件维护自己的状态和UI,当状 ...

  3. let import export React入门实例教程 connect provider combineReducers 箭头函数 30分钟掌握ES6/ES2015核心内容 Rest babel

    let与var的区别 http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html es6 导入导出 http://www.csdn.ne ...

  4. 专为设计师而写的GitHub快速入门教程

    专为设计师而写的GitHub快速入门教程 来源: 伯乐在线 作者:Kevin Li     原文出处: Kevin Li 在互联网行业工作的想必都多多少少听说过GitHub的大名,除了是最大的开源项目 ...

  5. 基于Nodejs生态圈的TypeScript+React开发入门教程

    基于Nodejs生态圈的TypeScript+React开发入门教程   概述 本教程旨在为基于Nodejs npm生态圈的前端程序开发提供入门讲解. Nodejs是什么 Nodejs是一个高性能Ja ...

  6. .NET Core快速入门教程 2、我的第一个.NET Core App(Windows篇)

    一.前言 本篇开发环境?1.操作系统: Windows 10 X642.SDK: .NET Core 2.0 Preview 二.安装 .NET Core SDK 1.下载 .NET Core下载地址 ...

  7. .NET Core快速入门教程 3、我的第一个.NET Core App (CentOS篇)

    一.前言 本篇开发环境?1.操作系统:CentOS7(因为ken比较偏爱CentOS7)2.SDK版本:.NET Core 2.0 Preview 你可能需要的前置知识1.了解如何通过Hyper-V安 ...

  8. React:快速上手(5)——掌握Redux(2)

    React:快速上手(5)——掌握Redux(2) 本文部分内容参考阮一峰的Redux教程. React-Redux原理 React-Redux运行机制 我觉得这张图清楚地描述React-Redux的 ...

  9. React:快速上手(3)——列表渲染

    React:快速上手(3)——列表渲染 使用map循环数组 了解一些ES6 ES6, 全称 ECMAScript 6.0 ,是 JaveScript 的下一个版本标准,2015.06 发版.ES6 主 ...

随机推荐

  1. javaweb开发.页面中文乱码问题

    1.设置eclips , window->Preferences->web->JSP Files中的Encoding选项为UTF-8 2.修改jsp文件头部为UTF-8 <%@ ...

  2. linux学习第七天 (Linux就该这么学)

    今天讲了chmod (权限 设置)和 chown(属性 设置),特殊权限:SUID u+s 数字法是4  x=s  - = S,SGID g+s 数字法是2 x=s -=S,SBIT o+t  x=t ...

  3. canvasJS

  4. Chapter3_操作符_算术操作符

    java中的算术操作符与其它语言并无太大区别,常用到的是以下这些: (1)加号(+),减号(-),除号(\),乘号(*),取模操作符(%),其中除号需要特别注意的是,会自动截取掉小数点后面的部分,而不 ...

  5. Pycharm配置

    平台:win10 x64 Pycharm的下载,安装,破解,编辑字体+配置IDE 详见博客:https://blog.csdn.net/yctjin/article/details/70307933? ...

  6. sock5客户端解密数据流

    一.安装 略 二.配置 vi /etc/shadowsocks.json { "server":"x.x.x.x", , , "password&qu ...

  7. 项目部署到服务器上之后request.getRemoteAddr()为什么获取的都是本地地址

    获取客户端的IP地址的方法是:request.getRemoteAddr(),这种方法在大部分情况下都是有效的.但是在通过了Apache,Squid等反向代理软件就不能获取到客户端的真实IP地址了.如 ...

  8. python函数(一)

    python函数(一) 1.函数的定义: def test(): print('test is running...') return 定义一个函数,有3个部分需要注意: 函数名称.函数的命名规范与变 ...

  9. EBS CAS SSO测试

    https://wiki.jasig.org/display/CAS/CASifying+Oracle+Portal https://wenku.baidu.com/view/5f110a85b9d5 ...

  10. 设置UniDbGrid的整行显示颜色,如果某字段值是我们的控制字段

    设置UniDbGrid的整行显示颜色,如果某字段值是我们的控制字段,使用下列判断设置更快捷一点: procedure TUniForm.UniDBGridDrawColumnCell(Sender: ...