百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

使用iframe+postMessage通信实现商城多页面装修

connygpt 2024-08-28 14:12 5 浏览

背景

开发项目是多商家的类似有赞的商城后台,需要支持客户端的店铺装修功能

系统用户多为企业用户对页面效果要求较高,导致首页变化非常频繁

前言

2020年第一版本装修上线了,方案是后台“模拟”客户端样式实现可视化,实现首页装修功能

实际上也就是后台写一套与客户端一样的样式解析装修json,实现装修预览的效果

模拟版本的装修上线后,确实解决了多店铺个性化首页的问题,实现了定制化首页,但是随着时间的推移,模拟版本暴露了很多问题,高频率的改版导致需求几乎无法满足

  • 装修数据为静态数据,不会根据商城商品状态而变化,例如某某商品下架了,但是首页装修数据里面依旧存在
  • 每次客户端样式发生变化,后台都需要同步编写一份,否则就无法可视化,导致工作量非常大
  • 不具备扩展性,只能可视化的装修首页,无法可视化装修其他页面,其他页面都是通过一个插槽实现
  • 插槽就是一个json对象的载体,因为不想写2套样式,所以采取这种很抽象的方案

随着业务的拓展,暴露出来的问题也是越来越严重,为了满足需求,很多场景下需要牺牲整个技术部门的效率,以及使用者的体验感,为了解决这个问题必须另辟蹊径,寻找其他解决方案

新方案必须解决以下问题

  • 装修中的商品数据必须为非静态数据
  • 避免2套样式的问题

装修中的商品数据实时刷新可以通过约定有规律的数据结构,后端解析并实时更新商品数据,实现装修中数据的更新

抛弃模拟方案后,也是思考很多方向,但是因为基于业务组件装修是没办法整个装修数据都json化的,所以最终尝试了一个理论上可行的方案,客户端通过iframe嵌入到后台,使用postMessage来完成后台与客户端之间的数据交互,实现装修功能

方案逻辑图

后台装修与客户端的主要思路

  • 装修模式下获取上次的装修记录
  • 建立前后台iframe之前的的联系
  • 后台装修发生变化,触发watch,watch触发postmessage,客户端得到相应,客户端watch触发,实时更新装修数据
  • 装修完成保存到数据库

具体实现方案

之前在掘金发布过一篇(开源)从0打造H5可视化搭建系统 - 易动(vue+ts+egg)文章,易动是更加灵活的装修方案,感兴趣的同学可以了解一下

基础组件定制装修方案,基础模块为: 按钮 文本 图片 轮播图此类数据 等等

本次的装修是基于业务组件进行区分,他的核心原理就是通过iframe进行数据交互实现实时装修功能

定制组件数据结构

客户端根据json数据进行组件的展示的,所有首先,我们需要定义好客户端与后台通用的数据结构,用于声明我们的装修数据

例如我定义的数据结构,仅供参考 示例 搜索框 轮播图

{
  id: guid(),
    compName: 'drag-search',
      name: '搜索框',
        data: [
          {
            placeholder: '想要什么呢,快来搜一下吧',
            tbHeader: false, // 是否显示淘宝推荐
            isUpdate: false
          }
        ]
},
  {
    id: guid(),
      compName: 'drag-swiper',
        name: '轮播图',
          data: [
            {
              interval: 5000,
              data: [], // 数据
              item: {
                // 单个数据
                img:
                'https://images.591wsh.com/2021/02/03/thumb_32371580472397824.png',
                isLogin: false, // 是否需要登录,
                linkType: 2, // 1 无链接 2 商品 3 外部链接 4分类
                commodity: {}, // 商品id
                dataurl: '', // 外部链接
                categoryid: '', // 类目id
              },
              isUpdate: true // 告诉服务器是否需更新data里面的商品数据
            }
          ],
            css: {
              height: 266, //
              marginTop: 20
            }
  },

为装修中的客户端页面增加一个组件

增加,修改,删除都会走如下逻辑,一句话说就是数据后台操作数据,客户端可以做出响应

// 后台点击右侧装修组件,例如点击 搜索框
// 匹配到搜索框的文字匹配定制的数据结构,得到如下点击的数据结构
{
  id: guid(),
    compName: 'drag-search',
      name: '搜索框',
        data: [
          {
            placeholder: '想要什么呢,快来搜一下吧',
            tbHeader: false, // 是否显示淘宝推荐
            isUpdate: false
          }
        ]
},
 // 后台通过监听存储装修数据变化的字段通知到客户端
 computed: {
   // .....
   // 可使用组件
   pageComponents: {
     get() {
       let { pageComponents } = this.$store.state.template
       if (pageComponents instanceof Array) {
         // 组件数据发生变化的时候需要通知到客户端
         this.iframeMessage(pageComponents)
         return pageComponents
       } else {
         return []
       }
     },
       set(data) {
         // 更新组件顺序
         this.$store.commit('template/update_current', data)
       }
   }
   // ......
 },
 methods:{
   // iframe加载完成的回调函数
   iframeLoad() {
     console.log('iframe加载完成')
     this.frm = document.getElementById('iframe')
     // 告诉客户端,目前处于装修中
     this.frm.contentWindow.postMessage(
       {
         isIframe: true
       },
       '*'
     )
   },
   // 通知客户端数据发生了更新
   iframeMessage(data) {
     console.log(data)
     if (this.frm) {
       this.frm.contentWindow.postMessage(
         {
           tempLateData: data
         },
         '*'
       )
     }
   }, 
 }
  


// 客户端通过postMessage进行最新的装修数据接收
window.addEventListener('message', _fundecoratio)
function _fundecoratio(event) {
    // ....
  if (event.data.tempLateData) {
    store.commit('app/setTempLateData', event.data.tempLateData)
  }
  // ....
}

// 客户端对应的页面再监听存在在vuex中的装修数据
computed: {
  ...mapState({
    tempLateData: state => state.app.tempLateData, // 后台的装修数据
    hoverComponent: state => state.app.hoverComponent, // 当前鼠标浮动的元素id
    clickComponent: state => state.app.clickComponent, // 当前鼠标点击选中的数据 
    isIframe: state => state.app.isIframe, // 当前是否在装修模式里面
  }),
},

// 客户端替换从接口获取的之前的页面装修数据,装修数据显示在页面上
watch: {
  tempLateData() {
    // 一旦后台通过postMessage更新装修数据,就可以替换原本接口获取的数据,实现实时装修功能
    this.indexData = this.tempLateData || []
  },
},

修改装修的组件数据

// 后台选取选中的组件
// 后台针对每个装修组件都建立一个vue文件进行json内数据的改变‘
// activeComponent.compName 为选中的组件compName,例如我选中搜索框 这里就是`drag-search-data`组件,这里可以是xxx-xxx-data组件

<template>
  <div class="template_right">
    <component
      v-if="activeComponent != false && activeComponent.compName"
      :is="activeComponent.compName + '-data'"
      :compData="activeComponent"
    ></component>
  </div>
</template>


// 组件内部绑定搜索框的提示文字,每次修改都会触发后台的计算属性·pageComponents·,进而后台通过postMessage通知到客户端,客户端进而存储到vuex,vuex值发生变化,客户端页面的watch起作用,页面发生变化,就吃实现组件数据的变化

点击客户端组件,通知后台并实现选中

我们知道,在装修里面点击客户端,就直接点击到了客户端,所以点击客户端的跳转函数,我们必须进行拦截,

// 前提须知 客户端每个装修组件的id都会在客户端写入到class中
<component :is="xxxxx":class="[`decoration_${item.id}`,]"></component>

// 装修监听函数体内
window.addEventListener('message', _fundecoratio)
function _fundecoratio(event) {
    // ....
 if (event.data.isIframe) {
    console.log('装修开发模式启动')
    store.commit('app/setIsIframe', true)
    // 拦截跳转函数
    uni.navigateTo = () => {}
    uni.switchTab = () => {}
    // 监听点击(装修用于选中组件)
    window.addEventListener('click', _decoratioclick, false)
  }
  // ....
}
function _decoratioclick(event) {
  let path: string = ''
  // 每次点击的时候都获取一下包含组件id的class
  event.path.map((res: any) => {
    if (res.className && res.className.includes('decoration_')) {
      path = res.className.split('decoration_')[1]
    }
  })
  // 选中客户端当前组件
  store.commit('app/setClickComponent', path)
  // 告知父级当前选中组件
  window.parent.postMessage(
    {
      activePage: path, // 将当前点击的组件id通过postMessage传递到后台
    },
    '*'
  )
}

// 装修后台
mounted() {
  window.addEventListener(
    'message',
    e => {
      if (e.data.activePage) { // 获取客户端传递过来的当前组件id 这就是实现点击客户端组件装修后台得到数据
        this.$store.commit('template/set_activeComponent', e.data.activePage)
      }
    },
    false
  )
},

添加组件到页面的流程图

客户端与装修后台相互传值总结

// 客户端发送
window.parent.postMessage(
  {
    activePage: path,
  },
  '*'
)

// 客户端接收
window.addEventListener('message', ()=> {
  // ....
})

// 装修后台发送
this.frm = document.getElementById('iframe')
this.frm.contentWindow.postMessage(
  {
     // .....
  },
  '*'
)

// 装修后台接收
window.addEventListener('message',e => {
    // ...
})

postMessage的数据都是实时监听的,所以任意一边传值另一边都可以快速接收到,这是实现本方案的核心,通过postMessage解决了通信上的所有问题,例如

  • 装修后台点击对应组件,客户端可以得到当前点击的组件的id
  • 客户端点击组件可以告知后台,当前用户选中的组件
  • 包括没实现的拖拽排序,都是可以实现的

多页面装修

做页面装修一定要想明白一件事,我们玩的不是装修,只是在操作页面抽象的数据结构

根据上面的想法,我们可以明白,活动页面很多仅仅是换换商品,换换链接,不会动不动就改页面

那个就可以抽象活动页的json数据结构

那么这里对应的就是图片组件 图片组件(优惠券也是图片样式) 商品组件 商品组件

在装修的时候我们定义好数据结构,依次添加这几个组件,客户端活动增加一行watch代码,就可以完美的实现活动页的装修,以及更新活动商品

注:公司项目无法透露,具体逻辑需要大家自己理解了

iframe装修方案优势

  • 100%的完美还原装修样式
  • 可以动态更新装修里面选中的商品的数据,需要数据结构统一化,后端即可按规律解析装修json
  • 如果出现新组件,不需要写2套样式
  • 后台装修定义好数据结构,客户端约定项目结构不变化,理论上整个项目所有页面都可以配置化

iframe装修方案弊端

通过iframe实现的前后台交互装修方案中,不仅需要动后台的装修代码,还需要客户端进行“兼容处理”,即客户端需要识别装修模式,与不断更新后台传入的装修数据,存在一定的耦合性

这种装修方案的弊端就是,如果希望操作起来更加便捷就需要在客户端进行功能的实现,并通过postMessage提交给装修后台

最后

h5装修的实现可以根据具体业务特征进行取舍,达到提效降本的目的,如果你也有类似的需求,欢迎评论交流



相关推荐

自学Python,写一个挨打的游戏代码来初识While循环

自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...

常用的 Python 工具与资源,你知道几个?

最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...

一张思维导图概括Python的基本语法, 一周的学习成果都在里面了

一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...

三日速成python?打工人,小心钱包,别当韭菜

随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...

Python自动化软件测试怎么学?路线和方法都在这里了

Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...

Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能

这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...

【黑客必会】python学习计划

阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...

公布了!2025CDA考试安排

CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...

一文搞懂全排列、组合、子集问题(经典回溯递归)

原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...

「西法带你学算法」一次搞定前缀和

我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...

平均数的5种方法,你用过几种方法?

平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...

【干货收藏】如何最简单、通俗地理解决策树分类算法?

决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...

面试必备:回溯算法详解

我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...

「机器学习」决策树——ID3、C4.5、CART(非常详细)

决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...

大话AI算法: 决策树

所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...