UNPKG

fsl-js-sdk

Version:
278 lines (246 loc) 6.86 kB
// FSLContainer.ts function copyText(text: string): Promise<string> { if (navigator.clipboard) { return navigator.clipboard .writeText(text) .then(() => { return text; }) .catch((error) => { return error; }); } if (Reflect.has(document, 'execCommand')) { return new Promise<string>((resolve, reject) => { try { const textArea = document.createElement('textarea'); textArea.value = text; // 在手机 Safari 浏览器中,点击复制按钮,整个页面会跳动一下 textArea.style.width = '0'; textArea.style.position = 'fixed'; textArea.style.left = '-999px'; textArea.style.top = '10px'; textArea.setAttribute('readonly', 'readonly'); document.body.appendChild(textArea); textArea.select(); document.execCommand('copy'); document.body.removeChild(textArea); resolve(text); } catch (error: any) { reject(error); } }); } return Promise.reject( `"navigator.clipboard""document.execCommand" 中存在API错误, 拷贝失败!`, ); } const formatEmail = (email: string | undefined) => { if (!email) { return ''; } const [name, company] = email.split('@'); let suffix = company; if (company && company.length > 11) { suffix = `***${company.slice(-11)}`; } if (name.length > 3) { return `${name.slice(0, 2)}***${name.slice(-1)}@${suffix}`; } return email; }; export class FSLContainer extends HTMLElement { static get observedAttributes() { return ['avatar', 'name']; } avatar: string = '/assets/avatar.png'; name: string = 'fsl@gmail.com'; isPC: boolean = true; noCompress: boolean = true; copy: ((text: string) => void) | null = null; close: ((id: string) => void) | null = null; shadow: ShadowRoot; constructor() { super(); document.body.style.margin = '0'; this.shadow = this.attachShadow({ mode: 'open' }); } connectedCallback() { this.updateState(); this.render(); window.addEventListener('resize', this.updateState.bind(this)); } disconnectedCallback() { window.removeEventListener('resize', this.updateState.bind(this)); } attributeChangedCallback( name: string, oldVal: string | ((text?: string) => void) | null, newVal: string | ((text?: string) => void) | null, ) { console.log('newVal', newVal); if (oldVal !== newVal) { if (typeof newVal === 'string') { this[name as 'avatar' | 'name'] = newVal; } else { this[name as 'copy' | 'close'] = newVal; } this.render(); } } updateState() { const clientWidth = document.documentElement.clientWidth; const clientHeight = document.documentElement.clientHeight; this.isPC = clientWidth > 1024; this.noCompress = clientHeight > 844; this.render(); } render() { this.shadow.innerHTML = ` <style> :host { display: block; height: 100vh; min-width: 390px; position: relative; } .appContainer { background: url(/assets/background.png) center center/cover no-repeat; height: 100vh; } .appContainer::after { position: absolute; content: ''; width: 100%; height: 100%; top: 0; left: 0; background: rgba(0, 0, 0, 0.5); z-index: 1; } .main { position: relative; z-index: 10; height: 100%; overflow: auto; } .centerContainer { display: flex; flex-direction: column; justify-content: center; min-height: 842px; position: relative; ${this.noCompress ? 'top: 50%; transform: translateY(-50%);' : ''} } .phoneFrame { width: 390px; height: 844px; ${this.isPC ? 'border: 1px solid #ddd;' : ''} border-radius: 30px; overflow: hidden; margin: 0 auto; background: white; } .header { display: flex; justify-content: space-between; align-items: center; padding: 32px 20px 0; color: #0E0F0C; background: #fff; } .header .left { display: flex; align-items: center; } .header .left img.avatar { width: 40px; height: 40px; border-radius: 50%; } .header .left span { margin-left: 10px; font-weight: 600; } .header .left img.copy { margin-left: 10px; width: 20px; cursor: pointer; } .header .right { display: flex; align-items: center; } .header .right img.close { width: 38px; cursor: pointer; } .page { flex: 1; padding: 20px 16px; overflow: auto; background: #fff; } .scroll-container { overflow: auto; } .container { position: relative; height: 100%; display: flex; flex-direction: column; } </style> <div class="appContainer"> <div class="main"> ${ this.isPC ? ` <div class="centerContainer"> <div class="phoneFrame"> ${this.renderContent()} </div> </div>` : ` <div class="phoneFrame" style="width: 100%; height: 100%; border-radius: 0;"> ${this.renderContent()} </div>` } </div> </div> `; this.shadow.querySelector('.copy')?.addEventListener('click', () => { copyText(this.name); this.copy?.(this.name); }); this.shadow.querySelector('.close')?.addEventListener('click', () => { const uid = new URLSearchParams(location.search).get('uid'); if (this.close) { this.close(uid!); return; } location.href = `https://id.fsl.com/application?uid=${uid}`; }); } renderContent() { const maskedName = formatEmail(this.name); return ` <div class="container"> <div class="header"> <div class="left"> <img class="avatar" src="${this.avatar}" alt="avatar" /> <span>${maskedName}</span> <img class="copy" src="/assets/copy.svg" alt="copy" /> </div> <div class="right"> <slot name="expand"></slot> <img class="close" src="/assets/close.svg" alt="close" /> </div> </div> <div class="page scroll-container"> <slot></slot> </div> </div> `; } }