vue 组件数据共享

As a company, we sell experiences on many different sales channels, gotui.com, musement.com, travel agencies platforms, onsite tour operator web-applications, etc. All of these platforms consume REST APIs and share common business logic: product pages, product listings, search pages, checkout, orders listings, login, account, etc.

作为一家公司,我们在许多不同的销售渠道上销售经验,包括gotui.com , musement.com ,旅行社平台,现场旅行社网络应用程序等。所有这些平台都使用REST API并共享通用的业务逻辑:产品页面,产品列表,搜索页面,结帐,订单列表,登录名,帐户等。

Rewriting and maintaining this logic for every project requires a lot of effort so we faced a big challenge: how do we develop blocks that are easy to plug-in but flexible enough to satisfy the different business requirements of our platforms? And how do we sync all these blocks?

为每个项目重写和维护此逻辑都需要大量的工作,因此我们面临一个巨大的挑战:我们如何开发易于插入但足够灵活以满足我们平台不同业务需求的模块? 以及我们如何同步所有这些块?

故事 (The story)

It was an exciting road to reach our current architecture.

这是达到我们当前架构的令人兴奋的道路。

It started after delivering our second web-application: we noticed a lot of copy-paste work and difficulties syncing new features and bug fixes on both applications at the same time.

它是在交付第二个Web应用程序之后开始的:我们注意到很多复制粘贴工作,并且难以同时在两个应用程序上同步新功能和错误修复。

In front of the coffee machine, we started our first meetings and the paper board became the place where we shared ideas and concepts.

在咖啡机前,我们开始了第一次会议,纸板成为了我们分享想法和概念的地方。

During Tech-Fridays, we developed the first PoCs, and finally, step by step, the architecture came out naturally and, more important, every member of the team contributed to it.

在Tech-Friday期间,我们开发了第一个PoC,最后,一步一步地,架构自然而然地诞生了,更重要的是,团队的每个成员都为此做出了贡献。

We ended up with a NuxtJS application that consumes Vue components imported as npm packages. Like LEGO® Technic™ kits, given a set of customizable blocks (shared-components), we can build many different vehicles (our platforms).

我们最终得到了一个NuxtJS应用程序,该应用程序使用作为npm软件包导入的Vue组件。 与乐高®Technic™套件一样,给定一组可定制的块(共享组件),我们可以制造许多不同的车辆(我们的平台)。

汇总构建 (Building with Rollup)

Having customizable components means that not all features and blocks are always used, so we need to be sure that only the necessary parts are imported. To do that we rely on the tree-shaking feature that removes unused code from the final bundled files.

具有可定制的组件意味着并非总是使用所有功能和块,因此我们需要确保仅导入必要的部分。 为此,我们依赖于摇树功能,该功能可从最终的捆绑文件中删除未使用的代码。

Since NuxtJS uses Webpack as the final bundling tool, the only way to allow Webpack to efficiently perform the tree-shaking is to provide ESM modules. Given that, we choose to build our shared-components with Rollup: Webpack will provide that type of output only with Version 5. Moreover, it’s very easy to understand what Rollup is doing under the hood and thanks to that writing custom plugins was really straightforward.

由于NuxtJS使用Webpack作为最终的捆绑工具,因此允许Webpack有效执行摇树的唯一方法是提供ESM模块 。 鉴于此,我们选择使用Rollup构建共享组件:Webpack仅在Version 5中提供该类型的输出。 此外,很容易理解Rollup在后台进行的操作,而且由于编写自定义插件非常简单。

Another benefit of Rollup t is that in our context the bundled files are 30–40% smaller compared to the Webpack ones.

Rollup t的另一个好处是,在我们的上下文中,捆绑的文件比Webpack的文件小30–40%。

通过商店沟通 (Communication via store)

Our shared-components expose different blocks so that the consuming application (we call it ‘orchestrator’) can choose to use only the ones required.

我们的共享组件公开了不同的块,因此使用中的应用程序(我们称为“协调器”)可以选择仅使用所需的那些。

Imagine a search-component: it exposes a listing, a filters block, and a search bar; in our orchestrator, we can decide to use only the listing and the input:

想象一下搜索组件:它公开一个清单,一个过滤器块和一个搜索栏; 在我们的协调器中,我们可以决定仅使用清单和输入:

import { SearchListing, SearchBar } from ‘@musement/search-component’;

But if they’re different components how do they sync the data? The search-component uses a vuex store module that is registered inside the orchestrator thanks to the registerModule method.

但是,如果它们是不同的组件,则如何同步数据? 搜索组件使用vuex存储模块,该模块在orchestrator内部注册,这要归功于registerModule方法 。

orchestratorStore.registerModule(‘searchStoreNamespace’, searchComponentStoreModule, { preserveState: false });

We set the preserveState to false because the search-component has its own store default state and the consumer knows nothing about it.

我们将preserveState设置为false,因为搜索组件具有其自己的商店默认状态,而使用者对此一无所知。

After the registration the SearchBar dispatches an action that fetches the data and stores the response:

注册后, SearchBar调度一个操作,该操作将获取数据并存储响应:

<template> <form v-on:submit.prevent="onSubmit">   <input v-model="text" placeholder="Search for activities…" />   <button type="submit">Search</button> </form></template>...export default Vue.extend({ name: 'SearchBar', data() {   return {     text: ''   } }, methods: {   onSubmit() {     this.$store.dispatch(       'searchStoreNamespace/fetchActivities',        { this.text }     );   }, },})

After the API response the SearchListing is able to show the fetched activities:

API响应后, SearchListing能够显示提取的活动:

<template>  <ul>    <li v-for="activity in activities" :key="activity.uuid">      {activity.name}    </li>  </ul></template>...export default Vue.extend({  name: 'SearchListing',  computed: {    ...mapGetters('searchStoreNamespace', [ 'activities' ]),  },})

建立 (Setup)

Since our shared-components can be composed by different blocks that communicate via a vuex-store module, passing Vue props directly from the orchestrator to the components would lead us to a lot of code duplication. For that reason, we decided to expose a setup method where we set customizable data directly inside the store, avoiding all the parent-child tree traversing.

由于我们的共享组件可以由通过vuex-store模块进行通信的不同块组成,因此将Vue道具直接从协调器传递到组件将导致我们重复很多代码。 因此,我们决定公开一种设置方法,在该方法中,我们直接在商店内部设置可自定义的数据,避免遍历所有父子树。

import { setup } from '@musement/search-component';setup(consumerStoreInstance, {  apiBaseURL: 'https://api.musement.com',  language: 'en-GB',  currency: 'GBP',  ...})

We need the consumerStoreInstance because the store module registration is performed inside the shared-component itself so that the consumer doesn’t need to be aware of that.

我们需要ConsumerStoreInstance,因为商店模块注册是在共享组件本身内部执行的,因此消费者不需要知道这一点。

NuxtJs的服务器端渲染 (Server-Side Rendering with NuxtJs)

Due to SEO requirements, most of our applications use Server-Side Rendering provided by NuxtJS.

由于SEO的要求,我们的大多数应用程序都使用NuxtJS提供的服务器端渲染 。

In those cases, we need to display crawlers relevant data after an API call so we expose an initialDispatch function that is called inside the NuxtJS fetch method.

在这些情况下,我们需要在API调用之后显示搜寻器的相关数据,以便公开在NuxtJS fetch方法内部调用的initialDispatch函数。

After that, we need to ensure that the vuex-store gets hydrated browser side with the same new data. We do that with a hydrate method that registers the store module on the client too.

之后,我们需要确保vuex存储在浏览器端具有相同的新数据。 我们使用可在客户端上注册存储模块的hydrate方法来做到这一点。

import { initialDispatch, hydrate } from '@musement/activity-component';export default {  name: 'ActivityPage',  async fetch({ store }) {    const activityUuid = store.state.activityPage.uuid;    initialDispatch(store, activityUuid);  },  beforeCreate() {    if (process.client) {      hydrate(this.$store);    }  }}

事件总线 (Event-bus)

As we said before our shared-components are black-boxes, but imagine we have our imported SearchListing, how do we inform the orchestrator that client-side navigation needs to be performed?

如前所述,共享组件是黑匣子,但是假设我们导入了SearchListing ,如何通知协调器需要执行客户端导航?

The way we communicate from the shared-components to the consumers is via an event-bus with a documented API. We create and expose it inside the shared-component:

我们从共享组件与使用者进行通信的方式是通过带有文档化API的事件总线。 我们在共享组件内部创建并公开它:

import Vue from 'vue';const eventBus = new Vue();export default {  $emit(eventName, eventPayload) {    eventBus.$emit(eventName, eventPayload);  },  $on(eventName, eventHandler) {    eventBus.$on(eventName, eventHandler);  },  $off(eventName, eventHandler) {    eventBus.$off(eventName, eventHandler);  },};

Inside the listing, we $emit a Vue event.

里面的上市,我们$ EMI吨Vue的事件 。

<template>  <ul>    <li v-for="activity in activities" :key="activity.uuid">      <h3>        <a          :href="activity.url"          @click.prevent="onActivityClick(activity.uuid)">            {activity.name}        </a>      </h3>    </li>  </ul></template>...import EventBusSearch from './eventBus';export default Vue.extend({  name: 'SearchListing',  computed: {    ...mapGetters('searchStoreNamespace', [ 'activities' ]),  },  methods: {    onActivityClick(uuid: string) {      EventBusSearch.$emit('onNavigation', { uuid });    }  },})

And finally, we listen to that event inside the orchestrator and remove it when the page will be destroyed.

最后,我们在协调器内部侦听该事件,并在页面被破坏时将其删除。

import { SearchListing, EventBusSearch } from '@musement/search-component';export default {  name: 'SearchPage',  ...  beforeMount() {    EventBusSearch.$on('onNavigation', this.onNavigation);  },  beforeDestroy() {    EventBusSearch.$off('onNavigation', this.onNavigation);  },  methods: {    onNavigation({ uuid }) {      this.$router.push({ name: 'activity', params: { uuid } });    }  }}

CSS主题 (CSS theming)

As blocks plugged inside different applications, our shared-components need to adapt to the overall look-and-feel of the context, especially to the colours palette.

随着将块插入不同的应用程序中,我们的共享组件需要适应上下文的整体外观,尤其是调色板。

To achieve that, we accept a theme property inside the config argument of the setup function:

为此,我们在setup函数的config参数中接受一个theme属性:

import { setup } from '@musement/search-component';setup(consumerStoreInstance, {  theme: {    name: 'musement',    vars: {      '--fontPrimary': 'Gill Sans, sans-serif;',    },  },  ...})

With the name property, the consumer can use one of the premade themes, and with the vars prop, it can override specific CSS variables; both are optional.

使用name属性,使用者可以使用预制主题之一,而使用vars prop可以覆盖特定CSS变量。 两者都是可选的。

Then, inside the shared-component, we set the theme in the store via a mutation, with a default fallback (in this case the theme ‘musement’):

然后,在共享组件内部,我们通过突变在商店中设置了主题,并具有默认后备(在本例中为主题“ musement”):

const themes = {  musement: {    '--primaryColor': 'red',    '--fontPrimary': 'Arial, sans-serif',  },  blueTheme: {    '--primaryColor': 'blue',    '--fontPrimary': 'Tahoma, sans-serif',  }}export default {  [SET_THEME](state, theme) {    state.theme = {      ...themes[theme.name || 'musement'],      ...(theme.vars || {}),    }  },}

Finally, we apply the CSS variables directly to the root element of the shared-component:

最后,我们将CSS变量直接应用于共享组件的根元素:

<template>  <div class="activityComponent" :style="theme">    <h1>{ activity.title }</h1>    ...  </div></template>...export default Vue.extend({  name: 'activityComponent',  computed: {    ...mapGetters('searchStoreNamespace', [ 'theme', 'activity' ]),  },})...<style lang="scss">.activityComponent {  font-family: var(--fontPrimary);  h1 {    color: var(--primaryColor);  }}</style>

结论 (Conclusion)

As you’ve probably noticed here we’ve only scraped the surface of the possibilities and we know, as a frontend team, that we’re only at the beginning of a long and thrilling journey; we are still faced with many challenges, like:

正如您可能已经在这里注意到的那样,我们只是探讨了可能性的表面,并且我们知道,作为前端团队,我们才刚刚开始漫长而激动的旅程; 我们仍然面临许多挑战,例如:

  • Efficiently manage shared-components inside shared-components有效管理共享组件内部的共享组件
  • Dynamic import based on feature flags基于功能标记的动态导入
  • Properly take in sync dependencies across the different platforms在不同平台上正确获取同步依赖项
  • Develop a light CSS library to reduce styles duplication and obtain layout consistency between our applications开发一个轻量级CSS库以减少样式重复并在我们的应用程序之间获得布局一致性

But these challenges are there to let us learn day after day better ways to provide valuable applications for our customers and, hopefully, contribute to the developer’s community with shareable solutions.

但是这些挑战使我们日复一日学习更好的方法来为我们的客户提供有价值的应用程序,并希望通过可共享的解决方案为开发人员社区做出贡献。

See you soon with the next chapter of this story, stay tuned!

很快就会看到这个故事的下一章,敬请期待!

翻译自: https://medium.com/tuidx/vue-shared-components-2c40973c32c5

vue 组件数据共享


http://www.taodudu.cc/news/show-6454091.html

相关文章:

  • Vue初识
  • Android 与Vue 页面交互
  • 新书上市 | Vue 3.0 核心源码解析,这本书给Vue学习提供新方法
  • UE4 材质切换(带动画效果)
  • UE4 下雪特效(特效)
  • 用ue4怎么制作一个物体故障闪烁的特效
  • 我所用的一些linux常见命令
  • Acer 4750 安装黑苹果_zx50jx4200安装黑苹果的辛酸路
  • 【转】NAS 黑群晖 配置完成(不含硬盘),NAS能做什么?
  • [work]Hackintosh
  • 单纯水帖
  • 别看,水帖!
  • XShell 还是 FinalShell?
  • el-date-picker限制只能选当天,当天之前,当天之后
  • 使用CSS连接数据库
  • 水一贴
  • [USACO19DEC]Moortal Cowmbat G 真牛快打
  • hexo+github搭建个人博客网站问题汇总和解决办法
  • 投稿贴
  • 关于在python中安装turtle出现的一些问题
  • iis某狗注入绕过(get)
  • 发帖水王
  • 第一帖,水贴
  • 发现水贴(算法入门题目003)
  • 无线传感器网络(特点,挑战和应用)
  • 无线传感器网络体系结构
  • 无线传感器网络(WSN)在各个领域的应用分析
  • C++编程练习-员工上下班
  • 职场人怎么提醒自己下班打卡?
  • java判断一个月连续打卡时间_java并发编程实战《五》死锁 挑战打卡60天

vue 组件数据共享_Vue共享组件相关推荐

  1. vue 递归组件多级_Vue递归组件实现树形结构菜单

    Tree 组件是递归类组件的典型代表,它常用于文件夹.组织架构.生物分类.国家地区等等,世间万物的大多数结构都是树形结构.使用树控件可以完整展现其中的层级关系,并具有展开收起选择等交互功能. 如图所示 ...

  2. vue 父链和子组件索引_vue子组件和父组件双向绑定的几种方案

    v-model案例 模仿v-model实现案例 我是一串要和内部名字联动的一串文字(父组件) 父组件改变值带动(父组件)点一下试试 .sync方案实现案例 这是父组件的东西.利用这个框改变值,看看有没 ...

  3. vue变量传值_Vue各类组件之间传值的实现方式

    1.父组件向子组件传值 首先在父组件定义好数据,接着将子组件导入到父组件中.父组件只要在调用子组件的地方使用v-bind指令定义一个属性,并传值在该属性中即可,此时父组件的使命完成,请看下面关键代码: ...

  4. vue template 复用_Vue之组件、路由

    组件: 组件系统是Vue.js其中一个重要的概念,它提供了一种抽象,让我们可以使用独立可复用的小组件来构建大型应用,任意类型的应用界面都可以抽象为一个组件树.(通俗点讲,如果你在页面上需要显示4个物品 ...

  5. vue 递归组件多级_Vue 递归组件构建一个树形菜单

    原标题:Vue 递归组件构建一个树形菜单 Vue.js 中的递归组件是一个可以调用自己的组件例如: Vue.component('recursive-component', { template: ` ...

  6. vue项目通讯录_vue 自定义组件实现通讯录功能

    在线demo:http://tangyupeng.top/dist/index.html#/phone 首页 + 确认 取消 import Vue from 'vue'; import Vuex fr ...

  7. vue 父组件调子组件方法_vue父组件调用子组件有哪些方法

    这次给大家带来vue父组件调用子组件有哪些方法,vue父组件调用子组件的注意事项有哪些,下面就是实战案例,一起来看一下. 情景: 父组件中引入上传附件的子组件:点击组件可以分别上传对应要求的图片,子组 ...

  8. 子组件调用父组件方法_vue父子组件通信以及非父子组件通信的方法

    组件是 vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用.一般来说,组件可以有以下几种关系,父子关系.兄弟关系和隔代关系,简化点可以分为父子关系和 ...

  9. js 操作vuex数据_Vue.js中使用Vuex实现组件数据共享案例

    当组件中没有关联关系时,需要实现数据的传递共享,可以使用Vuex 先不管图片 一.安装 在vue cli3中创建项目时勾选这个组件就可以了 或者手动安装 npm install store --sav ...

最新文章

  1. Oracle Study--RAW Device在Oracle下的应用
  2. java导出pdf集合_java实现导出pdf-Go语言中文社区
  3. Android 软键盘的全面解析,让你不再怕控件被遮盖
  4. OpenMap教程4 –图层
  5. 大神手把手教你设计秒杀架构模型
  6. 【论文复现】ReLU、Leaky ReLU、PReLU、RReLU实验对比(2015)
  7. 2021年中国石油市场回顾及2022年行业发展趋势分析预测:2021年石油需求震荡修复,石油对外依存度首次下降,预计2022年石油需求7.35亿吨[图]
  8. 【Antd】Pagination中的current和pageSize参数自动同步到url当中
  9. html常用js统计图表插件
  10. 图书 计算机功能室寄语,学校各功能室解说词
  11. 生成的包含卫兵:一次替代实用主义
  12. 音频录制(react)
  13. tic-tac-toe游戏(简单判断)
  14. Unity 网络请求
  15. Android Zxing3.3.2扫描、生成、解析二维码,以及近距离无法识别的问题
  16. -1岁的产品经理日记——part2(笔经,群面篇)
  17. OpenThreads库介绍——Block
  18. SaaS的本质其实是和网络游戏一样的
  19. C#之:线程同步 Monitor类
  20. 暗影精灵4适合计算机专业,暗影精灵4评测_暗影精灵4代怎么样|值得买吗-太平洋电脑网...

热门文章

  1. 新材料与我们有什么关系:盘点走进生活的新材料
  2. 物理大地测量学笔记(一)
  3. 欧姆龙r88d系列服务器说明书,欧姆龙R88D/R88M选型使用手册(中文)
  4. 重新开张,谢天谢地。
  5. 5年!我对OpenStack的一些看法
  6. 关于primarykey 和key的注意事项
  7. 【软件工程】六、软件配置管理
  8. WPF实现MDI窗体的方法
  9. 推荐8个免费建站、域名或虚拟主机
  10. Golang实现并发版网络爬虫:豆瓣-电影名人数评分爬取并保存文件