资讯专栏INFORMATION COLUMN

读zent源码库之Dialog组件实现

陈江龙 / 3187人阅读

摘要:但是,最后一步,事件怎么绑定呢这块没有深入研究了,不过我想,应该这样去实现也是没有问题的。的具体做法是,把方法放到了一个叫做的组件上去实现这个功能,然后再把内容放进这个组件。其他的逻辑比如显示隐藏之类,全部都放到组件自身上去实现。

1、Dialog组件提供什么功能,解决什么问题?

zent的Dialog组件,使用姿势是这样的(代码摘自zent官方文档:https://www.youzanyun.com/zan...)

import { Dialog, Button } from "zent";

class Example extends React.Component {
  state = { visible: false }

  triggerDialog = visible => {
    this.setState({ visible });
  };

  render() {
    return (
      
this.triggerDialog(false)} title="对话框" >

对话框内容

对话框其他内容

); } } ReactDOM.render(, mountNode);

可以通过visible属性控制弹层的显示与隐藏

可以随意的在Dialog组件里添加任意多的内容

可以在任意位置使用Dialog组件

2、如果我来实现会怎么做?

如果我来实现,其实很简单,用jQuery已经写了无数遍了,但是,想想当初用jQuery来写组件的时候,非常方便的可以在body下面插入一个div,并且绑定事件,或者,直接把弹层的div写到body标签下面。

但是,react,却是组件嵌套组件,所有组件都渲染在一个被称为root的div下面,这可怎么把一个节点挂载到body下面呢?

也简单,我直接用document.body.appendChild把组件直接插入到body后面,但是发现,document.body.appendChild的参数必须是标准的dom节点,而react里面,通过this.props.children取出来的数据,并不是标准的dom节点,这也好办,把这些节点转成标准的dom节点,然后插入到body下面不就ok了?我是这么想的。但是,最后一步,事件怎么绑定呢?这块没有深入研究了,不过我想,应该这样去实现也是没有问题的。

顺便说一下,曾经我还实现过一个React的弹层,但是必须放到最外层使用。。。哈哈,不说了,都是泪,侵入太强,无法做到在任意位置使用Dialog组件

3、zent的Dialog实现方式

zent实现方式,其实跟我上面说的基本思路是一致的,只是,用的方法不再是document.body.appendChild,而是用到了一个React提供的叫做ReactDOM.unstable_renderSubtreeIntoContainer(parentComponent, element, containerNode, callback)的方法,第一个参数是当前dialog所在的父组件,第二个参数是将要渲染的dialog内容,其实就是this.props.children,第三个参数是即将要挂载到body下面的一个div容器节点,callback就是成功之后的回调了。

从函数名可以看出,这个方法是不稳定的,但是,zent还是用了,不过效果很好,哈哈。

zent的具体做法是,把ReactDOM.unstable_renderSubtreeIntoContainer方法放到了一个叫做Portal的组件上去实现这个功能,然后再把dialog内容放进这个Portal组件。


    
      {this.props.children}
    

Portal组件本身的功能非常简单,仅仅只是负责把其子组件渲染到body下面的一个新创建的div下面去。其他的逻辑(比如显示、隐藏、mask之类),全部都放到dialog组件自身上去实现。当然,显示与隐藏的功能,还是由Portal来控制,隐藏的时候,Portal会把当前的子组件从body上面卸载掉。

4、极简实现

以下是一个极简的Portal实现,即把自己的子组件渲染到body上面去。

import React from "react";
import ReactDOM from "react-dom";

export default class Portal extends React.Component {
  renderChildren() {
    const container = document.createElement("div");
    document.body.appendChild(container);
    ReactDOM.unstable_renderSubtreeIntoContainer(this, React.Children.only(this.props.children), container);
  }
  componentDidMount() {
    this.renderChildren();
  }
  render() {
    return null;
  }
}

以下是,基于Portal的Dialog组件的极简实现:

import React from "react";
import Portal from "./portal";

export default class Dialog extends React.Component {
  render() {
    return 
      
{this.props.children}
} }

使用方式:

import React, { Component } from "react";
import ReactDOM, { render } from "react-dom";
import Dialog from "./dialog";

class App extends Component {
  onTextClick = () => {
    console.log("clicked")
  }

  render() {
    return (
      
this is dialog
); } } render(, document.getElementById("root"));

当然,真正要实现一个Dialog需要考虑的问题还有很多,比如控制隐藏与显示、定制动画,自定义样式,配置dialog的标题和其他属性等等,只是这些我们在jQuery时代都已经做过。

这里主要分析了Portal的实现,毕竟,在React里面,要把组件渲染到app根节点外面去并不容易。

(全文完)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95589.html

相关文章

  • 漫谈 React 组件库开发(一):多层嵌套弹层组件

    摘要:引言组件中有很多弹出式组件,常见的如,以及等。这样一种层次结构在实践中大大降低了各类弹层组件的实现和维护成本。但是的组件实现了一个大多数组件库都没有实现的功能弹层的嵌套处理。 引言 UI 组件中有很多弹出式组件,常见的如 Dialog,Tooltip 以及 Select 等。这些组件都有一个特点,它们的弹出层通常不是渲染在当前的 DOM 树中,而是直接插入在 body (或者其它类似的...

    warmcheng 评论0 收藏0
  • Zent - 源自有赞微商城的 React 组件

    摘要:是有赞端规范的实现版本,提供了一整套基础的组件以及常用的业务组件。目前我们有组件,其中包括以及等实用的业务组件。一套有赞设计师绘制的图标库。为了解决这些问题,提供了一套自己的时间选择组件,包括日期选择周选择组件月选择以及时间区间选择。 Zent ( ˈzent ) 是有赞 PC 端 Web UI 规范的 React 实现版本,提供了一整套基础的 UI 组件以及常用的__业务组件__。通...

    Corwien 评论0 收藏0
  • 源码系列1」还在恐惧源码?看完这篇就不怕了

    摘要:源码真的这么可怕吗从以上的事例中可以看出,其实并没有。对于源码的恐惧,让我们渐渐思维固化,自己告诉自己不要去碰源码,时间长了就遗忘了还有这样一条路可走。 一个小需求 事情的起因,是昨天有一个新的需求被提出。 需求是要实现,让我们自己定制的弹出层,具备按下 ESC 也能退出的功能。我把任务交给了同组的小伙伴S去实现。(这个项目用到了vue技术栈,以及饿了么的UI框架。) 我开完会回来,发...

    XGBCCC 评论0 收藏0
  • iview 和 Elemet UI 源码比较

    摘要:近期给自己立了个小,读源码,每周至少读篇源码下面来谈谈和这两个基于的框架源码的基本结构以及区别。例如四两个库组件整体引入和按需引入整体引入两个库一样的方法。 (近期给自己立了个小flag,读源码,每周至少读1篇源码) 下面来谈谈iview 和 Elemet UI 这两个基于Vue 的UI 框架源码的基本结构以及区别。 一、文件结构开发主要放在根文件夹下的src下: 1. ivew 文件...

    hizengzeng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<