由于业务需求,最近研究localStorage、indexedDB等如何跨域进行CRUD管理,经过一番研究,封装了如下代码并做个笔记
^3.3.4
在App.vue
中引入CrossDomainStorage
组件(后面有实现过程)
<script setup>
import { ref } from 'vue'
import CrossDomainStorage from "@/components/CrossDomainStorage/index.vue";
const crossDomainStorageRef = ref(null)
function sendTest() {
if (crossDomainStorageRef.value){
crossDomainStorageRef.value.sendMessage("getItem", {key:'APP_THEME_SCREEN'})
}
}
</script>
<template>
<div>
<button @click="sendTest">测试</button>
<CrossDomainStorage :src="'http://xxxx.xxx/'" ref="crossDomainStorageRef"/>
</div>
</template>
为了方便直接在App.vue
中实践
<script setup>
import ParentMsgListener from '@/utils/parentMsgListener'
const parentMsgListener = new ParentMsgListener()
parentMsgListener.addPermissionModule({ // 设置权限key对应处理方法
localStorage: {
setItem: localStorage.setItem,
getItem: localStorage.getItem,
},
asyncTest: {
text: async ()=> await 'asyncValue',
text2: () => 'testValue',
}
});
parentMsgListener.addPermission([ // 设置可操作的对象列表
'localStorage'
])
parentMsgListener.start();
</script>
CrossDomainStorage
组件<script setup lang="ts">
import {ref, reactive, onMounted} from 'vue';
defineOptions({
name: 'CrossDomainStorage'
});
const iframeRef = ref();
const emit = defineEmits(['onLoad','response'])
const props = defineProps({
src: {type: String, default:()=>"", required:true}
});
const status = ref(false)
const iframeStyles = reactive({
position: 'fixed',
top:0,
left:0,
width: 0,
height: 0,
zIndex:-1
});
window.addEventListener('message', function (e) {
if (e.data && e.data.request){
console.log('[发送端]从iframe获取数据', e.data)
emit('response', e.data||null)
}
});
function sendMessage(method: string, param: object, key: string) {
if (status.value===false)return;
key = key?key:'localStorage'
if (iframeRef?.value){
const iframeNode = iframeRef.value.contentWindow;
let request = {key, method, param}
console.log('[发送端]向iframe发送request:', request)
setTimeout(function () {
iframeNode.postMessage(request, '*')
}, 500)
}
}
defineExpose({
sendMessage: (method: string, param: object, key: string)=>sendMessage(method, param, key)
})
onMounted(()=>{
if (!!iframeRef.value && !!iframeRef.value.contentWindow){
iframeRef.value.onload = function () {
status.value = true;
emit('onLoad', true)
}
}
})
</script>
<template>
<iframe ref="iframeRef" :src="props.src"
:style="iframeStyles"
frameborder="0"
scrolling="no"/>
</template>
parentMsgListener.ts
封装消息管理类// src/utils/parentMsgListener.ts
const messageLog = function (log, ...arg){
arg.unshift(`[接收端]`, log)
console.log.apply(console, arg)
}
interface permissionOptions {
key: string[],
module: object
}
/**
* 监听响应拦截
*
* @param {object} e 接收数据
* @param {array} permission 权限列表
* @param {function} response 接收回调
*
* @return {void}
*/
const listenerResponse = async function (e, permission: permissionOptions, response) {
if (e.data && !!e.data.key && permission.key.includes(e.data.key)){
let result = undefined;
let lib = permission.module[e.data.key] || undefined;
let method = e.data?.method || '';
let param = e.data?.param||{};
if (!!lib){
let _param = [];
for (let key in param){
_param.push(`'${param[key]}'`)
}
try { // 调用非js内置方法且兼容异步调用处理方法
result = await ((lib[method]).apply(lib[method], Object.values(param)));
}catch (error) { // 调用js内置方法
result = eval(`${e.data.key}.${method}(${_param.join(',')})`);
}
}
messageLog('response:', result)
response({
request: e.data,
response: result
}, '*')
}
}
class ParentMsgListener {
/**
* 消息调用权限对应处理
* @var {object}
*/
private permissionMap = {};
/**
* 消息允许调用权限
* @var {string[]}
*/
private permission = []
constructor(permission) {
if (permission && permission.length>0){
this.addPermission(permission)
}
}
/**
* 添加授权权限key对应处理模块
*
* @param {string|object} name 权限key
* @param {function} fn 权限key处理方法
*
* @return this
*/
addPermissionModule(name:string|object, fn){
if (!fn && typeof name === 'object'){ // 批量导入
for (let moduleKey in name){
this.addPermissionModule.call(this, moduleKey, name[moduleKey]);
}
}else if(typeof name === 'string' && !!fn) { // 逐个导入
this.permissionMap[name] = fn;
}
return this;
}
/**
* 添加授权权限
*
* @param {string|string[]} permissionKey 权限key
*
* @return this
*/
addPermission(permissionKey: string|string[]){
if (permissionKey instanceof Array){
let that = this;
permissionKey.forEach((key)=>{
that.permission.push(key)
})
}else{
this.permission.push(permissionKey)
}
return this;
}
/**
* 发送消息
*
* @param {object} message 发送内容
* @param {string} targetOrigin 默认:*
*
* @return {void}
*/
sendMessage(message:any, targetOrigin:string = '*'){
messageLog('发送消息', message)
window.parent.postMessage(message, targetOrigin)
}
/**
* 启动监听
*/
start(){
window.addEventListener(
'message',
(e)=>listenerResponse(e, {
key: this.permission,
module: this.permissionMap
}, this.sendMessage)
)
}
}
export default ParentMsgListener