Skip to content

Commit

Permalink
Merge pull request #105 from terwer/dev
Browse files Browse the repository at this point in the history
fix: 添加浮窗 loading 提升用户体验
  • Loading branch information
terwer committed Jun 20, 2023
2 parents ef39d06 + 7690aaf commit 196b4a8
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 34 deletions.
27 changes: 27 additions & 0 deletions layouts/default.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
<script lang="ts" setup>
import Header from "~/components/default/Header.vue"
import Footer from "~/components/default/Footer.vue"
import { createAppLogger } from "~/common/appLogger"
import { sendMessageToParent } from "~/utils/innerIframeEvent"
const logger = createAppLogger("blog-app-layout")
// datas
onMounted(() => {
if (window.self !== window.top) {
logger.info("Current window is inside an iframe")
const isParentWindowLoaded = window.parent.document.readyState === "complete"
if (isParentWindowLoaded) {
nextTick(() => {
const height = document.body.scrollHeight + 10
logger.info(`Sending message to parent window with height: ${height}`)
sendMessageToParent("updateHeight", height)
})
} else {
logger.info("Parent window has not finished loading yet.")
}
window.addEventListener("load", function () {
logger.info("IFrame has finished loading.")
})
}
})
</script>

<template>
Expand Down
31 changes: 25 additions & 6 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const generateDynamicV = () => {
}

const isDev = process.env.NODE_ENV === "development"
const appBase = "/"
const appBase = "/plugins/siyuan-blog/"
const staticV = generateDynamicV()

// https://nuxt.com/docs/api/configuration/nuxt-config
Expand All @@ -24,7 +24,14 @@ export default defineNuxtConfig({
},

// build modules
modules: ["@vueuse/nuxt", "@nuxtjs/i18n", "@element-plus/nuxt", "@nuxtjs/color-mode", "@pinia/nuxt", "@nuxt/image"],
modules: [
"@vueuse/nuxt",
"@nuxtjs/i18n-edge",
"@element-plus/nuxt",
"@nuxtjs/color-mode",
"@pinia/nuxt",
"@nuxt/image",
],

// vueuse
vueuse: {
Expand Down Expand Up @@ -57,6 +64,14 @@ export default defineNuxtConfig({
themes: ["dark"],
},

// https://nuxt.com/docs/guide/going-further/custom-routing#hash-mode-spa
ssr: false,
router: {
options: {
hashMode: true,
},
},

css: ["~/assets/siyuan/style.styl", "~/assets/siyuan/index.styl"],

app: {
Expand Down Expand Up @@ -93,11 +108,15 @@ export default defineNuxtConfig({

// 环境变量
runtimeConfig: {
siyuanAuthToken: process.env.NUXT_SIYUAN_AUTH_TOKEN,
// siyuanAuthToken: process.env.NUXT_SIYUAN_AUTH_TOKEN,
siyuanAuthToken: "",
public: {
defaultType: process.env.NUXT_PUBLIC_DEFAULT_TYPE,
siyuanApiUrl: process.env.NUXT_PUBLIC_SIYUAN_API_URL,
waitTime: process.env.NUXT_PUBLIC_WAIT_TIME,
// defaultType: process.env.NUXT_PUBLIC_DEFAULT_TYPE,
defaultType: "siyuan",
// siyuanApiUrl: process.env.NUXT_PUBLIC_SIYUAN_API_URL,
siyuanApiUrl: "",
// waitTime: process.env.NUXT_PUBLIC_WAIT_TIME,
waitTime: "0",
},
},
})
55 changes: 35 additions & 20 deletions siyuan/iframeEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,21 @@

import { popContentIframeId } from "~/siyuan/siyuanConstants"
import { createAppLogger } from "~/common/appLogger"
import SiyuanBlog from "~/siyuan/index"

const logger = createAppLogger("iframe-events")
let added = false
export const adjustIframeHeight = (iframeId: string, customHeight?: number) => {
const adjustIframeHeight = (iframeId: string, customHeight?: number) => {
const iframe = document.getElementById(iframeId) as HTMLIFrameElement
let counter = 0
let lastHeight = "0px" // 将初始高度设为 "0px"
const defaultHeight = 350

// 注册定时器
const interval = setInterval(() => {
// 获取id为__nuxt的元素高度
const iframeBody = iframe?.contentWindow?.document.getElementById("__nuxt") as HTMLElement
let height = `${customHeight ?? iframeBody.scrollHeight}px`
let height = `${customHeight ?? iframeBody?.scrollHeight ?? defaultHeight}px`
if (height === lastHeight) {
if (!added) {
height = height + 10
Expand Down Expand Up @@ -65,25 +67,38 @@ export const adjustIframeHeight = (iframeId: string, customHeight?: number) => {
}
}

// 监听 message 事件
window.addEventListener("message", (event) => {
const iframe = document.getElementById(popContentIframeId) as HTMLIFrameElement
/**
* 注册 iframe 事件
*/
export const registerIframeEvent = (pluginInstance: SiyuanBlog) => {
// 监听 message 事件
window.addEventListener("message", (event) => {
const iframe = document.getElementById(popContentIframeId) as HTMLIFrameElement

// 判断是否是来自指定 iframe 的消息
if (event.source === iframe.contentWindow) {
const data = event.data
// 判断消息类型
if (data.type === "updateHeight") {
logger.info(`Try to cancel loading`)
pluginInstance.popView.cancelLoading()

// 判断是否是来自指定 iframe 的消息
if (event.source === iframe.contentWindow) {
const data = event.data
// 判断消息类型
if (data.type === "updateHeight") {
logger.info(`Received update height message from iframe`)
const height = data.height
// 更新 iframe 高度
if (height) {
iframe.height = `${height}px`
logger.info(`Updated iframe height to ${height}px`)
logger.info(`Received update height message from iframe`)
const height = data.height
// 更新 iframe 高度
if (height) {
iframe.height = `${height}px`
logger.info(`Updated iframe height to ${height}px`)
} else {
adjustIframeHeight(popContentIframeId)
logger.info(`Auto adjust iframe height to ${height}px`)
}
} else {
adjustIframeHeight(popContentIframeId)
logger.info(`Auto adjust iframe height to ${height}px`)
logger.warn(`Unknown message type, ignore`)
}
} else {
logger.warn(`message is not from contentWindow, ignore`)
}
}
})
})
logger.info("iframe event registered in plugin main")
}
50 changes: 50 additions & 0 deletions siyuan/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,53 @@
margin 0
padding 0
overflow hidden

.loading-spinner {
width: 64px;
height: 64px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 5px;
}

.loading-spinner > div {
box-sizing: border-box;
display: block;
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border-radius: 50%;
border: 2px solid #3498db;
border-bottom-color: transparent;
animation: loading-spinner-animation 0.75s 0s linear infinite;
}

.loading-spinner > div:nth-child(1) {
animation-delay: 0s;
}

.loading-spinner > div:nth-child(2) {
animation-delay: -0.6s;
}

.loading-spinner > div:nth-child(3) {
animation-delay: -0.4s;
}

.loading-spinner > div:nth-child(4) {
animation-delay: -0.2s;
}

@keyframes loading-spinner-animation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
6 changes: 6 additions & 0 deletions siyuan/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ import { isDev } from "~/common/Constants"

import "./index.styl"
import { icons } from "~/siyuan/utils/svg"
import { registerIframeEvent } from "~/siyuan/iframeEvent"

export default class SiyuanBlog extends Plugin {
public isMobile
public logger
public popView: any

constructor(options: { app: App; id: string; name: string; i18n: IObject }) {
super(options)

Expand All @@ -44,7 +47,10 @@ export default class SiyuanBlog extends Plugin {
onload() {
// 注册图标
this.addIcons(icons.iconShare)
// 初始化顶部栏以及图标
initTopbar(this)
// 注册 iframe 事件
registerIframeEvent(this)
}

openSetting() {
Expand Down
40 changes: 34 additions & 6 deletions siyuan/topbar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import { Dialog, Menu } from "siyuan"
import PageUtil from "~/siyuan/utils/pageUtil"
import { getAvailableOrigin } from "~/siyuan/utils/utils"
import { contentElement, contentHtml } from "~/siyuan/customElement"
import { adjustIframeHeight } from "~/siyuan/iframeEvent"
import { popContentIframeId } from "~/siyuan/siyuanConstants"

/**
* 顶栏按钮
Expand All @@ -50,8 +48,10 @@ export function initTopbar(pluginInstance: SiyuanBlog) {
topBarElement.addEventListener("click", async () => {
const sharePage =
"/plugins/siyuan-blog/#/share?id=" + PageUtil.getPageId() + "&origin=" + getAvailableOrigin() + "&isSsr=false"
showPopView(pluginInstance, topBarElement, sharePage)
adjustIframeHeight(popContentIframeId)
const popView = showPopView(pluginInstance, topBarElement, sharePage, {
showLoading: true,
})
pluginInstance.popView = popView
})

// topBarElement.addEventListener("click", async () => {
Expand Down Expand Up @@ -139,8 +139,14 @@ const showPage = (pluginInstance: SiyuanBlog, pageUrl: string, title?: string) =
* @param pluginInstance 插件实例对象
* @param boxElement 被点击的 box 元素
* @param pageUrl 当前页面的 URL
* @param options
*/
const showPopView = (pluginInstance: SiyuanBlog, boxElement: HTMLElement, pageUrl: string) => {
const showPopView = (
pluginInstance: SiyuanBlog,
boxElement: HTMLElement,
pageUrl: string,
options: { showLoading?: boolean; cancelLoading?: any } = {}
) => {
const popContentId = "pop-content"
let popContent = document.getElementById(popContentId)

Expand Down Expand Up @@ -170,8 +176,28 @@ const showPopView = (pluginInstance: SiyuanBlog, boxElement: HTMLElement, pageUr
popContent.style.opacity = "0"
popContent.style.transition = "opacity 0.3s ease-in-out"

// 添加loading效果
if (options.showLoading) {
const loadingElement = document.createElement("div")
loadingElement.className = "loading-spinner"
for (let i = 0; i < 4; i++) {
const divElement = document.createElement("div")
loadingElement.appendChild(divElement)
}
popContent.appendChild(loadingElement)

// 定义cancelLoading函数,用于取消loading
const cancelLoading = () => {
popContent?.removeChild(loadingElement)
}

// 在option中添加cancelLoading函数
options.cancelLoading = cancelLoading
}

// 填充内容
popContent.innerHTML = contentElement(pageUrl).innerHTML
const content = contentElement(pageUrl)
popContent.appendChild(content)

document.body.appendChild(popContent)

Expand Down Expand Up @@ -204,4 +230,6 @@ const showPopView = (pluginInstance: SiyuanBlog, boxElement: HTMLElement, pageUr
}
}, 300) // 等待 300ms,即过渡时间,然后再删除浮动框
}

return options
}
4 changes: 2 additions & 2 deletions utils/innerIframeEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { createAppLogger } from "~/common/appLogger"

const logger = createAppLogger("inner-iframe-event")

export const sendMessageToParent = (type: string) => {
export const sendMessageToParent = (type: string, height?: number) => {
const win = window.self as any
if (!win.parent.siyuan) {
logger.info(`Not in siyuan-note plugin iframe environment, ignore message sending`)
Expand All @@ -38,6 +38,6 @@ export const sendMessageToParent = (type: string) => {
const iframeWindow = window.self

// 向父窗口发送消息
iframeWindow.parent.postMessage({ type: type }, "*")
iframeWindow.parent.postMessage({ type: type, height: height }, "*")
logger.info(`Sends a message to the parent window, type => ${type}`)
}

1 comment on commit 196b4a8

@vercel
Copy link

@vercel vercel bot commented on 196b4a8 Jun 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.