前言
原型有个东西,看着是几个功能组件的组合体;
想拆分成对应的组件(全部写在一起是贼恐怖的事情),又不想用Vuex
这类来实现。
那最终的方案就是Vue
的eventbus
了, 这只是一种方案的实现。
具体业务请具体分析是否可以用这个来维护多组件数据的通讯!
效果图
只展示部分功能,实际原型要复杂的多;
原型大体是这样的
实现原理
其实就是各个组件独立维护自己的状态,组件的默认值从外部传入;
而内部通过watch
在immediate
立即触发复制一份到data
,
再watch data
回调$emit
,而对于聚拢所有数据,我们就用event bus
来实现;
如何局部状态化,就用到了inject provide
了,在当前组件下provide
,该分支的所有子组件都能inject
;
ng
有这个概念,react
的context
也是差不多的玩意
代码参考
依旧如前两篇文章,基于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>