国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

使用 Portal 優(yōu)雅實(shí)現(xiàn)“浮”在頁面上的組件

jk_v1 / 1061人閱讀

摘要:產(chǎn)品需求產(chǎn)品需求,實(shí)現(xiàn)一個(gè)選擇器組件,要求浮在頁面上方。本文討論的主要是,在有類似于組件一樣,浮在頁面的組件時(shí),如何設(shè)計(jì)組件樹方案一組件是組件的子組件。優(yōu)勢的顯示狀態(tài)屬于節(jié)點(diǎn)控制,狀態(tài)管理成本低。包括,事件冒泡。

產(chǎn)品需求

產(chǎn)品需求,實(shí)現(xiàn)一個(gè)選擇器 Selector 組件,要求浮在頁面上方。在網(wǎng)上隨便找了個(gè)圖,如下:

實(shí)現(xiàn)方案

實(shí)現(xiàn)這一的一個(gè) Selector 組件并不難,不是本文的討論內(nèi)容。
本文討論的主要是,在有類似于 Selector 組件一樣,“浮”在頁面的組件時(shí),如何設(shè)計(jì) React 組件樹?

方案一:Seletor 組件是 App 組件的子組件。

優(yōu)勢:Selector 屬于 App 的子節(jié)點(diǎn),子節(jié)點(diǎn)不受父節(jié)點(diǎn)的樣式屬性( position overflow )的干擾。

劣勢:Selector 的顯示狀態(tài)屬于 App 節(jié)點(diǎn),跨分支傳遞狀態(tài)成本太高。使用 Redux 或 Mobx 跨分支傳遞狀態(tài),依賴第三方組件,不利于復(fù)用;而手動傳遞,至少要 4 個(gè)步驟,如果 Button 節(jié)點(diǎn)更深,步驟會更多。并且這樣寫出的代碼,耦合性太強(qiáng),不利于維護(hù)。

方案二:Selector(fixed) 組件是 Button 組件的子組件。

優(yōu)勢:Selector 的顯示狀態(tài)屬于 Button 節(jié)點(diǎn)控制,狀態(tài)管理成本低。

劣勢:Selector 屬于 Button 的子節(jié)點(diǎn)。而當(dāng)父節(jié)點(diǎn) Button 有文字超出隱藏的需求時(shí)(overflow: hidden),子節(jié)點(diǎn) Selector 會被隱藏。

那么,有沒有兩全齊美的方案呢?有。

方案三:在 React 組件樹設(shè)計(jì)上,Selector 是 Button 的子組件。但是在 DOM 樹的角度 Selector 是 Body 的子節(jié)點(diǎn)。

在這個(gè)方案中,Button 和 Selector 還是屬于 React 組件樹中的父子節(jié)點(diǎn),享有父子組件狀態(tài)傳遞方便的優(yōu)勢。
但是,Button 和 Selector 不再屬于 DOM 樹中的父子節(jié)點(diǎn)!Selector 被渲染到了 Body 節(jié)點(diǎn)下面,屬于 Body 的子節(jié)點(diǎn)。這樣 Selector 組件再也不會受到 Button 組件的樣式干擾了。

在 React 中如何做到這一點(diǎn)呢?使用 React 16 的 Portals。
這個(gè)新屬性的介紹文章很短,我就翻譯下一吧。翻譯只是意譯,只為更好理解。

Portals

Portals 提供了一種超級棒的方法,可以將 react 子節(jié)點(diǎn)的 DOM 結(jié)構(gòu),渲染到 react 父節(jié)點(diǎn)之外的 DOM 中。

ReactDOM.createPortal(child, container)

第一個(gè)參數(shù) child 是任何可以被渲染的 ReactChild,比如 element, string 或者 fragment. 第二個(gè)參數(shù) container 是 一個(gè) DOM 元素。

使用方法

一般來說,在 react 中是父子節(jié)點(diǎn)的關(guān)系,那么在 DOM 中也是父子節(jié)點(diǎn)的關(guān)系。

render() {
  // 在 react 中 div 和 children 是父子的關(guān)系,在 DOM 中 div 和 children 也是父子的關(guān)系。
  return (
    
{this.props.children}
); }

然而,有時(shí)候打破了這種 react 父子節(jié)點(diǎn)和 DOM 父子節(jié)點(diǎn)的映射關(guān)系是非常有用的。使用 createPortal 可以將 react 的子節(jié)點(diǎn)插入到不同的 DOM 節(jié)點(diǎn)中。

render() {
  // React 并沒有創(chuàng)建一個(gè)新的 div,來包裹 children。它將 children 渲染到了 domNode 中。
  // domNode 可以是任意一個(gè)合法的 DOM 節(jié)點(diǎn),無論它在 DOM 節(jié)點(diǎn)中的哪個(gè)位置。
  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}

portal 一個(gè)典型的用法是,當(dāng)父組件有 overflow: hidden 或者 z-index 樣式時(shí),但是子組件需要“打破”父組件容器,顯示在父組件之外。比如 dialogs,hovercards,tooltips 組件。

[在 CodePen 上嘗試一下(https://codepen.io/gaearon/pe...

Portals 的事件冒泡

雖然 portal 可以在 DOM 樹中的任意位置,但是它的行為依舊和普通的 React child 一樣。比如上下文環(huán)境完全一樣,無論 child 是不是 portal; portal 也一直存在于在 React 樹上,無論它位于 DOM 樹中的什么位置。

包括,事件冒泡。portal 節(jié)點(diǎn)的事件會冒泡到它的 React 樹的祖先節(jié)點(diǎn)上,即使這些 React 樹上的祖先節(jié)點(diǎn)并不是 DOM 樹上的祖先節(jié)點(diǎn)。比如,有下面的 HTML 結(jié)構(gòu)。


  
    

在 DOM 樹中是 portal 和它的 React 父組件兄弟節(jié)點(diǎn),但是由于 React 的事件處理規(guī)則,讓 portal 的 React 父組件有能力捕獲 portal 的冒泡事件。

// These two containers are siblings in the DOM
const appRoot = document.getElementById("app-root");
const modalRoot = document.getElementById("modal-root");

class Modal extends React.Component {
  constructor(props) {
    super(props);
    this.el = document.createElement("div");
  }

  componentDidMount() {
    // The portal element is inserted in the DOM tree after
    // the Modal"s children are mounted, meaning that children
    // will be mounted on a detached DOM node. If a child
    // component requires to be attached to the DOM tree
    // immediately when mounted, for example to measure a
    // DOM node, or uses "autoFocus" in a descendant, add
    // state to Modal and only render the children when Modal
    // is inserted in the DOM tree.
    modalRoot.appendChild(this.el);
  }

  componentWillUnmount() {
    modalRoot.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(
      this.props.children,
      this.el,
    );
  }
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {clicks: 0};
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // This will fire when the button in Child is clicked,
    // updating Parent"s state, even though button
    // is not direct descendant in the DOM.
    this.setState(prevState => ({
      clicks: prevState.clicks + 1
    }));
  }

  render() {
    return (
      

Number of clicks: {this.state.clicks}

Open up the browser DevTools to observe that the button is not a child of the div with the onClick handler.

); } } function Child() { // The click event on this button will bubble up to parent, // because there is no "onClick" attribute defined return (
); } ReactDOM.render(, appRoot);

[在 CodePen 上嘗試一下(https://codepen.io/gaearon/pe...

父組件能夠捕獲 portal 的冒泡事件的設(shè)計(jì),允許開發(fā)者更加靈活的進(jìn)行抽象,而這些抽象不依賴于 portal 。例如,如果你渲染一個(gè) 組件,它的父組件能夠捕獲它的事件,無論使用的是不是 portal 實(shí)現(xiàn)的 (fixed 也能實(shí)現(xiàn))。

使用 portals 的實(shí)現(xiàn) Selector
// 數(shù)據(jù)和選中的元素的狀態(tài)由 Selector 自己控制
// 不要將 data、index 狀態(tài)暴露給其他組件
// 暴露給父組件,越多和父組件耦合的就越重
class Selector extends Component {
    componentDidMount(){
        fetch("xxx")
            .then(data => {
                this.setState({
                    data,
                })
            })
    }

    handleSelect = index => {
        this.setState({
            index
        })
    }
    
    render() {
        return (
            
        )
    }

}

// 控制 Modal 顯示狀態(tài)都封裝在 Button 中
class Button extends Component {
    handleClick = () => {
        this.setState( prevState => ({
            show: !prevState.show
        }))
    }
    
    render() {
        return (
            
我是按鈕 // 為了保存 Selector 的狀態(tài),不要 unmount Modal,用 display: none 實(shí)現(xiàn)隱藏。
) } } class App extends Component { render() { return (
) } }
討論:屬性暴露的越多越好,還是越少越好?

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/90241.html

相關(guān)文章

  • ELSE 技術(shù)周刊(2017.10.16期)

    摘要:前端中的計(jì)算機(jī)領(lǐng)域的通常認(rèn)為起源于。并對其主要內(nèi)容作了自己的解讀。搬到另一個(gè)地區(qū)會導(dǎo)致名氣降低。年度報(bào)告,年最受歡迎的編程語言年上最流行的種編程語言及前十最火熱的項(xiàng)目排行榜,分別由及登頂。技術(shù)周刊由小組出品,匯聚一周好文章,周刊原文。 showImg(https://segmentfault.com/img/bVWHC4?w=1000&h=710); 本期推薦 反擊爬蟲,前端工程師的腦...

    0xE7A38A 評論0 收藏0
  • 漫談 React 組件庫開發(fā)(一):多層嵌套彈層組件

    摘要:引言組件中有很多彈出式組件,常見的如,以及等。這樣一種層次結(jié)構(gòu)在實(shí)踐中大大降低了各類彈層組件的實(shí)現(xiàn)和維護(hù)成本。但是的組件實(shí)現(xiàn)了一個(gè)大多數(shù)組件庫都沒有實(shí)現(xiàn)的功能彈層的嵌套處理。 引言 UI 組件中有很多彈出式組件,常見的如 Dialog,Tooltip 以及 Select 等。這些組件都有一個(gè)特點(diǎn),它們的彈出層通常不是渲染在當(dāng)前的 DOM 樹中,而是直接插入在 body (或者其它類似的...

    warmcheng 評論0 收藏0
  • 當(dāng)大多數(shù)人對Vue理解到爐火純青的時(shí)候,是不是該思考一下怎么讓vue頁面騷氣起來

    寫在前面 當(dāng)大多數(shù)人Vue理解的爐火純青的時(shí)候,你應(yīng)該思考怎么讓vue頁面騷氣起來,下面就我個(gè)人在接觸Vue兩年的時(shí)間里,在實(shí)際工作中門戶網(wǎng)站在前端頁面交互應(yīng)用和技巧,炒幾道小菜給大家分享一哈,我把它封裝成一個(gè)項(xiàng)目vue-portal-webUI(github源碼),不敢說是UI,但也是各種常見常遇到的情景吧,看懂代碼需要一些vue、axios、es6、scss基礎(chǔ)、數(shù)據(jù)基本上是mock,功能和場...

    lingdududu 評論0 收藏0
  • 微前端改造初探

    摘要:我們繼續(xù)沿用了原來就有的,借此把融入整個(gè)微前端框架,而已經(jīng)改造的則不需要我們的開發(fā)團(tuán)隊(duì),分框架組和各個(gè)業(yè)務(wù)組。項(xiàng)目該項(xiàng)目是整個(gè)微前端項(xiàng)目的入口。本坑實(shí)踐它很大的理由也是用自己的方法初探微前端實(shí)踐方法的可行性。 在寫這篇文章的一個(gè)多月前,本坑還不知道微前端是什么,大概從字面上的含義是比較小的前端項(xiàng)目。 本坑開始實(shí)踐它,是由于工作要求。改造一個(gè)運(yùn)行多年,前端用jsp寫的服務(wù)平臺項(xiàng)目(以下簡...

    KunMinX 評論0 收藏0
  • 02.react進(jìn)階指南

    摘要:指定讀取當(dāng)前的。它為其后代元素觸發(fā)額外的檢查和警告。嚴(yán)格模式檢查僅在開發(fā)模式下運(yùn)行它們不會影響生產(chǎn)構(gòu)建。作用識別不安全的生命周期關(guān)于使用過時(shí)字符串的警告關(guān)于使用廢棄的方法的警告檢測意外的副作用檢測過時(shí)的為高階組件。 react 進(jìn)階 懶加載 React.lazy函數(shù)能讓你像渲染常規(guī)組件一樣處理動態(tài)引入(的組件)。Suspense加載指示器為組件做優(yōu)雅降級。fallback屬性接受任何在...

    zzbo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<