成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Ant design的Notification源碼分析

SimpleTriangle / 2802人閱讀

摘要:通過(guò)將實(shí)例傳入回調(diào)函數(shù)。添加再回過(guò)頭來(lái)看回調(diào)函數(shù)的內(nèi)容。其中的作用是一次調(diào)用傳入的各函數(shù),其中方法是移除中相應(yīng)的節(jié)點(diǎn),是傳入的關(guān)閉標(biāo)簽后的回調(diào)函數(shù)。

notification簡(jiǎn)介

notification就是通知提醒框,在系統(tǒng)四個(gè)角顯示通知提醒信息。經(jīng)常用于以下情況:

較為復(fù)雜的通知內(nèi)容。

帶有交互的通知,給出用戶下一步的行動(dòng)點(diǎn)。

系統(tǒng)主動(dòng)推送。

先來(lái)看一下notification的API。

API

notification.success(config)

notification.error(config)

notification.info(config)

notification.warning(config)

notification.warn(config)

notification.close(key: String)

notification.destroy()

可以看到,notification的API在antd的組件中可以說(shuō)是非常另類的,看著是不是有點(diǎn)眼熟,很像經(jīng)常使用的Console的API,調(diào)用起來(lái)十分簡(jiǎn)單。

console.log()

console.error()

console.info()

console.warn()

config的配置也比較簡(jiǎn)單,主要是標(biāo)題,內(nèi)容,關(guān)閉時(shí)的延時(shí)和回調(diào)等。詳見ANTD的官網(wǎng)。

notification的結(jié)構(gòu)

在分析代碼之前,我們先來(lái)看下notification的結(jié)構(gòu),通知組件主要分為三層,由高到低是

NotificationApi => Notification => n*Notice。

NotificationApi

NotificationApi是一個(gè)封裝的接口,提供統(tǒng)一調(diào)用的API,如info(),warn()等。

Notification

Notification是一個(gè)Notice容器,就是用來(lái)容納Notice列表的父組件,提供了添加,刪除等操作Notice的方法。

Notice

Notice就是我們所看到的通知標(biāo)簽了。

源碼分析

先從入口index.js入手,因?yàn)檫@是一個(gè)notification的API封裝,不是一個(gè)組件,所以沒有render方法。

//.......省略部分代碼........

const api: any = {
  open: notice,//入口
  close(key: string) {
    Object.keys(notificationInstance)
      .forEach(cacheKey => notificationInstance[cacheKey].removeNotice(key));
  },
  config: setNotificationConfig,
  destroy() {
    Object.keys(notificationInstance).forEach(cacheKey => {
      notificationInstance[cacheKey].destroy();
      delete notificationInstance[cacheKey];
    });
  },
};

//.......省略部分代碼........

["success", "info", "warning", "error"].forEach((type) => {
  api[type] = (args: ArgsProps) => api.open({
    ...args,
    type,
  });
});

api.warn = api.warning;
export interface NotificationApi {
  success(args: ArgsProps): void;
  error(args: ArgsProps): void;
  info(args: ArgsProps): void;
  warn(args: ArgsProps): void;
  warning(args: ArgsProps): void;
  open(args: ArgsProps): void;
  close(key: string): void;
  config(options: ConfigProps): void;
  destroy(): void;
}
export default api as NotificationApi;

接口比較清晰,可以看出API提供的不同的方法實(shí)際是通過(guò)一個(gè)類似工廠方法的open函數(shù)實(shí)現(xiàn)的,open函數(shù)的具體實(shí)現(xiàn)是notice,那么看下這個(gè)notice函數(shù)。

function notice(args: ArgsProps) {
  const outerPrefixCls = args.prefixCls || "ant-notification";
  const prefixCls = `${outerPrefixCls}-notice`;
  const duration = args.duration === undefined ? defaultDuration : args.duration;

//生成icon組件
  let iconNode: React.ReactNode = null;
  if (args.icon) {
    iconNode = (
      
        {args.icon}
      
    );
  } else if (args.type) {
    const iconType = typeToIcon[args.type];
    iconNode = (
      
    );
  }

  const autoMarginTag = (!args.description && iconNode)
    ? 
    : null;

  getNotificationInstance(outerPrefixCls, args.placement || defaultPlacement, (notification: any) => {
    notification.notice({
      content: (
        
{iconNode}
{autoMarginTag} {args.message}
{args.description}
{args.btn ? {args.btn} : null}
), duration, closable: true, onClose: args.onClose, key: args.key, style: args.style || {}, className: args.className, }); }); }

這段代碼主要的部分就是調(diào)用了getNotificationInstance函數(shù),看名字應(yīng)該是得到Notification的實(shí)例,命名方式是典型的單例模式,作為列表的容器組件,使用單例模式不僅節(jié)省了內(nèi)存空間,而且單例延遲執(zhí)行的特性也保證了在沒有通知的情況下不會(huì)生成notification組件,提升了頁(yè)面的性能。

function getNotificationInstance(prefixCls: string, placement: NotificationPlacement, callback: (n: any) => void)

查看定義,第一個(gè)參數(shù)是css前綴,第二個(gè)參數(shù)是notification的彈出位置,分為topLeft topRight bottomLeft bottomRight,第三個(gè)參數(shù)是一個(gè)回調(diào),回調(diào)的參數(shù)是notification實(shí)例,可以看到,在回調(diào)中調(diào)用了notification的notice方法,notice方法的參數(shù)是一個(gè)對(duì)象,content看名字應(yīng)該是通知標(biāo)簽的內(nèi)容,其他的參數(shù)也是調(diào)用notification中傳入的config參數(shù)。
接下來(lái)看下getNotificationInstance的實(shí)現(xiàn)

function getNotificationInstance(prefixCls: string, placement: NotificationPlacement, callback: (n: any) => void) {
  const cacheKey = `${prefixCls}-${placement}`;
  if (notificationInstance[cacheKey]) {
    callback(notificationInstance[cacheKey]);
    return;
  }

  //---實(shí)例化Notification組件
  (Notification as any).newInstance({
    prefixCls,
    className: `${prefixCls}-${placement}`,
    style: getPlacementStyle(placement),
    getContainer: defaultGetContainer,
  }, (notification: any) => {
    notificationInstance[cacheKey] = notification;
    callback(notification);
  });
}

代碼很簡(jiǎn)短,可以看到確實(shí)是使用了單例模式,因?yàn)榇嬖?個(gè)彈出位置,所以將每個(gè)位置的notification實(shí)例存放在notificationInstance[cacheKey]數(shù)組里,cacheKey是css前綴和彈出位置的組合,用以區(qū)分每個(gè)實(shí)例。接下來(lái)進(jìn)入newInstance方法來(lái)看下是怎么使用單例模式生成notification實(shí)例的。

實(shí)例化Notification
Notification.newInstance = function newNotificationInstance(properties, callback) {
  const { getContainer, ...props } = properties || {};
  const div = document.createElement("div");
  if (getContainer) {
    const root = getContainer();
    root.appendChild(div);
  } else {
    document.body.appendChild(div);
  }
  let called = false;
  function ref(notification) {
    if (called) {
      return;
    }
    called = true;
    callback({
      notice(noticeProps) {
        notification.add(noticeProps);
      },
      removeNotice(key) {
        notification.remove(key);
      },
      component: notification,
      destroy() {
        ReactDOM.unmountComponentAtNode(div);
        div.parentNode.removeChild(div);
      },
    });
  }
  ReactDOM.render(, div);
};

主要完成了兩件事

通過(guò)ReactDOM.render將Notification組件渲染到頁(yè)面上,可以選擇渲染到傳入的container或者body中。

通過(guò)ref將notification實(shí)例傳入callback回調(diào)函數(shù)。

可以看到傳入callback的參數(shù)對(duì)notification又做了一層封裝,目的是為了封裝destroy函數(shù),其中

+ notice():添加一個(gè)notice組件到notification
+ removeNotice():刪除指定notice組件。
+ destroy():銷毀notification組件。
添加Notice

再回過(guò)頭來(lái)看回調(diào)函數(shù)的內(nèi)容。

 getNotificationInstance(outerPrefixCls, args.placement || defaultPlacement, (notification: any) => {
    notification.notice({
      content: (
        
{iconNode}
{autoMarginTag} {args.message}
{args.description}
{args.btn ? {args.btn} : null}
), duration, closable: true, onClose: args.onClose, key: args.key, style: args.style || {}, className: args.className, }); });

調(diào)用了notification的notice方法,由前面的代碼可知notice其實(shí)是調(diào)用了Notification組件的add方法,記下來(lái)看下add方法是怎樣將標(biāo)簽添加進(jìn)Notification的。

//省略部分代碼

 state = {
  notices: [],
};

//省略部分代碼

  add = (notice) => {
  const key = notice.key = notice.key || getUuid();
  this.setState(previousState => {
    const notices = previousState.notices;
    if (!notices.filter(v => v.key === key).length) {
      return {
        notices: notices.concat(notice),
      };
    }
  });
}

Notification將要顯示的通知列表存在state的notices中,同通過(guò)add函數(shù)動(dòng)態(tài)添加,key是該notice的唯一標(biāo)識(shí),通過(guò)filter將已存在的標(biāo)簽過(guò)濾掉??梢韵胍?,Notification就是將state中的notices通過(guò)map渲染出要顯示的標(biāo)簽列表,直接進(jìn)入Notification組件的render方法。

  render() {
  const props = this.props;
  const noticeNodes = this.state.notices.map((notice) => {
    const onClose = createChainedFunction(this.remove.bind(this, notice.key), notice.onClose);
    return (
      {notice.content}
    );
  });
  const className = {
    [props.prefixCls]: 1,
    [props.className]: !!props.className,
  };
  return (
    
{noticeNodes}
); } }

根據(jù)state的notices生成Notice組件列表noticeNodes,然后將noticeNodes插入到一個(gè)Animate的動(dòng)畫組件中。其中createChainedFunction的作用是一次調(diào)用傳入的各函數(shù),其中remove方法是移除state中相應(yīng)的節(jié)點(diǎn),onClose是傳入的關(guān)閉標(biāo)簽后的回調(diào)函數(shù)。
看到這里Notification的結(jié)構(gòu)已經(jīng)比較清晰了,最后再來(lái)看下Notice組件的實(shí)現(xiàn)。

export default class Notice extends Component {
  static propTypes = {
    duration: PropTypes.number,
    onClose: PropTypes.func,
    children: PropTypes.any,
  };

  static defaultProps = {
    onEnd() {
    },
    onClose() {
    },
    duration: 1.5,
    style: {
      right: "50%",
    },
  };

  componentDidMount() {
    this.startCloseTimer();
  }

  componentWillUnmount() {
    this.clearCloseTimer();
  }

  close = () => {
    this.clearCloseTimer();
    this.props.onClose();
  }

  startCloseTimer = () => {
    if (this.props.duration) {
      this.closeTimer = setTimeout(() => {
        this.close();
      }, this.props.duration * 1000);
    }
  }

  clearCloseTimer = () => {
    if (this.closeTimer) {
      clearTimeout(this.closeTimer);
      this.closeTimer = null;
    }
  }

  render() {
    const props = this.props;
    const componentClass = `${props.prefixCls}-notice`;
    const className = {
      [`${componentClass}`]: 1,
      [`${componentClass}-closable`]: props.closable,
      [props.className]: !!props.className,
    };
    return (
      
{props.children}
{props.closable ? : null }
); } }

這個(gè)組件比較簡(jiǎn)單,主要是實(shí)現(xiàn)標(biāo)簽顯示一段時(shí)間后自動(dòng)消失,通過(guò)setTimeout設(shè)置一段時(shí)間后調(diào)用close方法,也就是上一段代碼中實(shí)現(xiàn)的移除state中的相應(yīng)節(jié)點(diǎn)以及調(diào)用相應(yīng)的回調(diào)函數(shù)。

總結(jié)

看到這里antd的通知組件的實(shí)現(xiàn)已經(jīng)比較清晰了,代碼并沒有特別復(fù)雜的部分,但是這種使用單例模式動(dòng)態(tài)添加組件的設(shè)計(jì)十分值得借鑒,在實(shí)現(xiàn)類似通知組件或者需要?jiǎng)討B(tài)添加的組件的時(shí)候可以參考這種設(shè)計(jì)模式,antd的Message組件也采用了同樣的設(shè)計(jì)。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/93885.html

相關(guān)文章

  • Ant Design源碼分析(三):Wave組件

    摘要:返回刪除的節(jié)點(diǎn)。組件運(yùn)行邏輯此時(shí),組件的代碼與邏輯已經(jīng)全部分析完了,整個(gè)組件的運(yùn)行邏輯可以通過(guò)下方這張圖來(lái)概括本篇完 Wave組件效果預(yù)覽 ???????在上一篇文章Button組件的源碼分析中遇到了一個(gè)Wave組件, Wave組件在Ant design中提供了通用的表單控件點(diǎn)擊效果,在自己閱讀源碼之前,也并沒有過(guò)更多留心過(guò)在這些表單控件的動(dòng)畫效果是如何實(shí)現(xiàn)的,甚至可能有時(shí)都沒注意到這...

    luzhuqun 評(píng)論0 收藏0
  • Vue開發(fā)總結(jié) 及 一些最佳實(shí)踐 (已更新)

    摘要:基本開發(fā)環(huán)境創(chuàng)建的項(xiàng)目,作為代碼編寫工具插件推薦插件配置文章目錄項(xiàng)目目錄結(jié)構(gòu)介紹框架選擇處理請(qǐng)求二次封裝項(xiàng)目目錄結(jié)構(gòu)簡(jiǎn)介業(yè)務(wù)相關(guān)靜態(tài)文件全局組件基礎(chǔ)樣式布局樣式及工具引入請(qǐng)求配置路由全局狀態(tài)管理工具文件入口文件主要配置文件頁(yè)面檢查配置測(cè)試 基本開發(fā)環(huán)境 vue-cli3 創(chuàng)建的項(xiàng)目,vscode 作為代碼編寫工具vscode插件推薦:vscode 插件配置 文章目錄 項(xiàng)目目錄結(jié)構(gòu)介紹...

    NotFound 評(píng)論0 收藏0
  • 用React實(shí)現(xiàn)一個(gè)最最最簡(jiǎn)單TodoList

    摘要:初學(xué),擼一個(gè)熟悉熟悉基本語(yǔ)法,只有最簡(jiǎn)單最簡(jiǎn)單的功能。引入這個(gè)之后,我們可以直接使用一些簡(jiǎn)單的組件,比如等,我們可以更加注重業(yè)務(wù)邏輯的實(shí)現(xiàn)。 初學(xué)React,擼一個(gè)TodoList熟悉熟悉基本語(yǔ)法,只有最簡(jiǎn)單最簡(jiǎn)單的功能。 showImg(https://segmentfault.com/img/remote/1460000010376536); 如上圖所示,是一個(gè)最簡(jiǎn)單的TodoLi...

    Forest10 評(píng)論0 收藏0
  • Ant-Design-組件-——-Form表單(一)

    摘要:擅長(zhǎng)網(wǎng)站建設(shè)微信公眾號(hào)開發(fā)微信小程序開發(fā)小游戲制作企業(yè)微信制作建設(shè),專注于前端框架服務(wù)端渲染技術(shù)交互設(shè)計(jì)圖像繪制數(shù)據(jù)分析等研究。 Ant Design of React @3.10.9 拉取項(xiàng)目 luwei.web.study-ant-design-pro, 切換至 query 分支,可看到 Form 表單實(shí)現(xiàn)效果 實(shí)現(xiàn)一個(gè)查詢表單 showImg(https://segmentfau...

    trilever 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

SimpleTriangle

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<