由于業(yè)務(wù)需求,最近研究localStorage、indexedDB等如何跨域進(jìn)行CRUD管理,經(jīng)過(guò)一番研究,封裝了如下代碼并做個(gè)筆記
環(huán)境
- vue:
^3.3.4
實(shí)戰(zhàn)
發(fā)送端(即觸發(fā)站點(diǎn))
在App.vue
中引入CrossDomainStorage
組件(后面有實(shí)現(xiàn)過(guò)程)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-632852.html
<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">測(cè)試</button>
<CrossDomainStorage :src="'http://xxxx.xxx/'" ref="crossDomainStorageRef"/>
</div>
</template>
接收端(即目標(biāo)站點(diǎn))
為了方便直接在App.vue
中實(shí)踐文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-632852.html
<script setup>
import ParentMsgListener from '@/utils/parentMsgListener'
const parentMsgListener = new ParentMsgListener()
parentMsgListener.addPermissionModule({ // 設(shè)置權(quán)限key對(duì)應(yīng)處理方法
localStorage: {
setItem: localStorage.setItem,
getItem: localStorage.getItem,
},
asyncTest: {
text: async ()=> await 'asyncValue',
text2: () => 'testValue',
}
});
parentMsgListener.addPermission([ // 設(shè)置可操作的對(duì)象列表
'localStorage'
])
parentMsgListener.start();
</script>
實(shí)現(xiàn)代碼
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('[發(fā)送端]從iframe獲取數(shù)據(jù)', 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('[發(fā)送端]向iframe發(fā)送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
}
/**
* 監(jiān)聽(tīng)響應(yīng)攔截
*
* @param {object} e 接收數(shù)據(jù)
* @param {array} permission 權(quán)限列表
* @param {function} response 接收回調(diào)
*
* @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 { // 調(diào)用非js內(nèi)置方法且兼容異步調(diào)用處理方法
result = await ((lib[method]).apply(lib[method], Object.values(param)));
}catch (error) { // 調(diào)用js內(nèi)置方法
result = eval(`${e.data.key}.${method}(${_param.join(',')})`);
}
}
messageLog('response:', result)
response({
request: e.data,
response: result
}, '*')
}
}
class ParentMsgListener {
/**
* 消息調(diào)用權(quán)限對(duì)應(yīng)處理
* @var {object}
*/
private permissionMap = {};
/**
* 消息允許調(diào)用權(quán)限
* @var {string[]}
*/
private permission = []
constructor(permission) {
if (permission && permission.length>0){
this.addPermission(permission)
}
}
/**
* 添加授權(quán)權(quán)限key對(duì)應(yīng)處理模塊
*
* @param {string|object} name 權(quán)限key
* @param {function} fn 權(quán)限key處理方法
*
* @return this
*/
addPermissionModule(name:string|object, fn){
if (!fn && typeof name === 'object'){ // 批量導(dǎo)入
for (let moduleKey in name){
this.addPermissionModule.call(this, moduleKey, name[moduleKey]);
}
}else if(typeof name === 'string' && !!fn) { // 逐個(gè)導(dǎo)入
this.permissionMap[name] = fn;
}
return this;
}
/**
* 添加授權(quán)權(quán)限
*
* @param {string|string[]} permissionKey 權(quán)限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;
}
/**
* 發(fā)送消息
*
* @param {object} message 發(fā)送內(nèi)容
* @param {string} targetOrigin 默認(rèn):*
*
* @return {void}
*/
sendMessage(message:any, targetOrigin:string = '*'){
messageLog('發(fā)送消息', message)
window.parent.postMessage(message, targetOrigin)
}
/**
* 啟動(dòng)監(jiān)聽(tīng)
*/
start(){
window.addEventListener(
'message',
(e)=>listenerResponse(e, {
key: this.permission,
module: this.permissionMap
}, this.sendMessage)
)
}
}
export default ParentMsgListener
到了這里,關(guān)于【VUE】localStorage、indexedDB跨域數(shù)據(jù)操作實(shí)戰(zhàn)筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!