zl程序教程

您现在的位置是:首页 >  前端

当前栏目

[Web Component] Watermark

Web Component
2023-09-14 08:59:11 时间
/* eslint-disable no-param-reassign */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { throttle } from 'lodash'

const getCoverInfo = () => {
  const minWidth = 350
  const maxWidth = 500
  const width = '30vw'
  const minHeight = 300
  const height = '25vh'
  const maxHeight = 450

  const numCols = Math.ceil(window.innerWidth / minWidth)
  const numRows = Math.ceil(window.innerHeight / minHeight)

  return {
    maxHeight,
    maxWidth,
    minWidth,
    width,
    height,
    minHeight,
    numCols,
    numRows,
    total: numCols * numRows,
  } as const
}

const createTemplate = (
  userName: string | null = 'xxx@zscaler.com',
  message: string | null = 'watermark',
  time = new Intl.DateTimeFormat('en-US').format(new Date()),
) => {
  // Calculate the number of columns and rows needed to cover the screen
  const { total, numCols, numRows, width, height, minHeight, minWidth, maxHeight, maxWidth } = getCoverInfo()

  const template = document.createElement('template')
  template.innerHTML = `
  <style>
  .org__overlay--watermark {
    pointer-events: none;
    -webkit-text-stroke: 1.5px rgba(255, 255, 255, 0.5);
    -webkit-text-fill-color: rgba(0, 0, 0, 0.5);
    font-size: 1.5rem;
    width: ${width};
    min-width: ${minWidth}px;
    height: ${height};
    min-height: ${minHeight}px;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    transform: rotate(-45deg);
  }
  .org__overlay--container {
    position: fixed;
    top: 0px;
    left: 0px;
    opacity: 0.5;
    width: 120vw;
    height: 125vh;
    z-index: 2147483647;
    pointer-events: none;
    display: grid;
    grid-template-columns: repeat(${numCols}, minmax(${minWidth}px, ${width}));
    grid-template-rows: repeat(${numRows}, minmax(${minHeight}px, ${height}))
    overflow: hidden;
  }
  .zscaler__overlay--container > div {
    max-width: ${maxWidth}px;
    max-height: ${maxHeight}px;
  }
  </style>
  <div class="zscaler__overlay--container">
      ${Array.from({ length: total })
        .map(
          () => `<div class="zscaler__overlay--watermark">
            <div>
              <div data-name>${userName || ''}</div>
              <div>${time}</div>
              <div data-message>${message || ''}</div>
            </div>
        </div>`,
        )
        .join('')}
  </div>
  `
  return template
}

// Add the style element to the template element's content
export default class CbiWatermark extends HTMLElement {
  #maxTotal = 0

  constructor() {
    super()
    this.attachShadow({ mode: 'open' })
  }

  handleResize = throttle(() => {
    const { total } = getCoverInfo()
    if (total > this.#maxTotal) {
      this.render()
    }
    this.#maxTotal = Math.max(total, this.#maxTotal)
  }, 200)

  connectedCallback() {
    this.render()
    this.#maxTotal = getCoverInfo().total
    window.addEventListener('resize', this.handleResize)
  }

  disconnectedCallback() {
    window.removeEventListener('resize', this.handleResize)
  }

  changeOverlayStyles(styles: Record<PropertyKey, string>) {
    const elm = this.shadowRoot!.querySelector<HTMLDivElement>('.zscaler__overlay--container')
    if (!elm) {
      return
    }
    Object.keys(styles).forEach((styleKey) => {
      ;(elm.style as any)[styleKey] = styles[styleKey]
    })
  }

  changeWatermarkStyles(styles: Record<PropertyKey, string>) {
    const elms = this.shadowRoot!.querySelectorAll<HTMLDivElement>('.zscaler__overlay--watermark')
    if (!elms) {
      return
    }
    Object.keys(styles).forEach((styleKey) => {
      elms.forEach((elm) => {
        ;(elm.style as any)[styleKey] = styles[styleKey]
      })
    })
  }

  static get observedAttributes() {
    return ['data-name', 'data-message']
  }

  attributeChangedCallback(attribute: 'data-name' | 'data-message', oldValue: string | null, newValue: string | null) {
    if (this.hasAttribute(attribute) && oldValue !== null && newValue !== oldValue) {
      this.render()
    }
  } 

  render() {
    this.shadowRoot!.replaceChildren(
      createTemplate(this.getAttribute('data-name'), this.getAttribute('data-message')).content.cloneNode(true),
    )
  }
}

customElements.define('cbi-watermark', CbiWatermark)
export const cbiWatermark = document.createElement("cbi-watermark");

cbiWatermark.setAttribute("data-message", "Loemlw aweio aoawef co");
cbiWatermark.setAttribute("data-name", "zddhentian@abc.com");

document.body.prepend(cbiWatermark);