从Antd水印组件学到的

119 阅读1分钟

🐵背景

近日,发现了antd上的水印组件。然后好奇试了下,发现水印的css样式无法勾选取消,猜测是勾选取消后触发了重绘。然后看了下水印组件的源码,发现用了MutationObserver。

🐵MutationObserver

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。

Antd对MutationObserver做了封装,叫rc-mutate-observer 。

首先是 useMutateObserver 的 hook:

import canUseDom from "rc-util/es/Dom/canUseDom";
import * as React from 'react';
var defaultOptions = {
  subtree: true,
  childList: true,
  attributeFilter: ['style', 'class']
};
export default function useMutateObserver(nodeOrList, callback) {
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultOptions;
  React.useEffect(function () {
    if (!canUseDom() || !nodeOrList) {
      return;
    }
    var instance;
    var nodeList = Array.isArray(nodeOrList) ? nodeOrList : [nodeOrList];
    if ('MutationObserver' in window) {
      instance = new MutationObserver(callback);
      nodeList.forEach(function (element) {
        instance.observe(element, options);
      });
    }
    return function () {
      var _instance, _instance2;
      (_instance = instance) === null || _instance === void 0 ? void 0 : _instance.takeRecords();
      (_instance2 = instance) === null || _instance2 === void 0 ? void 0 : _instance2.disconnect();
    };
  }, [options, nodeOrList]);
}

然后是 MutateObserver 组件

import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import React from 'react';
import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
import { supportRef, useComposeRef } from "rc-util/es/ref";
import findDOMNode from "rc-util/es/Dom/findDOMNode";
import useEvent from "rc-util/es/hooks/useEvent";
import DomWrapper from "./wrapper";
import useMutateObserver from "./useMutateObserver";
var MutateObserver = function MutateObserver(props) {
  var children = props.children,
    options = props.options,
    _props$onMutate = props.onMutate,
    onMutate = _props$onMutate === void 0 ? function () {} : _props$onMutate;
  var callback = useEvent(onMutate);
  var wrapperRef = React.useRef(null);
  var elementRef = React.useRef(null);
  var canRef = /*#__PURE__*/React.isValidElement(children) && supportRef(children);
  var mergedRef = useComposeRef(elementRef, canRef ? children.ref : null);
  var _React$useState = React.useState(null),
    _React$useState2 = _slicedToArray(_React$useState, 2),
    target = _React$useState2[0],
    setTarget = _React$useState2[1];
  useMutateObserver(target, callback, options);

  // =========================== Effect ===========================
  // Bind target
  useLayoutEffect(function () {
    setTarget(findDOMNode(elementRef.current) || findDOMNode(wrapperRef.current));
  });

  // =========================== Render ===========================
  if (!children) {
    if (process.env.NODE_ENV !== 'production') {
      console.error('MutationObserver need children props');
    }
    return null;
  }
  return /*#__PURE__*/React.createElement(DomWrapper, {
    ref: wrapperRef
  }, canRef ? /*#__PURE__*/React.cloneElement(children, {
    ref: mergedRef
  }) : children);
};
export default MutateObserver;

useMutateObserver调用了 MutationObserver。

MutateObserver组件里用 ref 的来获取dom。