精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

90行JS代碼構建屬于你的React

開發 前端
當我發現 React 所做的一切非常簡單,甚至如果我們不是下一家大型初創公司增加籌碼,僅需要很少的JS代碼就可以構建它。這也是促使我寫這篇文章的動力,希望你讀完這篇文章也有相同的感覺。

當我學習 React 的時候,我覺得它所做的一切都是魔術,然后我就開始思考這種魔術究竟是什么。我感到非常驚訝,當我發現 React 所做的一切非常簡單,甚至如果我們不是下一家大型初創公司增加籌碼,僅需要很少的JS代碼就可以構建它。這也是促使我寫這篇文章的動力,希望你讀完這篇文章也有相同的感覺。

我們將構建什么功能?

  •  JSX
  •  函數組件
  •  類組件
  •  生命周期鉤子函數

我們不會構建什么?

虛擬DOM

再次為了簡單起見,我們不會在本文中實現我們自己的虛擬DOM,我們將使用 snabbdom ,有趣的是,Vue.js 虛擬DOM借鑒了它,你可以在這里讀更多關于 snabbdom 的內容: https://github.com/snabbdom/s...

React Hooks

有些人可能對此感動失望,但是,一口吃不成一個胖子,我們需要一步一步來,因此讓我們首先構建基本的東西,然后再在此基礎上加以補充。我計劃后續文章中在我們此次構建的內容之上,編寫我們自己的 React Hooks 以及虛擬DOM,

可調試性

這是增加任何庫或框架的復雜度的關鍵部分之一,由于我們只是出于娛樂目的而做,因此我們可以放心地忽略 React 提供的可調試性功能,例如 dev tools 和分析器。

性能和兼容性

我們不會過于關注我們的庫的性能,我們只想構建能正常運行的庫。讓我們也不要費力地確保它可以在市場上的所有瀏覽器上使用,只有能夠在某些現代瀏覽器上可以使用,那就已經很好了。

讓我們開始動手

在開始之前,我們需要一個支持ES6,自動熱更新的腳手架。我已經創建了一個非常基礎的 webpack 腳手架,你可以進行克隆和設置: https://github.com/ameertheha...

[[282515]]

JSX

JSX 是一個開放標準,不僅限于 React,我們可以在沒有 React 的情況下使用它,它比你想象得還有容易。想要了解如何讓我們的庫支持 JSX ,我們首先需要看看在我們使用 JSX 時背后究竟發生了什么。 

  1. const App = (  
  2.     <div>  
  3.         <h1 className="primary">QndReact is Quick and dirty react</h1>  
  4.         <p>It is about building your own React in 90 lines of JavsScript</p>  
  5.     </div>  
  6. );  
  7. // 上面的 jsx 被轉換成下面這樣:  
  8. /**  
  9.  * React.createElement(type, attributes, children)  
  10.  */  
  11. var App = React.createElement(  
  12.     "div",  
  13.     null,  
  14.     React.createElement(  
  15.         "h1",  
  16.         {  
  17.             className: "primary"  
  18.         },  
  19.         "QndReact is Quick and dirty react"  
  20.     ),  
  21.     React.createElement(  
  22.         "p",  
  23.         null,  
  24.         "It is about building your own React in 90 lines of JavsScript"  
  25.     )  
  26. ); 

正如你看到的,每個 JSX 元素都通過 @babel/plugin-transform-react-jsx 插件轉換為了 React.createElement(...) 函數調用的形式,你可以在這里使用 JSX 進行更多的轉換

為了使上述轉換運行正常,在編寫 JSX 時,你需要引入 React,你就是為什么當你不引入 React 時,編寫 JSX 會出現錯誤的原因。 @babel/plugin-transform-react-jsx 插件已經添加在了我們的項目依賴中,下面我們先安裝一下依賴 

  1. npm install 

把項目的配置增加到 .babelrc 文件中: 

  1.  
  2.     "plugins": [  
  3.         [  
  4.             "@babel/plugin-transform-react-jsx",  
  5.             {  
  6.                 "pragma": "QndReact.createElement", // default pragma is React.createElement  
  7.                 "throwIfNamespace": false // defaults to true  
  8.             }  
  9.         ]  
  10.     ]  

此后,只要 Babel 看到 JSX ,它就會調用 QntReact.createElement(...),但是我們還未定義此函數,現在我們將其寫到 src/qnd-react.js 中。 

  1. const createElement = (type, props = {}, ...children) => {  
  2.     console.log(type, props, children);  
  3. };  
  4. // 像 React.createElement 一樣導出  
  5. const QndReact = {  
  6.     createElement  
  7. };  
  8. export default QndReact; 

我們在控制臺打印出了傳遞給我們的 type 、 props、 children。為了測試我們的轉換是否正常,我們可以在 src/index.js 中編寫一些 JSX 。 

  1. // QndReact 需要被引入  
  2. import QndReact from "./qnd-react";  
  3. const App = (  
  4.     <div>  
  5.         <h1 className="primary">  
  6.             QndReact is Quick and dirty react  
  7.         </h1>  
  8.         <p>It is about building your own React in 90 lines of JavsScript</p>  
  9.     </div>  
  10. ); 

啟動項目: npm start,在瀏覽器輸入localhost:3000,現在你的控制臺看起來應該與下圖類似:

根據以上信息,我們可以使用 snabbdom 創建我們內部的 虛擬DOM節點 ,然后我們才能將其用于我們的協調(reconciliation) 過程,可以使用如下的命令安裝 snabbdom: 

  1. npm install snabbdom 

當 QndReact.createElement(...) 被調用時嗎,創建和返回 虛擬DOM節點。 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     return h(type, { props }, children);  
  5. };  
  6. const QndReact = {  
  7.     createElement  
  8. };  
  9. export default QndReact; 

很好,現在我們可以解析 JSX 并創建自己的虛擬DOM節點,但是仍然無法在瀏覽器中呈現出來。為此,我們在 src/qnd-react-dom.js 添加一個 render 方法。 

  1. //src/qnd-react-dom.js  
  2. //React.render(<App />, document.getElementById('root'));  
  3. const render = (el, rootElement) => {  
  4.     //將el渲染到rootElement的邏輯  
  5.  
  6. const QndReactDom = {  
  7.     render  

與其我們自己去處理將元素放到 DOM 上的繁重工作,不如讓 snabbdom 去處理。為此我們可以引入模塊去初始化 snabbdom。snabbdom 中的模塊可以看做是插件,可以支持 snabbdom 做更多的事。 

  1. //src/qnd-react-dom.js  
  2. import * as snabbdom from 'snabbdom';  
  3. import propsModule from 'snabbdom/modules/props';  
  4. const reconcile = snabbdom.init([propsModule]);  
  5. const render = (el, rootDomElement) => {  
  6.     //將el渲染到rootElement  
  7.     reconcile(rootDomElement, el);  
  8.  
  9. const QndReactDom = {  
  10.     render  
  11.  
  12. export default QndReactDom; 

我們使用這個新的 render 函數去 src/index 中去做一些魔法。 

  1. //src/index.js  
  2. import QndReact from "./qnd-react";  
  3. import QndReactDom from './qnd-react-dom';  
  4. const App = (  
  5.     <div>  
  6.         <h1 className="primary">  
  7.             QndReact is Quick and dirty react  
  8.         </h1>  
  9.         <p>It is about building your own React in 90 lines of JavsScript</p>  
  10.     </div>  
  11. );  
  12. QndReactDom.render(App, document.getElementById('root')); 

瞧,我們的JSX已經可以渲染到屏幕上了。

等下,這個有一個小問題,當我們兩次調用 render 時,我們會在控制臺看到一些奇怪的錯誤(譯者注: 可以在 index.js 中多次調用 render,查看控制臺錯誤),背后的原因是我們只有在第一次渲染時,可以在真實的DOM節點上調用 reconcile 方法,然后,我們應該在之前返回的虛擬DOM節點上調用。 

  1. //src/qnd-react-dom.js  
  2. import * as snabbdom from 'snabbdom';  
  3. import propsModule from 'snabbdom/modules/props';  
  4. const reconcile = snabbdom.init([propsModule]);  
  5. let rootVNode;  
  6. //QndReactDom.render(App, document.getElementById('root'))  
  7. const render = (el, rootDomElement) => {  
  8.     if(rootVNode == null) {  
  9.         //第一次調用 render 時  
  10.         rootVNode = rootDomElement 
  11.     }  
  12.     rootVNode = reconcile(rootVNode, el);  
  13.  
  14. const QndReactDom = {  
  15.     render  
  16.  
  17. export default QndReactDom; 

很開心,我們的應用程序中有一個能正常工作的 JSX 渲染,現在讓我們開始渲染一個函數組件,而不僅僅是一些普通的 HTML。

讓我們向 src/index.js 添加一個 Greeting 函數組件,如下所示: 

  1. //src/index.js  
  2. import QndReact from "./qnd-react";  
  3. import QndReactDom from './qnd-react-dom';  
  4. const Greeting = ({ name }) => <p>Welcome {name}!</p> 
  5. const App = (  
  6.     <div>  
  7.         <h1 className="primary">  
  8.             QndReact is Quick and dirty react  
  9.         </h1>  
  10.         <p>It is about building your own React in 90 lines of JavsScript</p>  
  11.         <Greeting name={"Ameer Jhan"} />  
  12.     </div>  
  13. );  
  14. QndReactDom.render(App, document.getElementById('root')); 

此時,在控制臺會出現以下錯誤:

我們可以在 QndReact.createElement(...) 方法中打印出數據看一下原因。 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     console.log(type, props, children);  
  5.     return h(type, { props }, children);  
  6. };  
  7. ... 

 

如果可以看到,函數組件傳遞過來的 type 是一個JS函數。如果我們調用這個函數,就能獲得組件希望渲染的 HTML 結果。

我們根據 type 參數的類型,如果是函數類型,我們就調用這個函數,并將 props 作為參數傳給它,如果不是函數類型,我們就當作普通的 HTML 元素處理。 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     //如果是函數組件,那么調用它,并返回執行結果  
  5.     if (typeof (type) == 'function') {  
  6.         return type(props);  
  7.     }  
  8.     return h(type, { props }, children);  
  9. };  
  10. const QndReact = {  
  11.     createElement  
  12. };  
  13. export default QndReact; 

歡呼!我們的函數組件已經可以正常工作了。

我們已經完成了很多,讓我們深吸一口氣,喝杯咖啡,因為我們已經差不多實現了 React,不過我們還需要攻克類組件。

我們首先在 src/qnd-react.js 中創建 Component 基類: 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     //如果是函數組件,那么調用它,并返回執行結果  
  5.     if (typeof (type) == 'function') {  
  6.         return type(props);  
  7.     }  
  8.     return h(type, { props }, children);  
  9. };  
  10. class Component {  
  11.     constructor() { }  
  12.     componentDidMount() { }  
  13.     setState(partialState) { }  
  14.     render() { }  
  15.  
  16. const QndReact = {  
  17.     createElement,  
  18.     Component  
  19. };  
  20. export default QndReact; 

現在我們在 src/counter.js 中編寫我們的第一個 Counter 類組件: 

  1. //src/counter.js  
  2. import QndReact from './qnd-react';  
  3. export default class Counter extends QndReact.Component {  
  4.     constructor(props) {  
  5.         super(props);  
  6.         this.state = {  
  7.             count: 0  
  8.         }  
  9.     }  
  10.     componentDidMount() {  
  11.         console.log('Component mounted');  
  12.     }  
  13.     render() {  
  14.         return <p>Count: {this.state.count}</p>  
  15.     }  

是的,我知道我們尚未在計數器中實現任何邏輯,但是別擔心,一旦我們的狀態管理系統運行正常,我們就會添加這些內容。現在,讓我們嘗試在 src/index.js 中渲染它。 

  1. //src/index.js  
  2. import QndReact from "./qnd-react";  
  3. import QndReactDom from './qnd-react-dom';  
  4. import Counter from "./counter";  
  5. const Greeting = ({ name }) => <p>Welcome {name}!</p> 
  6. const App = (  
  7.     <div>  
  8.         <h1 className="primary">  
  9.             QndReact is Quick and dirty react  
  10.         </h1>  
  11.         <p>It is about building your own React in 90 lines of JavsScript</p>  
  12.         <Greeting name={"Ameer Jhan"} />  
  13.         <Counter />  
  14.     </div>  
  15. );  
  16. QndReactDom.render(App, document.getElementById('root')); 

和料想中的一樣,又又又報錯了。

上面的錯誤看起來是不是很熟悉,當你嘗試使用類組件而不集成自 React.Component 時,可能遇到過以上錯誤。要知道為什么會這樣,我們可以在 React.createElement(...) 中添加一個 console.log,如下所示: 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     console.log(typeof (type), type);  
  5.     //如果是函數組件,那么調用它,并返回執行結果  
  6.     if (typeof (type) == 'function') {  
  7.         return type(props);  
  8.     }  
  9.     return h(type, { props }, children);  
  10. }; 

我們來看看控制臺打印了什么內容。

你可以看出 Counter 的 type 類型也是函數,這是因為 Babel 會將 ES6 類轉換為普通的 JS 函數,那么我們該如何類組件的情況呢。其實,我們可以在我們的 Component 基類中添加一個靜態屬性,這樣我們利用該屬性去檢查 type 參數是否是一個類。React 中也是相同的處理邏輯,你可以閱讀 Dan的博客 

  1. //src/qnt-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     console.log(typeof (type), type);  
  5.     //如果是函數組件,那么調用它,并返回執行結果  
  6.     if (typeof (type) == 'function') {  
  7.         return type(props);  
  8.     }  
  9.     return h(type, { props }, children);  
  10. }; 
  11. class Component {  
  12.     constructor() { }  
  13.     componentDidMount() { }  
  14.     setState(partialState) { }  
  15.     render() { }  
  16.  
  17. //給 Component 組件添加靜態屬性來區分是函數還是類   
  18. Component.prototype.isQndReactClassComponent = true 
  19. const QndReact = {  
  20.     createElement,  
  21.     Component  
  22. };  
  23. export default QndReact; 

現在,我們在 QndReact.createElement(...) 中增加一些代碼來處理類組件。 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     console.log(type.prototype);  
  5.     /**  
  6.      * 如果是類組件  
  7.      * 1.創建一個實例  
  8.      * 2.調用實例的 render 方法  
  9.      */  
  10.     if (type.prototype && type.prototype.isQndReactClassComponent) {  
  11.         const componentInstance = new type(props);  
  12.         return componentInstance.render();  
  13.     }  
  14.     //如果是函數組件,那么調用它,并返回執行結果  
  15.     if (typeof (type) == 'function') {  
  16.         return type(props);  
  17.     }  
  18.     return h(type, { props }, children);  
  19. };  
  20. class Component {  
  21.     constructor() { }  
  22.     componentDidMount() { }  
  23.     setState(partialState) { }  
  24.     render() { }  
  25.  
  26. //給 Component 組件添加靜態屬性來區分是函數還是類   
  27. Component.prototype.isQndReactClassComponent = true 
  28. const QndReact = {  
  29.     createElement,  
  30.     Component  
  31. };  
  32. export default QndReact; 

現在,我們的類組件已經能夠渲染到瀏覽器上了:

我們向類組件中增加 state,在此之前,我們需要知道,每次調用 this.setState({}) 時,如何更新 DOM 的責任是 react-dom 包,而不是 React 的責任。這是為了使 React 的核心部分,例如Component 類與平臺分離,從而提升代碼的可重用性。即在 ReactNative 中,你也可以使用同樣的 Component 類,react-native 負責如何更新UI。你可能會問自己:當調用 this.setState(...) 時,React 如何知道該怎么做,答案就是 react-dom 通過在 React 上設置了一個 __updater 屬性與 React 進行通信。Dan 對此也有出色的文章,你可以點擊閱讀。現在讓我們在 QndReactDom 中為 QndReact 添加 __updater 屬性。

  1. //src/qnd-react-dom.js  
  2. import QndReact from './qnd-react';  
  3. import * as snabbdom from 'snabbdom';  
  4. import propsModule from 'snabbdom/modules/props';  
  5. ...  
  6. //QndReactDom 告訴 QndReact 如何更新 DOM  
  7. QndReact.__updater = () => {  
  8.     //當調用 this.setState 的時候更新 DOM 邏輯  

無論何時我們調用 this.setState({...}),我們都需要比較組件的 oldVNode 和在組件上調用了 render 方法之后生成的 newVNode。為了進行比較,我們在類組件上添加 __vNode 屬性,以維護該組件當前的 VNode 實例。 

  1. //src/qnd-react.js  
  2. ...  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     /**  
  5.      * 如果是類組件  
  6.      * 1.創建一個實例  
  7.      * 2.調用實例的 render 方法  
  8.      */  
  9.     if (type.prototype && type.prototype.isQndReactClassComponent) {  
  10.         const componentInstance = new type(props);  
  11.         componentInstancecomponentInstance.__vNode = componentInstance.render();  
  12.         return componentInstance.__vNode;  
  13.     }  
  14.     //如果是函數組件,那么調用它,并返回執行結果  
  15.     if (typeof (type) == 'function') {  
  16.         return type(props);  
  17.     }  
  18.     return h(type, { props }, children);  
  19. };  
  20. ... 

現在我們來在 Component 的基類中實現 setState 方法。 

  1. //src/qnd-react.js  
  2. ...  
  3. class Component {  
  4.     constructor() { }  
  5.     componentDidMount() { }  
  6.     setState(partialState) {   
  7.         this.state = {  
  8.             ...this.state,  
  9.             ...partialState  
  10.         }  
  11.         //調用 QndReactDom 提供的 __updater 方法  
  12.         QndReact.__updater(this);  
  13.     }  
  14.     render() { }  
  15.  
  16. ... 

處理 QndReactDom 中的 __updater 方法。 

  1. //src/qnd-react-dom.js  
  2. ...  
  3. QndReact.__updater = (componentInstance) => {  
  4.     //當調用 this.setState 的時候更新 DOM 邏輯  
  5.     //獲取在 __vNode 上存儲的 oldVNode  
  6.     const oldVNode = componentInstance.__vNode;  
  7.     //獲取 newVNode  
  8.     const newVNode = componentInstance.render();  
  9.     //更新 __vNode  
  10.     componentInstance.__vNode = reconcile(oldVNode, newVNode);  
  11.  
  12. ...  
  13. export default QndReactDom; 

OK,我們在 Counter 組件中增加 state 來檢驗我們的 setState 實現是否生效。 

  1. //src/counter.js  
  2. import QndReact from './qnd-react';  
  3. export default class Counter extends QndReact.Component {  
  4.     constructor(props) {  
  5.         super(props);  
  6.         this.state = {  
  7.             count: 0  
  8.         }  
  9.         // update the count every second  
  10.         setInterval(() => {  
  11.             this.setState({  
  12.                 count: this.state.count + 1  
  13.             })  
  14.         }, 1000);  
  15.     }  
  16.     componentDidMount() {  
  17.         console.log('Component mounted');  
  18.     }  
  19.     render() {  
  20.         return <p>Count: {this.state.count}</p>  
  21.     }  

太棒啦,現在 Counter 組件運行情況與我們預期完全一致。

我們繼續添加 componentDidMount 的生命周期鉤子函數。 Snabbdom 提供了一些鉤子函數,通過他們,我們可以知道真實DOM上面是否有添加,刪除或是更新了虛擬DOM節點,你可以在此處了解更多信息。 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     /**  
  5.      * 如果是類組件  
  6.      * 1.創建一個實例  
  7.      * 2.調用實例的 render 方法  
  8.      */  
  9.     if (type.prototype && type.prototype.isQndReactClassComponent) {  
  10.         const componentInstance = new type(props);  
  11.         componentInstancecomponentInstance.__vNode = componentInstance.render();  
  12.         return componentInstance.__vNode;  
  13.         //增加鉤子函數(當虛擬DOM被添加到真實DOM節點上時)  
  14.         componentInstance.__vNode.data.hook = {  
  15.             create: () => {  
  16.                 componentInstance.componentDidMount()  
  17.             }  
  18.         }  
  19.     }  
  20.     //如果是函數組件,那么調用它,并返回執行結果  
  21.     if (typeof (type) == 'function') {  
  22.         return type(props);  
  23.     }  
  24.     return h(type, { props }, children);  
  25. };  
  26. ...  
  27. export default QndReact; 

至此,我們已經在類組件上支持了 componentDidMount 生命周期鉤子函數。

結束之前,我們再添加下事件綁定的支持。為此,我們可以在 Counter 組件中增加一個按鈕,點擊的時候,計數器的數字增加。請注意,我們遵循的是基于常規的JS事件命名約定,而非基于 React,即雙擊事件使用 onDblClick,而非 onDoubleClick。 

  1. import QndReact from './qnd-react';  
  2. export default class Counter extends QndReact.Component {  
  3.     constructor(props) {  
  4.         super(props);  
  5.         this.state = {  
  6.             count: 0  
  7.         }  
  8.     }  
  9.     componentDidMount() {  
  10.         console.log('Component mounted');  
  11.     }  
  12.     render() {  
  13.         return (  
  14.             <div>  
  15.                 <p>Count: {this.state.count}</p>  
  16.                 <button onClick={() => this.setState({  
  17.                     count: this.state.count + 1  
  18.                 })}>Increment</button>  
  19.             </div>  
  20.         )  
  21.     }  

上面的組件不會正常工作,因為我們沒有告訴我們的 VDom 如何去處理它。首先,我們給 Snabdom 增加事件監聽模塊。 

  1. //src/qnd-react-dom.js  
  2. import QndReact from './qnd-react';  
  3. import * as snabbdom from 'snabbdom';  
  4. import propsModule from 'snabbdom/modules/props';  
  5. import eventlistenersModule from 'snabbdom/modules/eventlisteners';  
  6. const reconcile = snabbdom.init([propsModule, eventlistenersModule]);  
  7. ... 

Snabdom 希望將文本屬性和事件屬性作為兩個單獨的對象,我們我們需要這樣做: 

  1. //src/qnd-react.js  
  2. import { h } from 'snabbdom';  
  3. const createElement = (type, props = {}, ...children) => {  
  4.     ...  
  5.     let dataProps = {};  
  6.     let eventProps = {};  
  7.     for (let propKey in props) {  
  8.         // event 屬性總是以 `on` 開頭  
  9.         if (propKey.startsWith('on')) {  
  10.             const event = propKey.substring(2).toLowerCase();  
  11.             eventProps[event] = props[propKey];  
  12.         } else {  
  13.             dataProps[propKey] = props[propKey];  
  14.         }  
  15.     }  
  16.     return h(type, { props: dataProps, on: eventProps }, children);  
  17. };  
  18. ... 

現在當我們點擊 Counter 組件的按鈕的時候,計數器加1。

太棒了,我們終于完成了一個React的簡陋的實現。但是,我們還不能呈現列表,我想把它作為有趣的小任務交給您。我建議您嘗試在 src/index.js 中呈現一個列表,然后調試 QndReact.createElement(...) 方法找出問題所在。

感謝您一直陪伴我,希望您喜歡構建自己的 React ,并了解了 React 在此過程中是如何工作的。如果您在任何地方卡住了,請隨時參考我共享的代碼: https://github.com/ameertheha...

 

 

責任編輯:龐桂玉 來源: Win10系統之家
相關推薦

2017-03-28 21:03:35

代碼React.js

2023-10-08 18:05:57

2022-02-08 12:30:30

React事件系統React事件系統

2014-06-19 10:02:32

Haskell代碼

2021-09-09 05:57:57

JS模塊打包器前端

2025-10-27 02:25:00

2012-06-18 15:18:32

JS

2023-07-03 07:51:47

2021-12-16 06:21:16

React組件前端

2022-04-15 08:07:21

ReactDiff算法

2016-10-09 11:03:41

Javascript模塊化Web

2021-01-24 16:00:22

Ansible系統運維

2021-06-22 10:16:39

Java工具庫代碼

2017-05-08 14:27:49

PHP框架函數框架

2015-04-28 09:21:28

JSJS俄羅斯方塊游戲帝國

2017-12-25 05:08:53

智能客服深度學習人工智能

2020-04-27 14:54:45

React開發

2025-03-25 08:15:00

JavaScript開發代碼

2021-12-26 12:10:21

React組件前端

2021-02-01 13:59:47

比特幣區塊鏈安全
點贊
收藏

51CTO技術棧公眾號

日本sm残虐另类| 视频一区在线观看| 亚洲韩国一区二区三区| 国产精品三区四区| 天码人妻一区二区三区在线看| 亚洲小说图片视频| 555夜色666亚洲国产免| 亚洲精品久久久久久久蜜桃臀| 日夜干在线视频| 麻豆精品在线看| 欧美福利小视频| 白丝女仆被免费网站| 91麻豆精品一二三区在线| 亚洲成a天堂v人片| 永久免费精品视频网站| 无码精品黑人一区二区三区| 麻豆freexxxx性91精品| 性色av一区二区咪爱| 欧美自拍偷拍网| 国内精品偷拍| 91成人看片片| 日本a视频在线观看| 在线观看黄色av| av电影天堂一区二区在线观看| 国产欧美中文字幕| 久久久精品视频网站| 好看不卡的中文字幕| 亚洲人av在线影院| 国产日韩视频一区| 国产一区二区在线观| 欧美午夜精品久久久| 国产白丝袜美女久久久久| 宅男在线观看免费高清网站| 中文字幕第一区综合| 欧美三级电影在线播放| 日本韩国在线观看| 岛国精品一区二区| 亚洲wwwav| 国产一区二区三区三州| 日韩不卡一区二区三区| 日本国产欧美一区二区三区| 成年人午夜视频| 一区免费视频| 欧美激情a在线| 草视频在线观看| 98精品久久久久久久| 永久免费精品影视网站| 黄色三级生活片| 欧美美乳视频| 亚洲毛片在线看| 成年人在线观看av| 日韩深夜福利| 精品视频偷偷看在线观看| 国产精品一区二区三区不卡 | 热久久天天拍国产| 精品亚洲国产成av人片传媒| 99久久人妻精品免费二区| 99国产精品久久一区二区三区| 91精品欧美综合在线观看最新| 天天操狠狠操夜夜操| 精品久久99| 欧美三级乱人伦电影| 亚洲黄色小视频在线观看| 日韩高清成人| 欧美喷潮久久久xxxxx| 一个色综合久久| 国产精品亚洲一区二区在线观看 | 欧美在线观看视频网站| av有声小说一区二区三区| 欧美亚洲一区三区| av免费一区二区| 国产成人免费视频网站视频社区| 欧美一卡2卡3卡4卡| 国产性猛交96| 日本一区福利在线| 一区二区三区 在线观看视| 能直接看的av| 影视一区二区| 欧美亚州一区二区三区| 四虎影院在线免费播放| 九九在线精品视频| 超碰97在线播放| 深夜影院在线观看| 国产精品久久久一本精品| 看全色黄大色大片| 天堂av中文在线观看| 欧美日韩一区精品| 韩国黄色一级片| 亚洲图区在线| 久久亚洲影音av资源网| 日本少妇裸体做爰| 免费成人在线影院| 99久久99久久精品国产片| 亚洲av成人精品一区二区三区在线播放 | 国内精品久久久久影院优 | 免费黄色在线| 亚洲午夜激情网页| 成人午夜激情av| 日韩欧美激情电影| 亚洲男子天堂网| 亚洲 欧美 变态 另类 综合| 99成人在线| 国产精自产拍久久久久久| 秋霞网一区二区| 国产精品免费人成网站| 国产精品www在线观看| 国精产品一区二区三区有限公司| 日韩一区二区三区免费观看| 国产免费看av| 国产一区二区三区四区三区四| 欧洲一区二区视频| 国内精品偷拍视频| 国产精品美女久久久久av爽李琼| 欧美人成在线观看| 欧美大陆国产| 亚洲欧洲日产国产网站| 久久艹精品视频| 久久 天天综合| 日韩一区免费观看| 91九色在线看| 欧美日韩亚洲综合在线| 美女久久久久久久久久| 狠狠88综合久久久久综合网| 国产有码在线一区二区视频| 精品视频一二三| 亚洲二区在线观看| 日韩成人av免费| 经典一区二区| 欧美亚洲一级片| 亚洲精品久久久蜜桃动漫| 国产精品欧美极品| 丰满少妇在线观看| 怕怕欧美视频免费大全| 午夜精品蜜臀一区二区三区免费| www男人的天堂| 1000部国产精品成人观看| 激情综合网俺也去| 免费成人av| 欧美一级淫片videoshd| 天堂在线观看免费视频| 亚洲国产乱码最新视频 | 99在线免费视频观看| 日韩精品一级| 欧美成人网在线| 国产精品国产三级国产普通话对白| 国产亚洲短视频| 日本精品久久久久中文字幕| 婷婷成人在线| 青青草99啪国产免费| 青青草在线免费观看| 婷婷开心激情综合| 粉嫩av懂色av蜜臀av分享| 亚洲国产日韩欧美一区二区三区| 国产伦精品一区二区三区| 国内高清免费在线视频| 亚洲第一视频网站| 日本三级理论片| www.日韩在线| 久草精品在线播放| 国产精品一区二区av日韩在线| 热草久综合在线| 国产小视频在线观看| 91黄色在线观看| 国产一二三四视频| 国产一区久久久| 中文字幕精品在线播放| av综合网页| 午夜精品福利电影| 欧美偷拍视频| 欧美三级视频在线观看| 三级在线观看免费大全| 国产九九视频一区二区三区| 激情小视频网站| 婷婷成人综合| 国产日韩欧美自拍| 日韩av官网| 亚洲码在线观看| 亚洲一区二区影视| 亚洲最新视频在线播放| 人妻丰满熟妇av无码久久洗澡| 久久九九精品| 日本成人性视频| 国产精品一区二区中文字幕| 欧美孕妇孕交黑巨大网站| 91精彩在线视频| 日韩一区二区三区四区| 欧美日韩一二三四区| 国产精品久久久久影院亚瑟| 欧美69精品久久久久久不卡| 亚洲综合国产| 异国色恋浪漫潭| 精品人人人人| 国产精品偷伦一区二区| 青青青草视频在线| 亚洲日本成人女熟在线观看| 国产乱码精品一区二区| 精品福利樱桃av导航| 肉色超薄丝袜脚交69xx图片| 成人一区在线观看| 国产精品久久久毛片| 精品福利av| 亚洲人成影视在线观看| 久久精品66| 国产日韩av在线播放| 99热99re6国产在线播放| 最近2019中文字幕大全第二页| 空姐吹箫视频大全| 欧美片在线播放| 国内精品福利视频| 亚洲午夜影视影院在线观看| 黄色免费一级视频| 91小视频在线免费看| 91丨porny丨九色| 日韩av不卡在线观看| 欧美视频在线观看视频| 91精品一区二区三区综合| 欧美不卡在线一区二区三区| 色妞ww精品视频7777| 国产精品中文在线| xx欧美视频| 久久久久久久成人| 高潮毛片在线观看| 综合av色偷偷网| 日韩一二三四| 欧美精品一区二区精品网| 一级片aaaa| 在线视频欧美精品| 亚洲免费在线视频观看| 亚洲午夜一区二区| 久久久久久久极品内射| 中文字幕一区二| 极品久久久久久久| 久久这里只有精品首页| av网页在线观看| 懂色av噜噜一区二区三区av| 日本高清免费在线视频| 免费观看成人av| 黄色片视频在线| 三级在线观看一区二区| 人妻有码中文字幕| 国产欧美欧美| 国产高清精品在线观看| 一区二区亚洲| 免费一级特黄毛片| 国产精品大片| 久久99久久99精品| 午夜精品999| a级片一区二区| 欧美xxx在线观看| 欧美一级爱爱视频| 欧美国产激情| 国产精品国产三级国产专区51| 欧美/亚洲一区| 美女av免费观看| 亚洲网站在线| 欧美,日韩,国产在线| 99成人精品| 欧美a在线视频| 老司机亚洲精品| av网址在线观看免费| 首页欧美精品中文字幕| 中文字幕永久视频| 久久99精品国产91久久来源| www.国产福利| 成人精品国产免费网站| 激情综合丁香五月| 国产亚洲视频系列| 午夜国产福利视频| 亚洲精品中文在线影院| 久草视频免费播放| 丰满岳妇乱一区二区三区| 亚洲欧美偷拍一区| 欧美日韩成人综合在线一区二区 | 国产粉嫩在线观看| 欧洲美女7788成人免费视频| 国产第一亚洲| a级国产乱理论片在线观看99| 激情视频极品美女日韩| 欧美一级片免费观看| 日韩精品久久| 男人添女荫道口女人有什么感觉| 中文日韩欧美| 性欧美1819| 粉嫩av一区二区三区粉嫩| 特级西西人体wwwww| 中文字幕乱码一区二区免费| 中文字幕av久久爽av| 欧美性黄网官网| 伊人网视频在线| 欧美精品一区二区三区高清aⅴ | 久久精品视频在线| 丰满诱人av在线播放| 国产精品91一区| 日韩精品视频在线看| 欧美凹凸一区二区三区视频| 艳女tv在线观看国产一区| 人人妻人人添人人爽欧美一区| 日韩电影在线看| 在线观看一区二区三区四区| 欧美国产视频在线| 国产午夜精品无码| 欧美日韩免费一区二区三区 | 2019中文亚洲字幕| 另类小说综合网| 欧美.www| 在线看的黄色网址| 99视频精品全部免费在线| 娇小11一12╳yⅹ╳毛片| 日韩欧美国产黄色| 性猛交富婆╳xxx乱大交天津| 国产一区二区三区四区福利| 日本高清在线观看视频| 国产精品永久免费在线| 久久精品凹凸全集| 久久综合久久久久| 国内精品国产三级国产a久久| 精品国产成人亚洲午夜福利| 亚洲国产欧美日韩另类综合| 国产强伦人妻毛片| 一区二区成人av| 2022成人影院| 国产亚洲自拍偷拍| 综合五月婷婷| 手机版av在线| 日本一区二区成人在线| 亚洲天堂一区在线| 欧美精品一区二区三区蜜臀| 污视频在线看网站| 成人精品一区二区三区电影免费| 精品国产欧美日韩| 欧美s码亚洲码精品m码| 成人午夜电影久久影院| www青青草原| 欧美放荡的少妇| 一级毛片视频在线观看| 国产精品久久久久久久av电影| 亚洲人成网www| av7777777| av成人免费在线观看| 国产无遮挡又黄又爽又色| 精品久久国产老人久久综合| 神马午夜伦理不卡| 91情侣偷在线精品国产| 亚洲欧洲日韩| 一区二区久久精品| 最新国产の精品合集bt伙计| 在线免费一级片| 久久精品国产一区| 成人亚洲精品| 色哺乳xxxxhd奶水米仓惠香| 国产精品自拍网站| 久操免费在线视频| 精品精品欲导航| 黄色成人在线网| 精品日产一区2区三区黄免费| 亚洲免费观看| 亚洲av综合一区二区| 在线看日韩精品电影| 1024视频在线| 亚洲xxxx3d| 国内精品福利| 三级黄色片网站| 91国产丝袜在线播放| 在线观看av黄网站永久| 成人免费高清完整版在线观看| 午夜精品毛片| 久久久无码人妻精品无码| 亚洲国产中文字幕在线视频综合| 色呦呦中文字幕| 国产成人精品国内自产拍免费看| 成人网18免费网站| 成人性生交视频免费观看| 亚洲制服丝袜一区| 日韩在线免费看| 国产在线a不卡| 欧美日韩免费| 精品人妻一区二区三区视频| 欧美丝袜第三区| 色综合999| 欧美日韩国产精品一区二区| 久久国产欧美日韩精品| 欧美人妻精品一区二区免费看| 日韩电影免费在线观看中文字幕 | 亚洲视频碰碰| 午夜时刻免费入口| 56国语精品自产拍在线观看| 黄色软件视频在线观看| 日韩妆和欧美的一区二区| 国产裸体歌舞团一区二区| 圆产精品久久久久久久久久久| 在线a欧美视频| 久久a爱视频| 天天影视色综合| 偷拍亚洲欧洲综合| 免费超碰在线| 久久久久久a亚洲欧洲aⅴ| 激情五月播播久久久精品| 在线观看免费国产视频| 久久夜精品香蕉| 经典一区二区|