Vue 2.x折腾记 - (18) 用Vue的Inject Provide结合Event Bus来实现局部的状态维护

前言

原型有个东西,看着是几个功能组件的组合体;javascript

想拆分红对应的组件(所有写在一块儿是贼恐怖的事情),又不想用Vuex这类来实现。css

那最终的方案就是Vueeventbus了, 这只是一种方案的实现。html

具体业务请具体分析是否能够用这个来维护多组件数据的通信!vue

效果图

只展现部分功能,实际原型要复杂的多;java

原型大致是这样的react

实现原理

其实就是各个组件独立维护本身的状态,组件的默认值从外部传入;antd

而内部经过watchimmediate当即触发复制一份到data,ide

watch data回调$emit,而对于聚拢全部数据,咱们就用event bus来实现;flex

如何局部状态化,就用到了inject provide了,在当前组件下provide,该分支的全部子组件都能inject;ui

ng有这个概念,reactcontext也是差很少的玩意

代码参考

依旧如前两篇文章,基于antd design vue来实现的,固然还有部分自定义组件是本身封装的

因此呢,看看用法就好,通常来讲大家跑步起来

eventbus.js

import Vue from 'vue';
export const eventBus = new Vue();
复制代码

BasicSetting.vue(父组件)

记得在组件生命周期销毁!!这是个好习惯!!!

<template>
  <a-card :bodyStyle="{ position: 'relative' }">
    <template #extra>
      <btn-popconfirm size="default" :text="isEdit ? '关闭编辑' : '开启编辑'" :message="`肯定要${isEdit ? '关闭编辑' : '开启编辑'}续期配置?`" @change="onEdit" />
      <btn-popconfirm size="default" type="primary" text="肯定配置" :disabled="!isEdit" :message="`肯定要更新配置?操做需谨慎!`" @change="onUpdate" />
    </template>

    <div class="basic-setting">
      <a-col v-bind="{ xs: 24, sm: 24, md: 24, lg: 24, xxl: 6 }">
        <pivot-card :defaultValue="pivotData" :bordered="false" />
      </a-col>
      <a-col v-bind="{ xs: 24, sm: 24, md: 24, lg: 24, xxl: 18 }">
        <product-item />
      </a-col>
    </div>
    <div class="overlay" v-if="!isEdit" />
  </a-card>
</template>

<script> import PivotCard from './PivotCard'; import ProductItem from './ProductItem'; import { eventBus } from '@/utils/eventBus'; export default { name: 'BasicSetting', provide: function() { return { bus: eventBus }; }, components: { PivotCard, ProductItem }, created() { eventBus.$on('pivot', this.getPivotData); eventBus.$on('productItem', this.getProductItemData); }, beforeDestroy() { eventBus.$off('pivot'); }, data() { return { isEdit: false, // 是否开启编辑 pivotData: { // 基准信息 minMoney: 200, // 最低金额 maxMoney: 4000, // 最高金额 defaultAmount: 2000 // 默认额度 } }; }, methods: { onEdit(e) { // 开启关闭编辑 if (e) { this.isEdit = !this.isEdit; } }, onUpdate(e) { // 更新提交 }, getPivotData(e) { console.log('我是基准表单的值回调: ', JSON.stringify(e)); // 获取基准信息的回调 }, getProductItemData(e) { console.log('我是产品项的值回调: ', JSON.stringify(e)); } } }; </script>

<style lang="scss" scoped> .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(230, 229, 229, 0.24); z-index: 999; } </style>


复制代码

PivotCard.vue子组件

<template>
  <a-card>
    <template #title>
      最低金额、最高金额、默认额度
    </template>
    <a-row type="flex" justify="start" align="middle" style="margin:10px 0;">
      <a-col :sm="24" :md="10">
        <span style="padding:5px 0">最低金额</span>
      </a-col>
      <a-col :sm="24" :md="14">
        <a-input-number :min="0" v-model="fields.minMoney" :formatter="value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')" :parser="value => value.replace(/\¥\s?|(,*)/g, '')" />
      </a-col>
    </a-row>
    <a-row type="flex" justify="start" align="middle" style="margin:10px 0;">
      <a-col :sm="24" :md="10"> <span style="padding:5px 0">最高金额</span></a-col>
      <a-col :sm="24" :md="14">
        <a-input-number :min="0" :formatter="value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')" :parser="value => value.replace(/\¥\s?|(,*)/g, '')" v-model="fields.maxMoney" />
      </a-col>
    </a-row>
    <a-row type="flex" justify="start" align="middle" style="margin:10px 0;">
      <a-col :sm="24" :md="10"> <span style="padding:5px 0">默认额度</span></a-col>
      <a-col :sm="24" :md="14">
        <a-input-number :min="0" :max="100" v-model="fields.defaultAmount" :formatter="value => `¥ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')" :parser="value => value.replace(/\¥\s?|(,*)/g, '')" />
      </a-col>
    </a-row>
  </a-card>
</template>

<script> export default { inject: ['bus'], data() { return { fields: {} }; }, props: { defaultValue: { // 默认值 type: Object, default: function() { return { minMoney: 200, maxMoney: 4000, defaultAmount: 2000 }; } } }, watch: { defaultValue: { // 把默认值初始化了 immediate: true, deep: true, handler(newValue, oldValue) { if (newValue) { this.fields = newValue; } } }, fields: { // 监听变更回调给父 immediate: true, deep: true, handler(newValue, oldValue) { console.log('newValue, oldValue: ', newValue, oldValue); if (newValue) { this.bus.$emit('pivot', newValue); } } } } }; </script>

<style lang="scss" scoped> .ant-input-number { min-width: 150px; } </style>

复制代码

总结

到这里,咱们结合Vue提供的一些特性实现了,可能某些特性有些小伙伴用的少;

这里有用到新的slot语法,还有比较冷门的provide | inject;

有不对之处请留言,会及时修正,谢谢阅读

相关文章
相关标签/搜索