Watermark高阶组件

Watermark作为高阶组件,包裹编辑器内容,即代码中的children,并传入用户信息做水印,其中的核心方法createWatermark(),传入当前的dom,方便讲水印作为背景印到div上。

  1. export default class Watermark extends React.PureComponent {
  2. static propTypes = {
  3. userInfo: propTypes.object,
  4. children: propTypes.any,
  5. getCurrentUserInfo: propTypes.func.isRequired,
  6. isPrivate: propTypes.bool,
  7. };
  8. componentDidMount() {
  9. if (this.props.userInfo) {
  10. this.init();
  11. } else {
  12. this.props.getCurrentUserInfo();
  13. }
  14. }
  15. componentDidUpdate(preProps) {
  16. if (this.props.userInfo !== preProps.userInfo || this.props.isPrivate !== preProps.isPrivate) {
  17. this.init();
  18. }
  19. }
  20. init = () => {
  21. const { userInfo, isPrivate } = this.props;
  22. if (userInfo) {
  23. const {
  24. userVO: {
  25. name,
  26. // email,
  27. id,
  28. },
  29. } = userInfo;
  30. // console.log(`${name}(${id})`);
  31. createWatermark(this.container.current, `${name}(${id})`, isPrivate);
  32. }
  33. };
  34. render() {
  35. const { children } = this.props;
  36. return <div ref={this.container}>{children}</div>;
  37. }
  38. container = React.createRef();
  39. }

添加水印核心方法

  1. import { getByteLength } from '@sjk/fe-components-react';
  2. import colorUtil from '@/utils/colorUtil';
  3. // 给元素加水印
  4. export default function(el, text, isPrivate) {
  5. const pageBackgroundColor = window.getComputedStyle(document.getElementsByTagName('body')[0]).backgroundColor;
  6. let backgroundColor = '#fff';
  7. let color = '#fefefe';
  8. const isDarkColorTheme = colorUtil.isDarkColor(pageBackgroundColor);
  9. if (isDarkColorTheme) {
  10. backgroundColor = pageBackgroundColor;
  11. color = colorUtil.getFontColorFromDarkStyle(pageBackgroundColor);
  12. }
  13. const textLength = getByteLength(text);
  14. let canvas = window.document.createElement('canvas');
  15. const fontSize = 14;
  16. // debugger;
  17. const width = (fontSize * textLength) / 2 + 30;
  18. const height = isPrivate ? 104 : fontSize;
  19. canvas.width = isPrivate ? (width > 260 ? width : 260) : width;
  20. canvas.height = height;
  21. let ctx = canvas.getContext('2d');
  22. ctx.font = `${fontSize}px sans-serif`;
  23. ctx.fillStyle = backgroundColor;
  24. ctx.fillRect(0, 0, width, height);
  25. // 隐藏个人信息的颜色
  26. ctx.fillStyle = color;
  27. ctx.fillText(text, 30, fontSize);
  28. if (isPrivate) {
  29. ctx.fillText(text, 60, fontSize * 2);
  30. ctx.fillText(text, 90, fontSize * 3);
  31. ctx.fillText(text, 120, fontSize * 4);
  32. ctx.rotate((35 * Math.PI) / 180);
  33. ctx.font = `32px sans-serif`;
  34. // 切换颜色显示警告信息
  35. ctx.fillStyle = 'rgba(242, 242, 242, 0.603921568627451)';
  36. if (isDarkColorTheme) {
  37. ctx.fillStyle = 'rgba(80, 80, 80, 0.603921568627451)';
  38. }
  39. ctx.fillText('私密文档', 10, 20);
  40. }
  41. const img = canvas.toDataURL('image/png');
  42. // debugger
  43. el.style.background = `url("${img}") left top`;
  44. el = null;
  45. canvas = null;
  46. ctx = null;
  47. }

辅助函数

  1. // 获取字符串字节长度,汉字两个字节,字母一个字节
  2. export default function getByteLength(str) {
  3. if (!str) return 0;
  4. if (typeof str != 'string') {
  5. str += '';
  6. }
  7. // eslint-disable-next-line
  8. return str.replace(/[^\x00-\xff]/g, '01').length;
  9. }

颜色深浅判断,从而显示字体颜色

  1. export default {
  2. regex: {
  3. rgbStyleAll: /(^rgb\((\d+),\s*(\d+),\s*(\d+)\)$)|(^rgba\((\d+),\s*(\d+),\s*(\d+)(,\s*\d+\.\d+)*\)$)/,
  4. hexStyle: /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/,
  5. rgbaStyle: /^rgba\((\d+),\s*(\d+),\s*(\d+)(,\s*\d+\.\d+)*\)$/,
  6. rgbStyle: /^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/,
  7. hexWidthStyle: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,
  8. },
  9. isRgbStyle(rgb) {
  10. return this.regex.rgbStyleAll.test(rgb);
  11. },
  12. isHexStyle(hex) {
  13. this.regex.hexStyle.test(hex);
  14. },
  15. isDarkColor(colorStyle) {
  16. if (this.isRgbStyle(colorStyle)) {
  17. if (colorStyle.indexOf('rgba') >= 0) {
  18. const rgba = this.regex.rgbaStyle.exec(colorStyle);
  19. const r = parseInt(rgba[1]);
  20. return r < 128;
  21. } else {
  22. const rgb = this.regex.rgbStyle.exec(colorStyle);
  23. const r = parseInt(rgb[1]);
  24. return r < 128;
  25. }
  26. } else if (this.isHexStyle(colorStyle)) {
  27. const rgb = this.regex.hexWidthStyle.exec(colorStyle);
  28. const r = parseInt(rgb[1], 16);
  29. return r < 128;
  30. } else {
  31. return false;
  32. }
  33. },
  34. /**
  35. * 获取背景色和字体颜色
  36. * @param colorStyle
  37. */
  38. getFontColorFromDarkStyle(colorStyle) {
  39. if (this.isRgbStyle(colorStyle)) {
  40. if (colorStyle.indexOf('rgba') >= 0) {
  41. const rgba = this.regex.rgbaStyle.exec(colorStyle);
  42. return `rgba(${rgba[1] - 1}, ${rgba[2] - 1}, ${rgba[2] - 1}, ${rgba[4]})`;
  43. } else {
  44. const rgb = this.regex.rgbStyle.exec(colorStyle);
  45. return `rgb(${rgb[1] - 1}, ${rgb[2] - 1}, ${rgb[2] - 1})`;
  46. }
  47. } else {
  48. const rgb = this.regex.hexWidthStyle.exec(colorStyle);
  49. const r = parseInt(rgb[1], 16);
  50. const g = parseInt(rgb[2], 16);
  51. const b = parseInt(rgb[3], 16);
  52. return `rgb(${r}, ${g}, ${b})`;
  53. }
  54. },
  55. };