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;

有不對之處請留言,會及時修正,謝謝閱讀

相關文章
相關標籤/搜索