成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何在React中做到jQuery-free

開發 前端
討論如何使用 React 自帶的強大功能,和一些良心第三方庫屏蔽兼容性,來取代 jQuery 的主要功能,做到 jQuery-free。在 jQuery 中,我們已經熟悉了使用 sizzle 選擇器來完成 DOM 元素的選取。而在 React 中,我們可以使用 ref 來更有針對性的獲取元素。

前言

前些天在訂閱的公眾號中看到了以前阮一峰老師寫過的一篇文章,「如何做到 jQuery-free?」。這篇文章討論的問題,在今天來看仍不過時,其中的一些點的討論主要是面向新內核現代瀏覽器的標準 DOM API,很可惜的是在目前的開發環境下,我們仍然無法完全拋棄 IE,大部分情況下我們至少還要兼容到 IE 8,這一點使我們無法充分踐行文章中提到的一些點,而本文也正是***啟發,順著阮老師文章的思路來討論如何在 React 中實戰 IE8-compatible 的 jQuery-free。

首先我們仍要說的是,jQuery 是現在***的 JavaScript 工具庫。在 W3techs 的統計中,目前全世界 70.6% 的網站在使用他,而 React 甚至還不到 0.1%,但 React 一個值得注意的趨勢是,他在目前***流量網站中的使用率是***的,比例達到了 16%。這一趨勢也表明了目前整個前端界的技術趨勢,但 70.6% 的數字也在告訴我們,jQuery 在 JS 庫中的王者地位,即使使用了React,也可能因為各種各樣的原因,還要和 jQuery 來配合使用。但 React 本身的體積已經讓我們對任何一個重庫產生了不適反應,為了兼容 IE8,我們仍然需要使用 1.x 的 jQuery 版本,但當時設計上的缺陷使得我們無法像 lodash 那樣按需獲取。而 React 和 jsx 的強大,又使得我們不需要了 jQuery 的大部分功能。從這個角度來看,他臃腫的體積讓開發者更加難以忍受,jQuery-free 勢在必行。

下面就順著阮老師當年的思路,來討論如何使用 React 自帶的強大功能,和一些良心第三方庫屏蔽兼容性,來取代 jQuery 的主要功能,做到 jQuery-free。

(注:React 15.x 版本已經不再兼容 IE8,因此本文討論的 React 仍是 0.14.x 的版本,同時為了易于理解,本文也基本上以 ES6 class 的方式來聲明組件,而不采用 pure function。)

一、選取 DOM 元素

在 jQuery 中,我們已經熟悉了使用 sizzle 選擇器來完成 DOM 元素的選取。而在 React 中,我們可以使用 ref 來更有針對性的獲取元素。

  1. import React from 'react'
  2. class Demo extends React.Compoent { 
  3.  
  4.     getDomNode() { 
  5.         return this.refs.root; // 獲取 Dom Node 
  6.     } 
  7.     render() { 
  8.         return ( 
  9.             <div ref="root">just a demo</div> 
  10.         ); 
  11.     } 

這是最簡單的獲取 node 的方式,如果有多層結構嵌套呢?沒有關系。

  1. import React from 'react'
  2. class Demo extends React.Compoent { 
  3.  
  4.     getRootNode() { 
  5.         return this.refs.root; // 獲取根節點 Dom Node 
  6.     } 
  7.     getLeafNode() { 
  8.         return this.refs.leaf; // 獲取葉節點 Dom Node 
  9.     } 
  10.     render() { 
  11.         return ( 
  12.             <div ref="root"
  13.                 <div ref="leaf">just a demo</div> 
  14.             </div> 
  15.         ); 
  16.     } 

如果是組件和組件嵌套呢?也沒關系,父組件仍然可以拿到子組件的根節點。

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. class Sub extends React.Compoent { 
  4.     render() { 
  5.         return ( 
  6.             <div>a sub component</div> 
  7.         ); 
  8.     } 
  9. class Demo extends React.Compoent { 
  10.  
  11.     getDomNode() { 
  12.         return this.refs.root; // 獲取 Dom Node 
  13.     } 
  14.      
  15.     getSubNode() { 
  16.         return ReactDOM.findDOMNode(this.refs.sub); // 獲取子組件根節點 
  17.     } 
  18.     render() { 
  19.         return ( 
  20.             <div ref="root"
  21.                 <Sub ref="sub" /> 
  22.             </div> 
  23.         ); 
  24.     } 

上面使用了比較易懂的 API 來解釋 Ref 的用法,但里面包含了一些現在 React 不太推薦和即將廢棄的方法,如果用 React 推薦的寫法,我們可以這樣寫。

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. class Sub extends React.Compoent { 
  4.     getDomNode() { 
  5.         return this.rootNode; 
  6.     } 
  7.     render() { 
  8.         return ( 
  9.             <div ref={(c) => this.rootNode = c}>a sub component</div> 
  10.         ); 
  11.     } 
  12. class Demo extends React.Compoent { 
  13.  
  14.     getDomNode() { 
  15.         return this.rootNode; // 獲取 Dom Node 
  16.     } 
  17.      
  18.     getSubNode() { 
  19.         return this.sub.getDomNode(); // 獲取子組件根節點 
  20.     } 
  21.     render() { 
  22.         return ( 
  23.             <div ref={(c) => this.rootNode = c}> 
  24.                 <Sub ref={(c) => this.sub = c} /> 
  25.             </div> 
  26.         ); 
  27.     } 

有人可能會問,那子組件怎么拿父組件的 Dom Node 呢,從 React 的單向數據流角度出發,遇到這種情況我們應該通過回調通知給父組件,再由父組件自行判斷如何修改 Node,其實父組件拿子組件的 Node 情況也很少,大多數情況下我們是通過 props 傳遞變化給子組件,獲取子組件 Node,更多的情況下是為了避開大量重新渲染去修改一些Node的屬性(比如 scrollLeft)。

二、DOM 操作

jQuery 中提供了豐富的操作方法,但一個個操作 DOM 元素有的時候真的很煩人并且容易出錯。React 通過數據驅動的思想,通過改變 view 對應的數據,輕松實現 DOM 的增刪操作。

  1. class Demo extends React.Compoent { 
  2.     constructor(props) { 
  3.         super(props); 
  4.         this.state = { 
  5.             list: [1, 2, 3], 
  6.         }; 
  7.         this.addItemFromBottom = this.addItemFromBottom.bind(this); 
  8.         this.addItemFromTop = this.addItemFromTop.bind(this); 
  9.         this.deleteItem = this.deleteItem.bind(this); 
  10.     } 
  11.      
  12.     addItemFromBottom() { 
  13.         this.setState({ 
  14.             list: this.state.list.concat([4]), 
  15.         }); 
  16.     } 
  17.      
  18.     addItemFromTop() { 
  19.         this.setState({ 
  20.             list: [0].concat(this.state.list), 
  21.         }); 
  22.     } 
  23.      
  24.     deleteItem() { 
  25.         const newList = [...this.state.list]; 
  26.         newList.pop(); 
  27.         this.setState({ 
  28.             list: newList, 
  29.         }); 
  30.     } 
  31.      
  32.     render() { 
  33.         return ( 
  34.             <div> 
  35.                 {this.state.list.map((item) => <div>{item}</div>)} 
  36.                 <button onClick={this.addItemFromBottom}>尾部插入 Dom 元素</button> 
  37.                 <button onClick={this.addItemFromTop}>頭部插入 Dom 元素</button> 
  38.                 <button onClick={this.deleteItem}>刪除 Dom 元素</button> 
  39.             </div> 
  40.         ); 
  41.     } 

三、事件的監聽

React 通過根節點代理的方式,實現了一套很優雅的事件監聽方案,在組件 unmount 時也不需要自己去處理內存回收相關的問題,非常的方便。

  1. import React from 'react'
  2. class Demo extends React.Component { 
  3.     constructor(props) { 
  4.         super(props); 
  5.         this.handleClick = this.handleClick.bind(this); 
  6.     } 
  7.     handleClick() { 
  8.         alert('我是彈窗'); 
  9.     } 
  10.     render() { 
  11.         return ( 
  12.             <div onClick={this.handleClick}>點擊我彈出彈框</div> 
  13.         ); 
  14.     } 

這里有一個小細節就是 bind 的時機,bind 是為了保持相應函數的上下文,雖然也可以在 onClick 那里 bind,但這里選擇在 constructor 里 bind 是因為前者會在每次 render 的時候都進行一次 bind,返回一個新函數,是比較消耗性能的做法。

但 React 的事件監聽,畢竟只能監聽至 root component,而我們在很多時候要去監聽 window/document 上的事件,如果 resize、scroll,還有一些 React 處理不好的事件,比如 scroll,這些都需要我們自己來解決。事件監聽為了屏蔽差異性需要做很多的工作,這里像大家推薦一個第三方庫來完成這部分的工作,add-dom-event-listener,用法和原生的稍有區別,是因為這個庫并不旨在做 polyfill,但用法還是很簡單。

  1. var addEventListener = require('add-dom-event-listener'); 
  2. var handler = addEventListener(document.body, 'click'function(e){ 
  3.   console.log(e.target); // works for ie 
  4.   console.log(e.nativeEvent); // native dom event 
  5. }); 
  6. handler.remove(); // detach event listener 

另一個選擇是 bean,達到了 IE6+ 級別的兼容性。

四、事件的觸發

和事件監聽一樣,無論是 Dom 事件還是自定義事件,都有很優秀的第三方庫幫我們去處理,如果是 DOM 事件,推薦 bean,如果是自定義事件的話,推薦 PubSubJS。

五、document.ready

React 作為一個 view 層框架,通常情況下頁面只有一個用于渲染 React 頁面組件的根節點 div,因此 document.ready,只需把腳本放在這個 div 后面執行即可。而對于渲染完成后的回調,我們可以使用 React 提供的 componentDidMount 生命周期。

  1. import React from 'react'
  2. class Demo extends React.Component { 
  3.     constructor(props) { 
  4.         super(props); 
  5.     } 
  6.      
  7.     componentDidMount() { 
  8.         doSomethingAfterRender(); // 在組件渲染完成后執行一些操作,如遠程獲取數據,檢測 DOM 變化等。 
  9.     } 
  10.     render() { 
  11.         return ( 
  12.             <div>just a demo</div> 
  13.         ); 
  14.     } 

六、attr 方法

jQuery 使用 attr 方法,獲取 Dom 元素的屬性。在 React 中也可以配合 Ref 直接讀取 DOM 元素的屬性。

  1. import React from 'react'
  2. class Demo extends React.Component { 
  3.     constructor(props) { 
  4.         super(props); 
  5.     } 
  6.      
  7.     componentDidMount() { 
  8.         this.rootNode.scrollLeft = 10; // 渲染后將外層的滾動調至 10px 
  9.     } 
  10.     render() { 
  11.         return ( 
  12.             <div  
  13.                 ref={(c) => this.rootNode = c}  
  14.                 style={{ width: '100px', overflow: 'auto' }} 
  15.             >  
  16.                 <div style={{ width: '1000px' }}>just a demo</div> 
  17.             </div> 
  18.         ); 
  19.     } 

但是,在大部分的情況下,我們完全不需要做,因為 React 的單向數據流和數據驅動渲染,我們可以不通過 DOM,輕松拿到和修改大部分我們需要的 DOM 屬性。

  1. import React from 'react'
  2. class Demo extends React.Component { 
  3.     constructor(props) { 
  4.         super(props); 
  5.         this.state = { 
  6.             link: '//www.taobao.com'
  7.         }; 
  8.         this.getLink = this.getLink.bind(this); 
  9.         this.editLink = this.editLink.bind(this); 
  10.     } 
  11.      
  12.     getLink() { 
  13.         alert(this.state.link); 
  14.     } 
  15.      
  16.     editLink() { 
  17.         this.setState({ 
  18.             link: '//www.tmall.com'
  19.         }); 
  20.     } 
  21.      
  22.     render() { 
  23.         return ( 
  24.             <div> 
  25.                 <a href={this.state.link}>跳轉鏈接</a> 
  26.                 <button onClick={this.getLink}>獲取鏈接</button> 
  27.                 <button onClick={this.editLink}>修改鏈接</button> 
  28.             </div> 
  29.         ); 
  30.     } 
  31.      

七、addClass/removeClass/toggleClass

在 jQuery 的時代,我們通常靠獲取 Dom 元素后,再 addClass/removeClass 來改變外觀。在 React 中通過數據驅動和第三庫classnames 修改樣式從未如此輕松。

  1. .fn-show { 
  2.     display: block; 
  3. .fn-hide { 
  4.     display: none; 
  5. }
  1. import React from 'react'
  2. import classnames from 'classnames'
  3. class Demo extends React.Component { 
  4.     constructor(props) { 
  5.         super(props); 
  6.         this.state = { 
  7.             show: true
  8.         }; 
  9.         this.changeShow = this.changeShow.bind(this); 
  10.     } 
  11.      
  12.     changeShow() { 
  13.         this.setState({ 
  14.             show: !this.state.show,  
  15.         }); 
  16.     } 
  17.      
  18.     render() { 
  19.         return ( 
  20.             <div> 
  21.                 <a  
  22.                     href="//www.taobao.com"  
  23.                     className={classnames({ 
  24.                         'fn-show': this.state.show, 
  25.                         'fn-hide': !this.state.show, 
  26.                     })} 
  27.                 > 
  28.                     跳轉鏈接 
  29.                 </a> 
  30.                 <button onClick={this.changeShow}>改變現實狀態</button> 
  31.             </div> 
  32.         ); 
  33.     } 
  34.      

八、css

jQuery 的 css 方法用于設置 DOM 元素的 style 屬性,在 React 中,我們可以直接設置 DOM 的 style 屬性,如果想改變,和上面的 class 一樣,用數據去驅動。

  1. import React from 'react'
  2. class Demo extends React.Component { 
  3.     constructor() { 
  4.         super(props); 
  5.         this.state = { 
  6.             backgorund: 'white'
  7.         }; 
  8.         this.handleClick = this.handleClick.bind(this); 
  9.     } 
  10.      
  11.     handleClick() { 
  12.         this.setState({ 
  13.             background: 'black'
  14.         }); 
  15.     } 
  16.      
  17.     render() { 
  18.         return ( 
  19.             <div  
  20.                 style={{ 
  21.                     background: this.state.background, 
  22.                 }} 
  23.             > 
  24.                 just a demo 
  25.                 <button>change Background Color</button> 
  26.             </div> 
  27.         ); 
  28.     } 

九、數據存儲

比起 jQuery,React 反而是更擅長管理數據,我們沒有必要像 jQuery 時那樣將數據放進 Dom 元素的屬性里,而是利用 state 或者 內部變量(this.xxx) 來保存,在整個生命周期,我們都可以拿到這些數據進行比較和修改。

十、Ajax

Ajax 確實是在處理兼容性問題上一塊令人比較頭疼的地方,要兼容各種形式的 Xhr 不說,還有 jsonp 這個不屬于 ajax 的功能也要同時考慮,好在已經有了很好的第三方庫幫我們解決了這個問題,這里向大家推薦 natty-fetch,一個兼容 IE8 的fetch 庫,在 API 設計上向 fetch 標準靠近,而又保留了和 jQuery 類似的接口,熟悉 $.ajax 應該可以很快的上手。

十一、動畫

React 在動畫方面提供了一個插件 ReactCSSTransitionGroup,和它的低級版本 ReactTransitionGroup,注意這里的低級并不是退化版本,而是更加基礎的暴露更多 API 的版本。

這個插件的靈感來自于 Angular 的 ng-animate,在設計思路上也基本保持一致。通過指定 Transition 的類名,比如 example ,在元素進場和退場的時候分別加上對應的類名,以實現 CSS3 動畫。例如本例中,進場會添加 example-enter 和 example-enter-active到對應的元素 ,而在退場 example-leave 和 example-leave-active 類名。當然你也可以指定不同的進場退場類名。而對應入場,React 也區分了兩種類型,一種是 ReactCSSTransitionGroup ***次渲染時(appear),而另一種是 ReactCSSTransitionGroup 已經渲染完成后,有新的元素插入進來(enter),這兩種進場可以使用 prop 進行單獨配置,禁止或者修改超時時長。具體的例子,在上面給出的鏈接中有詳細的例子和說明,因此本文不再贅述。

但這個插件最多只提供了做動畫的方案,如果我想在動畫進行的過程中做一些其他事情呢?他就無能為力了,這時候就輪到 ReactTransitionGroup 出場了。ReactTransitionGroup 為他包裹的動畫元素提供了六種新的生命周期:componentWillAppear(callback), componentDidAppear(), componentWillEnter(callback), componentDidEnter(),componentWillLeave(callback), componentDidLeave()。這些 hook 可以幫助我們完成一些隨著動畫進行需要做的其他事。

但官方提供的插件有一個不足點,動畫只是在進場和出場時進行的,如果我的組件不是 mount/unmount,而只是隱藏和顯示怎么辦?這里推薦一個第三方庫:rc-animate,從 API 設計上他基本上是延續了 ReactCSSTransitionGroup 的思路,但是通過引入 showProp這一屬性,使他可以 handle 組件顯示隱藏這一情況下的出入場動畫(只要將組件關于 show/hide 的屬性傳給 showProp 即可),同時這個庫也提供自己的 hook,來實現 appear/enter/leave 時的回調。

如果你說我并不滿足只是進場和出場動畫,我要實現類似鼠標拖動時的實時動畫,我需要的是一個 js 動畫庫,這里向大家推薦一個第三方庫:react-motion , react-motion 一個很大的特點是,有別以往使用貝塞爾曲線來定義動畫節奏,引入了剛度和阻尼這些彈簧系數來定義動畫,按照作者的說法,與其糾結動畫時長和很難掌握的貝塞爾表示法,通過不斷調整剛度和阻尼來調試出最想要的彈性效果才是最合理的。Readme 里提供了一系列的很炫的動畫效果,比如這個 draggable list。Motion 通過指定 defaultStyle、style,傳回給子組件正在變化中的 style,從而實現 js 動畫。

  1. <Motion defaultStyle={{x: 0}} style={{x: spring(10)}}> 
  2.   {interpolatingStyle => <div style={interpolatingStyle} />} 
  3. </Motion> 

總結

本文的靈感來源于阮老師兩年前的文章,這篇的實戰意義更大于對未來技術的展望,希望能夠給各位正在使用 React 開發系統的同學們一點啟發。

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2021-02-26 15:10:00

前端React組件交互

2022-07-15 09:01:15

React對象編程

2021-04-09 18:01:03

前端ReactDOM

2021-05-23 15:46:23

React代碼前端

2023-01-01 23:42:22

React框架暗黑模式

2023-01-29 08:00:00

Instagram濾鏡圖片編輯

2023-12-01 09:18:27

AxiosAxios 庫

2013-05-14 10:54:57

jQuery網站開發

2017-07-04 19:02:17

ReacRedux 項目

2022-11-15 18:31:37

React

2017-06-20 12:48:55

React Nativ自定義模塊Note.js

2021-05-31 17:37:26

ViteReactesbuild

2010-11-18 08:46:27

ASP.NET MVC

2020-06-17 17:29:11

BashLinux

2016-08-24 21:24:27

MySQL存儲數據庫

2021-03-11 23:43:20

JavaScript數組開發

2021-03-18 10:45:02

JavaScript數組運算符

2021-04-19 16:31:33

Stratis加密Linux

2019-08-23 10:42:00

Linux復制文檔

2020-11-24 13:55:20

FedoraVirtualBoxLinux
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一区二区在线播放 | 亚洲精品欧美 | 日韩久久中文字幕 | 精品久久久久久一区二区 | 亚洲国产欧美在线 | 97精品超碰一区二区三区 | 日韩久久精品 | 成人网在线看 | 久久久久久久综合 | 日本在线综合 | 国产精品欧美大片 | 国产在线一区二区 | 中文字幕高清 | 九色网址 | 99热首页| 国产精品久久久久久久免费大片 | 91精品久久久久久久 | 国产精品一区二区三区四区 | 99精品国自产在线 | 懂色中文一区二区三区在线视频 | gav成人免费播放视频 | 日本一区二区高清视频 | 国产精品久久久久久一级毛片 | 久久日韩精品一区二区三区 | 国产午夜精品一区二区三区四区 | 黄色片免费看 | 亚洲日本成人 | www.日韩系列 | 国产一区三区视频 | 亚洲欧美久久 | 午夜影院网站 | 日韩在线视频观看 | 中文字幕在线一区二区三区 | aaaaa毛片| 国产精品99久久久久久动医院 | 国产高清91| 伊人网一区 | 特黄特色大片免费视频观看 | 91精品麻豆日日躁夜夜躁 | 久久日韩精品一区二区三区 | 激情婷婷 |