import * as React from 'react'; import { Props, State } from './type'; import { genSpmLink } from '../utils/statistics' import { BaseComponent, handleComponentClickLog } from '../base-component' import ClipboardJS from 'clipboard'; import { callHandler } from 'nejsbridge/dist/bridge.lofter.es'; import { isLofter, isUpAppVersion, ios } from 'nw-detect'; import { openAppLofter } from 'nw-app-lofter' import { parse, stringifyUrl } from 'query-string-for-all'; import { showMessage } from '../common/toast/toast'; import { remToRealPx } from '../style/function.style'; import log from '../utils/lofter-log' export class HotArea extends React.Component { public static defaultProps = new Props(); public state = new State(); public className: string; public constructor(props: any) { super(props) this.className = 'hotArea_' + new Date().getTime(); } handleClick = (value: string) => { if (!value) return; // 模板活动跳转相关打点 handleComponentClickLog(this.props.instanceKey) setTimeout(() => { const { needLofterApp, lofterNewWebview, lofterNewWebviewTransparent, link, } = this.props; if (link.type === 4) { // jsbridge 处理,目前只支持无data的jsbridge let bridgeData; try { const bridgeDataStr = link.data; if (bridgeDataStr){ bridgeData = JSON.parse(bridgeDataStr); } } catch (error) { console.log('bridgeData parse failed', error); } console.log('callHandler', value, bridgeData); if (bridgeData) { callHandler(value, bridgeData); } else { callHandler(value); } return; } const host = window.location.host; const isLofterPage = host.indexOf('lofter') >= 0; // 如果是lofter页面,并且要求先打开app,并且当前还在lofter端外,先唤起app并打开当前页 if (isLofterPage && needLofterApp && !isLofter()) { openAppLofter({ path: 'webview', query: { url: window.location.href } }) } else if (lofterNewWebview && isLofter()) { // // ios端6.21.4以前的市集webview可能处理不了此类scheme if (ios() && !isUpAppVersion('6.21.4')) { window.location.href = value return; } window.location.href = `lofter://webview?url=${encodeURIComponent(value)}&inside=true${lofterNewWebviewTransparent ? '&opacity=true' : ''}` } else { // 如果是剪切板口令热区,并且当前已在lofter内,复制口令后,提示用户重启app,触发剪切板识别 if (value.startsWith('https://uls.lofter.com') && isLofter()) { showMessage('口令已复制,请重新打开LOFTER APP') return; } window.location.href = value } }, 300) } watch = () => { let el = document.getElementById('viewport-left') let vwEl = document.getElementById('viewport') let left = vwEl!.getBoundingClientRect().left let top = vwEl!.getBoundingClientRect().top this.setState({ viewportLeft: left, viewportTop: top }) const config = { attributes: true, childList: true} const callback = (mutationList: any) => { mutationList.forEach((mutation: any) => { switch(mutation.type) { case 'childList': this.setState({ viewportLeft: vwEl!.getBoundingClientRect().left, viewportTop: vwEl!.getBoundingClientRect().top }) break; } }) } let observer = new MutationObserver(callback) observer.observe(el!, config) } componentDidMount() { if (this.props.isEdit) { this.watch() } const { link } = this.props; if (link && link.type === 3) { const {type, value} = link; if (type === 3) { const clipboard = new ClipboardJS('.' + this.className, { text: () => value }) clipboard.on('success', function(e: any) { console.log('copy succeed', e.text) e.clearSelection(); }); clipboard.on('error', function(e: any) { console.log('copy failed', e.text) }); } } } public render() { const backgroundImage = this.props.backgroundImage; let href: string = ''; const { link, isEdit, style, fixed } = this.props; const { viewportLeft, viewportTop } = this.state; if(link){ const linkType = this.props.link.type; const linkValue = this.props.link.value; switch (linkType) { case 0: // 普通链接 href = linkValue; const urlData = parse(location.search); // 如果当前cms页还有adTrace信息,那么跳转市集卡牌目标页时也增加adtrace信息 if (urlData.adTrace && linkValue.indexOf('/market') >= 0) { href = stringifyUrl({ url: linkValue, query: { adTrace: urlData.adTrace } }) console.log('Set current adtrace to next card page.') } break; case 1: // 商品详情页 // @ts-ignore href = genSpmLink({url: `//www.lofter.com/market/fe/html/product.html?productId=${linkValue}&njb_navigator=false`, name: 'spmCmspageProduct'}); break; case 2: // 市集优惠券 // @ts-ignore href = genSpmLink({url: `//www.lofter.com/market/fe/html/couponProducts.html?couponId=${linkValue}`, name: 'spmCmspageCoupon'}); break; case 3: // 剪切板口令 href = `https://uls.lofter.com?incantation=${linkValue}`; break; case 4: // jsbridge href = linkValue; break; default: break; } }else{ href = 'javascript:void(0);' } let left: string | number = 0; if (fixed && isEdit && typeof style.left === 'string') { left = viewportLeft/37.5 + parseFloat(style.left.slice(0, -3)) + 'rem' } else { left = style.left || 0; } let top: string | number = 0; if (fixed && isEdit && typeof style.top === 'string') { top = viewportTop/37.5 + parseFloat(style.top.slice(0, -3)) + 'rem' } else { if (fixed) { const screenHeight = window.innerHeight; const topNumber = typeof style.top === 'string' ? remToRealPx(parseFloat(style.top.slice(0, -3))) : (style.top || 0); const areaHeight = typeof style.height === 'string' ? remToRealPx(parseFloat(style.height.slice(0, -3))) : (style.height || 0); if (topNumber + areaHeight > screenHeight) { console.warn('当前fixed定位热区展示位置超出屏幕,已修正'); top = screenHeight - areaHeight + 'px'; } else { top = style.top || 0; } } else { top = style.top || 0; } } return (
{backgroundImage && }
) } }