const { createApp } = Vue; const treeNode = { name: 'tree-node', props: { node: { type: Object, default: [] } }, template: `
{{ node.pageName }}
{{ node.pageName }}
`, data() { return { isExpanded: true } }, inject: ['getSelectId'], computed: { selectId () { return this.getSelectId() }, }, methods: { toggle(node) { this.isExpanded = !this.isExpanded this.$emit('node-click', node) }, selectPage(node){ this.$emit('node-click', node) } } } const app = createApp({ provide () { return { getSelectId: () => this.pageUuid } }, data() { return { message: 'Hello Vue!', treeData: [], appVersion: '', pageUuid: '', pageType:'', pageName: '', previewSizeOptions: [], previewSizeW: 1920, previewSizeH: 1080, previewSize: '1920x1080', cleanup: null, currentIndex: 0, pageList: [], isPreview: false, isShowTip: false, appName: projectName, resizeObserver: null, setTimeout1: null, isHtml: true, url: '', childUrl: '', iframeMessage: null, childIframe: null, // 导航页内嵌子页面添加键盘事件 } }, watch: { pageType:{ handler(value){ this.$nextTick(()=>{ if (!this.appName) return this.changePageType(value) let iframeDoc = null let iframeAppDoc = null const iframeKeydownHandler=(e) => { this.keyboardEvents(e) } if (value === 'app') { if (iframeDoc) { iframeDoc.removeEventListener('keydown', iframeKeydownHandler); } const iframeId = this.isHtml ? '#iframeApp' : '#vueIframeApp' const iframeApp = document.querySelector(iframeId); // 聚焦到iframe时,键盘左右切换不生效 // iframeApp.addEventListener('load', () => { // iframeAppDoc = iframeApp.contentDocument || iframeApp.contentWindow.document; // iframeAppDoc.addEventListener('keydown', iframeKeydownHandler); // if (!this.isHtml) { // const tag = iframeAppDoc.querySelector('.ai-tag') // tag && (tag.style && (tag.style.visibility = 'hidden') || tag.style.setAtrrbute('visibility','hidden')) // } // }); if (this.resizeObserver) { this.resizeObserver.disconnect() this.resizeObserver = null } } else { // 监听web类型iframe父元素大小变化 const element = document.querySelector('.preview-web') this.resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const { width, height } = entry.contentRect if (this.previewSize == 'auto') { this.previewSizeW = parseInt(width) this.previewSizeH = parseInt(height) } this.changeResolution() } }) this.resizeObserver.observe(element) if (iframeAppDoc) { iframeAppDoc.removeEventListener('keydown', iframeKeydownHandler); } // 聚焦到iframe时,键盘左右切换不生效 const iframeWeb = this.isHtml ? document.getElementById('iframe') : document.getElementById('vueIframeWeb') iframeWeb.addEventListener('load', () => { iframeDoc = iframeWeb.contentDocument || iframeWeb.contentWindow.document; iframeDoc.addEventListener('keydown', iframeKeydownHandler); }); } }) } }, isHtml(value){ this.$nextTick(()=>{ if (!this.appName) return let iframeDoc = null let iframeAppDoc = null const iframeKeydownHandler=(e) => { this.keyboardEvents(e) } if (value === 'app') { if (iframeDoc) { iframeDoc.removeEventListener('keydown', iframeKeydownHandler); } const iframeId = this.isHtml ? '#iframeApp' : '#vueIframeApp' const iframeApp = document.querySelector(iframeId); // 聚焦到iframe时,键盘左右切换不生效 // iframeApp.addEventListener('load', () => { // iframeAppDoc = iframeApp.contentDocument || iframeApp.contentWindow.document; // iframeAppDoc.addEventListener('keydown', iframeKeydownHandler); // if (!this.isHtml) { // this.$nextTick(() => { // const tag = iframeAppDoc.querySelector('.ai-tag') // tag && (tag.style && (tag.style.visibility = 'hidden') || tag.style.setAtrrbute('visibility','hidden')) // }) // } // }); if (this.resizeObserver) { this.resizeObserver.disconnect() this.resizeObserver = null } } else { // 监听web类型iframe父元素大小变化 const element = document.querySelector('.preview-web') this.resizeObserver = new ResizeObserver(entries => { for (let entry of entries) { const { width, height } = entry.contentRect if (this.previewSize == 'auto') { this.previewSizeW = parseInt(width) this.previewSizeH = parseInt(height) } this.changeResolution() } }) this.resizeObserver.observe(element) if (iframeAppDoc) { iframeAppDoc.removeEventListener('keydown', iframeKeydownHandler); } // 聚焦到iframe时,键盘左右切换不生效 const iframeWeb = this.isHtml ? document.getElementById('iframe') : document.getElementById('vueIframeWeb') iframeWeb.addEventListener('load', () => { iframeDoc = iframeWeb.contentDocument || iframeWeb.contentWindow.document; iframeDoc.addEventListener('keydown', iframeKeydownHandler); }); } }) }, previewSize(val) { const option = this.previewSizeOptions.find(item => item.value === val) this.previewSizeW = option.w this.previewSizeH= option.h this.changeResolution() }, previewSizeW(val) { if (!this.appName) return this.changeResolution() }, previewSizeH(val) { if (!this.appName) return this.changeResolution() } }, mounted() { document.querySelector('#app').style.display = 'block' this.getPageList() this.communicationFun() }, methods: { communicationFun () { this.iframeMessage = useEventListener(window, 'message', async (event) => { // 处理消息 判断data值是页面id时处理切换页面 if (event.source != window) { const currentPage = this.pageList.find(item => item.pageUuid == event.data) this.pageUuid = currentPage.pageUuid this.pageName = currentPage.pageName this.pageType = currentPage.pageScene this.isHtml = currentPage.codeType === 'html' this.getAppPageVersion(currentPage) this.currentIndex = this.pageList.findIndex(item=>item.pageUuid == this.pageUuid) || 0; } }, true) }, // 修改页面类型 changePageType(value) { const autoSize = { label: "自定义", value: "auto", w: 375, h: 812 } if (value === 'app') { this.previewSizeOptions = [autoSize, ...resolutionInfo.app] this.previewSizeW = 393 this.previewSizeH= 852 this.previewSize = '393x852-16' } else { let iframe = document.querySelector('.preview-web') autoSize.w = parseInt(iframe.clientWidth) autoSize.h = parseInt(iframe.clientHeight) this.previewSizeOptions = [autoSize, ...resolutionInfo.web] this.previewSizeW = autoSize.w this.previewSizeH= autoSize.h this.previewSize = 'auto' } this.changeResolution() }, // 找第一个页面 findFirstPage(treeData) { const queue = [...treeData]; while (queue.length > 0) { const item = queue.shift(); // 如果是有效页面,直接返回 if (item.folderFlag === false && item.uuid) { return item; } // 如果是文件夹且有子节点,将子节点加入队列前端(优先处理) if (item.folderFlag === true && item.childrenList?.length) { queue.unshift(...item.childrenList); } // 如果是空文件夹,自动跳过(继续循环) } return null; }, // 页面列表 getPageList() { this.treeData = filterByHasVersion(treeArr) // const currentPage = this.treeData.find(item => item.default) || this.treeData[0] const currentPage = this.findFirstPage(this.treeData) console.log(this.treeData, this.pageList); this.pageUuid = currentPage.pageUuid this.pageName = currentPage.pageName this.pageType = currentPage.pageScene this.isHtml = currentPage.codeType === 'html' this.$nextTick(()=>{ this.getAppPageVersion(currentPage) }) collectItems(this.treeData, this.pageList); this.currentIndex = this.pageList.findIndex(item=>item.pageUuid == this.pageUuid) || 0; this.cleanup = this.createKeyboardNavigation(); }, // 获取应用中页面内容 async getAppPageVersion(info) { const isApp = this.pageType == 'app' let iframe = this.isHtml ? document.getElementById('iframe') : document.getElementById('vueIframeWeb') if (isApp) { iframe = document.getElementById('iframeApp') } if (info.parentUrl) { iframe.src = info.parentUrl this.childUrl = info.url } else { iframe.src = info.url; } }, loadHtmlIframe() { if (this.childIframe) { this.childIframe() this.childIframe = null } const isApp = this.pageType == 'app' // let template = handleCode(this.pageHtml, !isApp); let iframe = document.getElementById('iframe') if (isApp) { iframe = document.getElementById('iframeApp') } const htmlIframe = iframe.contentDocument || iframe.contentWindow.document; if (htmlIframe) { const navIframe = htmlIframe.getElementById('navigation') || htmlIframe.getElementById('contentFrame') this.$nextTick(() => { const top = this.checkIframePositionSimple(htmlIframe) if (navIframe) { if (top) { navIframe.style.height = `calc(100vh - ${top}px)`; // 减去导航高度 } // navIframe.srcdoc = handleCode(this.childUrl, !isApp); navIframe.src = this.childUrl const iframeKeydownHandler=(e) => { this.keyboardEvents(e) } navIframe.addEventListener('load', () => { const navIframeDoc = navIframe.contentDocument || navIframe.contentWindow.document; this.childIframe = useEventListener(navIframeDoc, 'keydown', iframeKeydownHandler) }); } var homeMenu = htmlIframe.querySelector(`[data-uuid="${this.pageUuid}"]`) let currentMenu = htmlIframe.querySelector('.active-menu') if (homeMenu) { currentMenu?.classList.remove('active-menu') homeMenu.classList.add('active-menu'); } }) } }, // 获取子页面位置信息 checkIframePositionSimple(htmlIframe) { const iframe = htmlIframe.getElementById('navigation'); if (iframe) { const iframeRect = iframe.getBoundingClientRect(); return iframeRect.top } return }, renderIframe(pageHtml) { // const isApp = this.pageType == 'app' // let template = handleCode(pageHtml, !isApp); // let iframe = document.getElementById('iframe') // if (isApp) { // iframe = document.getElementById('iframeApp') // } // if(isIOSWechat()) { // const parser = new DOMParser(); // const doc = parser.parseFromString(template, 'text/html'); // const updatedHtmlString = new XMLSerializer().serializeToString(doc); // const iframeDocument = iframe.contentDocument || iframe.contentWindow.document; // iframeDocument.write(updatedHtmlString); // return // } // if(!this.isHtml) { // return // } // iframe.srcdoc = template }, // 点击目录切换页面 handleChangePage(node) { if (!node.folderFlag) { this.pageName = node.pageName this.pageType = node.pageScene this.$nextTick(()=>{ this.getAppPageVersion(node) }) } this.currentIndex = this.pageList.findIndex(item=>item.pageUuid == node.uuid) || 0; this.pageUuid = node.uuid }, changeResolution() { if (this.pageType === 'app') { const contentApp = document.querySelector('.preview-suitable-content-app') // contentApp.style.aspectRatio = Number(this.previewSizeW)/Number(this.previewSizeH) const borderDom = document.querySelector('.app-border') const scale = Math.min(contentApp.offsetWidth/Number(this.previewSizeW), contentApp.offsetHeight/Number(this.previewSizeH)) borderDom.style.transform = `scale(${scale})` } else { if (this.appName) { const contentApp = document.querySelector('.page-content') let borderDom = this.isHtml ? document.getElementById('iframe') : document.getElementById('vueIframeWeb') const scale = Math.min(contentApp.offsetWidth/Number(this.previewSizeW), contentApp.offsetHeight/Number(this.previewSizeH)) borderDom.style.transform = `scale(${scale})` } } }, changeCurrentIndex(num) { if (num == -1) { if (this.currentIndex > 0) { this.currentIndex-- } } else { if (this.currentIndex < this.pageList.length - 1) { this.currentIndex++ } } this.handleChangePage(this.pageList[this.currentIndex]) }, // 键盘事件 keyboardEvents(event) { if (event.key === 'ArrowLeft') { // 向左键:移动到前一个项目,如果已经是第一个则不处理 event.preventDefault(); this.changeCurrentIndex(-1) } else if (event.key === 'ArrowRight') { // 向右键:移动到下一个项目,如果已经是最后一个则不处理 event.preventDefault(); this.changeCurrentIndex(1) } else if (event.key === 'Escape') { this.isPreview = false this.isShowTip = false clearTimeout(this.setTimeout1) this.setTimeout1 = null } }, createKeyboardNavigation() { // 处理键盘事件 const handleKeyDown = (event) => { if (this.pageList.length === 0) return; this.keyboardEvents(event) }; // 添加事件监听 window.addEventListener('keydown', handleKeyDown); // 返回一个移除事件监听的函数 return () => { window.removeEventListener('keydown', handleKeyDown); }; }, toPreview() { this.isPreview = true this.isShowTip = true this.setTimeout1 = setTimeout(()=>{ this.isShowTip = false }, 5000) }, vueIfameloaded() { this.$nextTick(() => { const iframeId = this.pageType === 'app' ? '#vueIframeApp' : '#vueIframeWeb' const iframeApp = document.querySelector(iframeId); // const iframeAppDoc = iframeApp.contentDocument || iframeApp.contentWindow.document; // const tag = iframeAppDoc.querySelector('.ai-tag') // tag && (tag.style && (tag.style.visibility = 'hidden') || tag.style.setAtrrbute('visibility','hidden')) }) } }, beforeDestroy() { this.cleanup() if (this.resizeObserver) { this.resizeObserver.disconnect() } if (this.iframeMessage) { this.iframeMessage() this.iframeMessage = null } if (this.childIframe) { this.childIframe() this.childIframe = null } } }) app.component('treeNode', treeNode); app.mount('#app') // 过滤用户没有生成的页面 function filterByHasVersion(data) { // 如果不是数组,直接返回 if (!Array.isArray(data)) return data; // 使用 filter 移除 hasVersion === 1 的对象 return data.filter(item => { if (item.hasVersion === '1') { return false; // 移除该对象 } // 递归处理 children if (item.children && Array.isArray(item.children)) { item.children = filterByHasVersion(item.children); } return true; // 保留该对象 }); } /** * 用于遍历嵌套数组中 folderFlag 为 false 的对象 * @param {Array} items - 要遍历的嵌套数组 */ function collectItems(nodes, flatItems) { nodes.forEach((node) => { if (node.folderFlag === false) { flatItems.push({ ...node, }); } if (node.childrenList && node.childrenList.length > 0) { collectItems(node.childrenList, flatItems); } }); }