• React随笔1


    1、jsx = js+xml  是js的拓展语法

     从本质上讲,JSX 只是为 React.createElement(component, props, ...children) 函数提供的语法糖

     优点:1)执行的效率更快

        2)他是类型安全的,编译的过程中就行及时的发现错误

        3)在使用jsx的时候编写模板或更加简单和快速

       注意:jsx中HTML标签必须按照W3C的规范写  标签必须闭合

    //不能使用一个普通的表达式作为 React 元素类型。如果你想使用普通表达式来表示元素类型,首先你需要将其赋值给大写的变量。这通常会出现在根据不同的 props 渲染不同的组件时:
    //为了解决这个问题,首先需要将表达式赋值给一个以大写字母开头的变量。
    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // 错误!JSX 类型不能是表达式!!!!!
      return <components[props.storyType] story={props.story} />;
      // 正确!JSX 类型可以是一个以大写字母开头的变量.
      const SpecificStory = components[props.storyType];
      return <SpecificStory story={props.story} />;
    //在 JavaScript 中,if 语句和 for 循环不是表达式,因此不能在 JSX 中直接使用。但你可以将他们放在附近的代码块中,例如:
    function NumberDescriber(props) {
      let description;
      if (props.number % 2 == 0) {
        description = <strong>even</strong>;
      } else {
        description = <i>odd</i>;
      }
      return <div>{props.number} is an {description} number</div>;
    }

      属性展开

    //如果你已经有一个 object 类型的 props,并且希望在 JSX 中传入,你可以使用扩展操作符 ... 传入整个 props 对象。这两个组件是等效的:
    function App1() {
      return <Greeting firstName="Ben" lastName="Hector" />;
    }
    
    function App2() {
      const props = {firstName: 'Ben', lastName: 'Hector'};
      return <Greeting {...props} />;
    }
    //你也可以挑选你的组件将使用的指定属性(props),同时使用展开运算符传递所有其他属性(props)。
    const Button = props => {
      const { kind, ...other } = props;
      const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
      return <button className={className} {...other} />;
    };
    
    const App = () => {
      return (
        <div>
          <Button kind="primary" onClick={() => console.log("clicked!")}>
            Hello World!
          </Button>
        </div>
      );
    };
    //在上面的例子中,kind 属性(props)被安全地使用,并且 不被 传递给 DOM 中的 <button> 元素。 所有其他属性(props)都通过 ... other 对象传递,使得这个组件非常灵活。 你可以看到它传递了onClick 和 children 属性(props)。
    //展开(Spread) 属性可能很有用,但它们还可以轻松地将不必要的属性(props)传递给不关心它们的组件,或将无效的HTML属性传递给DOM。我们建议谨慎使用此语法!!!!!!!!

      React组件也可以返回一个元素数组

    render() {
      // No need to wrap list items in an extra element!
      return [
        // Don't forget the keys :)
        <li key="A">First item</li>,
        <li key="B">Second item</li>,
        <li key="C">Third item</li>,
      ];
    }

      Functions(函数) 作为 Children(子元素)

    //通常情况下,嵌入到 JSX 中的 JavaScript 表达式会被认为是一个字符串、React元素 或者是这些内容的一个列表。然而, props.children 类似于其他的 props(属性) ,可以被传入任何数据,而不是仅仅只是 React 可以渲染的数据。例如,如果有自定义组件,其 props.children 的值可以是回调函数
    function Repeat(props){
      let items = [];
      for(let i = 0;i<props.numTimes;i++){
        items.push(props.children(i))
      }  
      return <div>{items}</div>
    }    
    funxtion ListOfTenThings(){
      return (
        <Repeat numTimes={10}>
            {(index) => <div>this is item {index} in the list</div>}
        </Repeat>
      )
    }        

      Booleans, Null, 和 Undefined 被忽略

    //false,null,undefined,和 true 都是有效的的 children(子元素) 。但是并不会被渲染,下面的JSX表达式渲染效果是相同的
    <div />
    <div></div>
    <div>{false}</div>
    <div>{null}</div>
    <div>{undefined}</div>
    <div>{true}</div>
    
    //在有条件性渲染 React 元素时非常有用。如果 showHeader 为 true 时,<Header />会被渲染:
    <div>
      {showHeader && <Header />}
      <Content />
    </div>
    
    //需要注意的是“falsy”值,例如数值 0 ,仍然会被 React 渲染。例如,这段代码不会按照你预期的发生,因为当 props.messages 是一个空数组时 0 会被打印
    <div>
      {props.messages.length &&
        <MessageList messages={props.messages} />
      }
    </div>
    //要修复这个问题,确保 && 之前的表达式总是布尔值:
    <div>
      {props.messages.length > 0 &&
        <MessageList messages={props.messages} />
      }
    </div>
    
    //反过来,如果在输出中想要渲染 false ,true,null 或者 undefined ,你必须先将其转化为字符串:
    <div>
      My JavaScript variable is {String(myVariable)}.
    </div>

    2、react 开发环境的搭建

      1)react.js  核心文件  (npm i react --save)

      2)react-dom.js 渲染页面中的DOM 当前文件依赖于react核心文件  (npm i react-dom --save)

      3)babel.js  ES6转换成ES5   jsx语法转换成js  现今浏览器进行代码的兼容   (npm i babel-standalone --save)

    3、注释/多行标签需要有一个父元素包裹

      let MyDOm = (<div>
        {/*此处是注释*/} 
        <div>上面是注释</div>
      </div>)
    
      ReactDOM.render(MyDom,document.getElementId("root"))

    4、hook

      export default () => {
    
      const [count,setCount] = useState(0)
    
      //const [count,setCount] = useState(() = > {return 0})    同上
    
      return (<div>
    
        {count}
    
        <button onClick={() = > setConut(x => x+1)}> +1 </button> 
    
      </div>)
    
      }

    5、可以用 花括号 把任意的 JavaScript 表达式 嵌入到 JSX 中。例如,2 + 2

    6、如果是空标签,您应该像 XML 一样,使用 />立即闭合它 :

    const element = <img src={user.avatarUrl} />;

    7、Babel 将JSX编译成 React.createElement() 调用

    //下面的两个例子是是完全相同的:
    const element = (
      <h1 className="greeting">
        Hello, world!
      </h1>
    );
    
    const element = React.createElement(
      'h1',
      {className: 'greeting'},
      'Hello, world!'
    );
    
    //React.createElement() 会执行一些检查来帮助你编写没有bug的代码,但基本上它会创建一个如下所示的对象:
    // 注意: 这是简化的结构
    const element = {
      type: 'h1',
      props: {
        className: 'greeting',
        children: 'Hello, world'
      }
    };

    8、函数式组件和累组件

    //函数式组件
    function Welcome (props){
      return <h1>Hello,{props.name}</h1>  
    }
    //类组件
    class Welcome extends React.Component {
      render(){
        return <h1>Hello,{this.props.name}</h1>
      }  
    }

    9、纯函数和非纯函数 :React 组件都必须是纯函数,并禁止修改其自身 props 

    //纯函数
    function sum(a, b) {
      return a + b;
    }
    //非纯函数:它改变了自身的输入值
    function withdraw(account, amount) {
      account.total -= amount;
    }

    10、state(状态)更新可能是异步的

      React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。

         因为 this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)。

    //例如, 以下代码可能导致 counter(计数器)更新失败:
    //错误
    this.setState({
    counter:this.state.counter + this.props.increment,
    })
    //要解决这个问题,应该使用第 2 种 setState() 的格式,它接收一个函数,而不是一个对象。该函数接收前一个状态值作为第 1 个参数, 并将更新后的值作为第 2 个参数:
    //正确
    this.setState((state,props)=>({
    counter:state.counter + props.increment
    }))

     11、定时器在componentMount中设置,需要在componentWillUNmount中销毁

     componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }

    12、正确使用state

      1)不要直接修改state

    // 错误
    this.state.comment = 'Hello';
    // 正确
    this.setState({comment: 'Hello'});

      2)state跟新可能是异步的

      React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。

      因为 this.props 和 this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)。

      例如, 以下代码可能导致 counter(计数器)更新失败:

    // 错误
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    //要解决这个问题,应该使用第 2 种 setState() 的格式,它接收一个函数,而不是一个对象。该函数接收前一个状态值作为第 1 个参数, 并将更新后的值作为第 2 个参数:
    // 正确
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }));
    //我们在上面使用了一个箭头函数,但是也可以使用一个常规的函数:
    // 正确
    this.setState(function(state, props) {
      return {
        counter: state.counter + props.increment
      };
    });

      3)state跟新会被合并

      当你调用 setState(), React 将合并你提供的对象到当前的状态中。

      合并是浅合并,所以 this.setState({comments}) 不会改变 this.state.posts 的值,但会完全替换this.state.comments 的值。

    13、处理事件

      1)react 事件使用驼峰命名,而不是全部小写。

      2)通过 JSX , 你传递一个函数作为事件处理程序,而不是一个字符串。

    //例如,HTML:
    <button onclick="activateLasers()">
      Activate Lasers
    </button>
    //在 React 中略有不同:
    <button onClick={activateLasers}>
      Activate Lasers
    </butto//实事件处理:react绑定事件用小驼峰,在绑定函数的时候不能加(),不然会立即执行
    //1、修改this的指向
    //2、bind方法原地绑定
    //3、函数通过箭头函数进行创建
    //4、constructor中提前绑定
    //5、把事件调用写成箭头函数的形式
    
    class Com extends React.COmponent{
        constructor(props){
             super(props)
             this.funcC = this.funcC.bind(this)
        }
    
        funcA(){
            console.log(this)           
        }
        funcB = ()=>{
            console.log(this)           
        }
        funcC(){
            console.log(this)           
        }
        funcD(){
            console.log(this)           
        }
        funcE = (this,i) =>{
            console.log(i)  
            console.log(this)           
        }
        funcF = (i,e) =>{
            console.log(i)  
            console.log(e)           
        }
    
         render(){
             return(
             <div>
              //我是组件
               <button onClick = {this.funcA.bind(this)}>bind方式绑定</button>
               <button onClick = {this.funcB}>bind方式绑定</button>
               <button onClick = {this.funcC}>bind方式绑定</button>
               <button onClick = {() => {this.funcD()}}>bind方式绑定</button>
               <button onClick = {this.funcE.bind(this,'我是参数1','我是参数2')}>参数1</button>
               <button onClick = {this.funcF('我是参数1','我是参数2',e)}>参数2</button>
             </div>
             )
        }
    }

      3)另一个区别是,在 React 中你不能通过返回 false(愚人码头注:即 return false; 语句) 来阻止默认行为。必须明确调用 preventDefault 。

    //例如,对于纯 HTML ,要阻止链接打开一个新页面的默认行为,可以这样写:
    <a href="#" onclick="console.log('The link was clicked.'); return false">
      Click me
    </a>
    //在 React 中, 应该这么写:
    function ActionLink() {
      function handleClick(e) { //这里, e 是一个合成的事件。
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }

      4)this指向问题

    //在JSX回调中你必须注意 this 的指向。 在 JavaScript 中,类方法默认没有 绑定 的。如果你忘记绑定 this.handleClick 并将其传递给onClick,那么在直接调用该函数时,this 会是 undefined 。
    //这不是 React 特有的行为;这是 JavaScript 中的函数如何工作的一部分。 一般情况下,如果你引用一个后面没跟 () 的方法,例如 onClick={this.handleClick} ,那你就应该 绑定(bind) 该方法。
    
    //方法1:bind方法
    class Toggle extends React.Component {
      constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
    
        // 这个绑定是必要的,使`this`在回调中起作用
        this.handleClick = this.handleClick.bind(this);
      }
    
      handleClick() {
        this.setState(state => ({
          isToggleOn: !state.isToggleOn
        }));
      }
    
      render() {
        return (
          <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    
    //方法2:实验性的 属性初始化语法 ,使用属性初始值设置来正确地 绑定(bind) 回调:
    class LoggingButton extends React.Component {
      // 这个语法确保 `this` 绑定在 handleClick 中。
      // 警告:这是 *实验性的* 语法。
      handleClick = () => {
        console.log('this is:', this);
      }
    
      render() {
        return (
          <button onClick={this.handleClick}>
            Click me
          </button>
        );
      }
    }
    
    //方法3:回调中使用一个 箭头函数:
    //这个语法的问题是,每次 LoggingButton 渲染时都创建一个不同的回调。在多数情况下,没什么问题。然而,如果这个回调被作为 prop(属性) 传递给下级组件,这些组件可能需要额外的重复渲染。我们通常建议在构造函数中进行绑定,以避免这类性能问题。
    class LoggingButton extends React.Component {
      handleClick() {
        console.log('this is:', this);
      }
    
      render() {
        // This syntax ensures `this` is bound within handleClick
        return (
          <button onClick={(e) => this.handleClick(e)}>
            Click me
          </button>
        );
      }
    }

      4)将参数传递给事件处理程序

    //在循环内部,通常需要将一个额外的参数传递给事件处理程序。 例如,如果 id 是一个内联 ID,则以下任一方式都可以正常工作:
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
    
    //上面两个例子中,参数 e 作为 React 事件对象将会被作为第二个参数进行传递。通过箭头函数的方式,事件对象必须显式的进行传递,但是通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

    14、条件渲染

      1)声明一个变量并使用一个 if 语句是一个有条件地渲染组件

    render() {
        const isLoggedIn = this.state.isLoggedIn;
        let button;
    
        if (isLoggedIn) {   //if语法
          button = <LogoutButton onClick={this.handleLogoutClick} />;
        } else {
          button = <LoginButton onClick={this.handleLoginClick} />;
        }
    
        return (
          <div>
            <Greeting isLoggedIn={isLoggedIn} />
            {button}
          </div>
        );
      }

      2)使用逻辑&&操作符的内联if用法

    //您可以 在JSX中嵌入任何表达式 ,方法是将其包裹在花括号中。这也包括 JavaScript 逻辑 && 运算符。 它有助于有条件地包含一个元素:
    function Mailbox(props) {
      const unreadMessages = props.unreadMessages;
      return (
        <div>
          <h1>Hello!</h1>
          {unreadMessages.length > 0 &&
            <h2>
              You have {unreadMessages.length} unread messages.
            </h2>
          }
        </div>
      );
    }
    
    const messages = ['React', 'Re: React', 'Re:Re: React'];
    ReactDOM.render(
      <Mailbox unreadMessages={messages} />,
      document.getElementById('root')
    );

      3)另一个用于条件渲染元素的内联方法是使用 JavaScript 的条件操作符 condition ? true : false 。

      4)防止组件渲染

      在极少数情况下,您可能希望组件隐藏自身,即使它是由另一个组件渲染的。为此,返回 null 而不是其渲染输出。

    //从组件的 render 方法返回 null 不会影响组件生命周期方法的触发。 例如, componentWillUpdate 和 componentDidUpdate 仍将被调用。
    function WarningBanner(props) {
      if (!props.warn) {
        return null;
      }
    
      return (
        <div className="warning">
          Warning!
        </div>
      );
    }

     15、列表(list)和键(keys)

    //在数组中使用的 keys 必须在它们的同辈之间唯一。然而它们并不需要全局唯一。我们可以在操作两个不同数组的时候使用相同的 keys 
    //键是React的一个内部映射,但其不会传递给组件的内部。如果你需要在组件中使用相同的值,可以明确使用一个不同名字的 prop 传入。
    //Post 组件可以读取 props.id,但是不能读取 props.key 。
    function Post(props) {
      const posts = props.posts;
      return (
        <ul>
          {numbers.map((post) =>
            <ListItem key={post.id}
                      id={post.id}  
                      title={post.title} />
          )}
        </ul>
      );
    }

    16、表单

      1)受控组件

      概念:在 HTML 中,表单元素如 <input><textarea> 和 <select> 表单元素通常保持自己的状态,并根据用户输入进行更新。而在 React 中,可变状态一般保存在组件的 state(状态) 属性中,并且只能通过 setState() 更新。

            我们可以通过使 React 的 state 成为 “单一数据源原则” 来结合这两个形式。然后渲染表单的 React 组件也可以控制在用户输入之后的行为。这种形式,其值由 React 控制的输入表单元素称为“受控组件”。

      受控组件的替代方案:

      有时使用受控组件有些乏味,因为你需要为每一个可更改的数据提供事件处理器,并通过 React 组件管理所有输入状态。当你将已经存在的代码转换为 React 时,或将 React 应用程序与非 React 库集成时,这可能变得特别烦人。在这些情况下,您可能需要使用不受控的组件,用于实现输入表单的替代技术

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ''};
    
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});  //this.setState({value: event.target.value.toUpperCase()});
      }
    
      handleSubmit(event) {
        alert('A name was submitted: ' + this.state.value);
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Name:
              <input type="text" value={this.state.value} onChange={this.handleChange} />
            </label>
            <input type="submit" value="Submit" />
          </form>
        );
      }
    }

      2)textarea

      <textarea> 的赋值使用 value 属性替代。这样一来,表单中 <textarea> 的书写方式接近于单行文本输入框 

      3)select标签

    //React 中,并不使用这个 selected 属性,而是在根 select 标签中使用了一个 value 属性。这使得受控组件使用更方便,因为你只需要更新一处即可。例如:
    class FlavorForm extends React.Component {
      constructor(props) {
        super(props)
        this.state = { value: 'coconut' }
    
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
      handleChange(event) {
        this.setState({ value: event.target.value })
      }
      handleSubmit(event) {
        alert('Your favorite flavor is :' + this.state.value)
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Pick your favorite flavor:
          <select value={this.state.value} onChange={this.handleChange}>   //<select multiple={true} value={['B', 'C']}>   您可以将一个数组传递给 value 属性,允许你在 select 标签中选择多个选项
                <option value="grapefruit">Grapefruit</option>
                <option value="lime">lime</option>
                <option value="coconut">coconut</option>
           <option value="mango">mango</option>
              </select>
            </label>
            <input type="submit" value="Submit" />
          </form>
        )
      }
    }

      4)file input 标签 (不受控 组件)

      在HTML中, <input type="file"> 可以让用户从设备存储器中选择一个或多个文件上传到服务器,或者通过 JavaScript 使用 File API 操作。

    <input type="file" />

      5)处理多个输入元素

      当您需要处理多个受控的 input 元素时,您可以为每个元素添加一个 name 属性,并且让处理函数根据 event.target.name 的值来选择要做什么。

    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          numberOfGuests: 2
        };
    
        this.handleInputChange = this.handleInputChange.bind(this);
      }
    
      handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
        //ES6 计算的属性名称语法来更新与给定输入名称相对应的 state(状态) 键:
        //下面这段代码等价于ES5代码:
        //var partialState = {};
        //partialState[name] = value;
        // this.setState(partialState);
        this.setState({ 
          [name]: value
        });
      }
    
      render() {
        return (
          <form>
            <label>
              Is going:
              <input
                name="isGoing"
                type="checkbox"
                checked={this.state.isGoing}
                onChange={this.handleInputChange} />
            </label>
            <br />
            <label>
              Number of guests:
              <input
                name="numberOfGuests"
                type="number"
                value={this.state.numberOfGuests}
                onChange={this.handleInputChange} />
            </label>
          </form>
        );
      }
    }

      6)如果您正在寻找一个完整的解决方案,包括验证、跟踪访问的字段以及处理表单提交,那么 Formik 是最受欢迎的选择之一。但是,它建立在受控组件和管理状态的相同原则之上 - 所以不要忽视学习它们。

    17、状态提升

      在一个 React 应用中,对于任何可变的数据都应该循序“单一数据源”原则。通常情况下,state 首先被添加到需要它进行渲染的组件。然后,如果其它的组件也需要它,你可以提升状态到它们最近的祖先组件。你应该依赖 从上到下的数据流向 ,而不是试图在不同的组件中同步状态。(官方demo: http://react.html.cn/docs/lifting-state-up.html)

    18、组合(Composition)VS 继承(Inheritance)

      在 Facebook ,我们在千万的组件中使用 React,我们还没有发现任何用例,值得我们建议你用继承层次结构来创建组件。

      使用 props(属性) 和 组合已经足够灵活来明确、安全的定制一个组件的外观和行为。切记,组件可以接受任意的 props(属性) ,包括原始值、React 元素,或者函数。

    //使用特别的 children prop 来直接传递 子元素,props.children自带props,代表子组件的内容
    function Dialog(props) {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            {props.title}
          </h1>
          <p className="Dialog-message">
            {props.message}
          </p>
          {props.children}
        </FancyBorder>
      );
    }
    
    class SignUpDialog extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.handleSignUp = this.handleSignUp.bind(this);
        this.state = {login: ''};
      }
    
      render() {
        return (
          <Dialog title="Mars Exploration Program"
                  message="How should we refer to you?">
            <input value={this.state.login}
                   onChange={this.handleChange} />
    
            <button onClick={this.handleSignUp}>
              Sign Me Up!
            </button>
          </Dialog>
        );
      }
    
      handleChange(e) {
        this.setState({login: e.target.value});
      }
    
      handleSignUp() {
        alert(`Welcome aboard, ${this.state.login}!`);
      }
    }

    19、优化性能

      1)ES6 对于数组支持展开语法 ,使得解决上述问题更加简单。如果你使用的是Create React App,默认支持该语法

    handleClick() {
      this.setState(state => ({
        words: [...state.words, 'marklar'],
      }));
    };
    //可以以一种简单的方式重写上述代码,使得改变对象的同时不会突变对象,例如,如果有一个 colormap 的对象并且编写一个函数将 colormap.right 的值改为 'blue'
    function updateColorMap(colormap) {
      colormap.right = 'blue';
    }
    //在不突变原来的对象的条件下实现上面的要求,我们可以使用Object.assign 方法:
    function updateColorMap(colormap) {
      return Object.assign({}, colormap, {right: 'blue'});
    }
    //updateColorMap 现在返回一个新的对象,而不是修改原来的对象。Object.assign 属于ES6语法,需要 polyfill。
    //JavaScript提案添加了对象展开符 ,能够更简单地更新对象而不突变对象。
    function updateColorMap(colormap) {
      return {...colormap, right: 'blue'};
    }

      2)使用 Immutable 数据结构  https://github.com/immutable-js/immutable-js

    //使用 Immutable 数据结构
    const SomeRecord = Immutable.Record({ foo: null });
    const x = new SomeRecord({ foo: 'bar' });
    const y = x.set('foo', 'baz');
    const z = x.set('foo', 'bar');
    x === y; // false
    x === z; // true
  • 相关阅读:
    点击某个内容复制到粘贴板
    滚动条全局样式
    23个Python爬虫开源项目代码:爬取微信、淘宝、豆瓣、知乎、微博等
    爬虫数据清洗
    邮件二次验证
    mysql基础语句
    orm操作
    解决跨域请求
    第二十一章 线程局部存储区
    第二十章 DLL高级技术
  • 原文地址:https://www.cnblogs.com/zhengyulu/p/12852450.html
Copyright © 2020-2023  润新知