feat: 新增 Demo 站点

This commit is contained in:
ZiuChen 2024-04-02 12:17:26 +08:00
parent 35932564d9
commit d1f2269fbe
7 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,36 @@
<template>
<div class="home">
<h2>Home</h2>
<iframe ref="iframeRef" src="/demos/promiseify-post-message/inner" frameborder="0" />
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { registerBase } from './base'
const iframeRef = ref<HTMLIFrameElement | null>(null)
onMounted(() => {
if (iframeRef.value && iframeRef.value.contentWindow) {
registerBase(iframeRef.value.contentWindow)
}
})
</script>
<style scoped>
/* 隐藏掉窄屏时 fixd 在顶部的 Return to top */
:global(.VPLocalNav) {
display: none;
}
.home {
padding: 25px;
}
iframe {
width: 100%;
height: 100%;
border: 1px solid #ccc;
}
</style>

View File

@ -0,0 +1,40 @@
<template>
<div class="inner">
<h2>Inner</h2>
<button @click="getUserToken('123456')">getUserToken: {{ userToken }}</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { registerSdk, postMessage } from './sdk'
registerSdk()
const userToken = ref('')
async function getUserToken(userId: string) {
const token = await postMessage({
namespace: 'user',
action: 'getUserToken',
payload: {
userId
}
})
if (token) {
userToken.value = token as string
}
}
</script>
<style scoped>
/* 隐藏掉窄屏时 fixd 在顶部的 Return to top */
:global(.VPLocalNav) {
display: none;
}
.inner {
padding: 25px;
}
</style>

View File

@ -0,0 +1,43 @@
import get from 'lodash-es/get'
import { FuncMap } from './types'
import { JSBridgeParams } from './sdk'
/**
* SDK
*/
export function registerBase(target: Window) {
window.addEventListener('message', async (e) => {
const params = e.data as JSBridgeParams<any>
const namespace = params.namespace
const action = params.action
const callback = get(callbackMap, [namespace, action])
if (callback) {
const result = await callback(params.payload)
target.postMessage(
{
params,
result
},
'*'
)
}
})
}
type Namespace = keyof FuncMap
type Action = keyof FuncMap[Namespace]
type Payload = FuncMap[Namespace][Action] extends { payload: infer P } ? P : never
type Result = FuncMap[Namespace][Action] extends { result: infer R } ? R : never
const callbackMap: Record<
Namespace,
{
[key in Action]: (payload: Payload) => Result
}
> = {
user: {
getUserToken: ({ userId }) => {
return 'token:' + userId
}
}
}

View File

@ -0,0 +1,17 @@
---
layout: page
navbar: false
sidebar: false
aside: false
footer: false
---
# Promiseify PostMessage
将 postMessage 消息通信 Promise 化
<script setup>
import DemoComponent from './Index.vue'
</script>
<DemoComponent />

View File

@ -0,0 +1,14 @@
---
layout: page
navbar: false
sidebar: false
aside: false
footer: false
outline: false
---
<script setup>
import DemoComponent from './Inner.vue'
</script>
<DemoComponent />

View File

@ -0,0 +1,46 @@
import { FuncMap } from './types'
export interface JSBridgeParams<T extends keyof FuncMap> {
namespace: T
action: keyof FuncMap[T]
payload: FuncMap[T][keyof FuncMap[T]] extends { payload: infer P } ? P : never
}
/**
* SDK
*/
export function registerSdk() {
window.addEventListener('message', messageHandler)
}
const postMessageCallbackMap = new Map()
function messageHandler({ data, type }: MessageEvent) {
if (type === 'message') {
const { params, result } = data
const key = [params.namespace, params.action, params.id].join('.')
const callback = postMessageCallbackMap.get(key)
if (callback) {
callback(result)
postMessageCallbackMap.delete(key)
}
}
}
let uniqueId = 0
export function postMessage<T extends keyof FuncMap>(
params: JSBridgeParams<T>
): Promise<FuncMap[T][keyof FuncMap[T]] extends { result: infer R } ? R : never> {
return new Promise((resolve) => {
if (window.parent) {
const id = uniqueId++
const key = [params.namespace, params.action, id].join('.')
postMessageCallbackMap.set(key, resolve)
const _params = structuredClone(params)
// @ts-expect-error - id is private field.
_params.id = id
window.parent.postMessage(_params, '*')
}
})
}

View File

@ -0,0 +1,11 @@
/**
* SDK
*/
export interface FuncMap {
user: {
getUserToken: {
payload: { userId: string }
result: string
}
}
}