“干倒”尤雨溪

作为一个有梦想的前端。我们的目标是:
向尤雨溪学习,“干倒”尤雨溪。

又又又发现了一种开发组件的方式,虽然很多人已经这样开发了。但是作为菜鸡的发现者,依然觉得很香,之前说过通过遍历solt。然后劫持监听事件。然后通过ref进行组件的控制。这种方式,代码复杂,灵活性不高。

今天使用bus来封装组件。对你没听错,就是耳熟能详的bus(对于不知道bus的可以自己百度)。

其实使用bus是对于很多需求,很多联动组件。就需要使用bus来控制。本次就拿比较常见的。开始日期与结束日期来举例。

用法

    <StartDate v-model="startDate1" />
    <EndDate v-model="endDate1" />
效果图

StartDate组件

<template>
  <a-date-picker :placeholder="placeholder" :value="value" @change="change" valueFormat="YYYY-MM-DD" :disabled-date="disabledStartDate"
                 :disabled="disabled" :allowClear="allowClear"/>
</template>

<script lang="ts">
import {defineComponent, onUnmounted, ref, unref, watch} from "@vue/composition-api";
import moment from "moment";
import {$bus, START_VALUE, END_VALUE} from "./hooks/bus";

export default defineComponent({
  name: "StartDate",
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    placeholder: String,
    value: {
      type: String,
      required: true
    },
    /**
     * 开始日期的监听symbol 同组件中使用多个 开始日期组件。需要用传入不同的symbol
     */
    startSymbol: {
      type: Symbol,
      default: START_VALUE
    },
    /**
     * 结束日期的监听symbol 同组件中使用多个 结束日期组件。需要用传入不同的symbol
     */
    endSymbol: {
      type: Symbol,
      default: END_VALUE
    },
    disabled: {
      type: Boolean,
      default: false
    },
    allowClear: {
      type: Boolean,
      default: false
    },
    /**
     * 是否可以等于
     */
    eq: {
      type: Boolean,
      default: false
    }
  },
  setup(props, {emit}) {
    const endValue = ref('')

    const change = (value: string) => {
      emit('change', value)
    }

    watch(() => props.value, (value: string) => {
      setTimeout(() => $bus.$emit(props.startSymbol, value))
    }, {
      immediate: true
    })

    $bus.$on(props.endSymbol, (value: string) => {
      endValue.value = value;
    })

    const disabledStartDate = (startValue: string) => {
      if (!startValue || !unref(endValue)) {
        return false;
      }
      if(props.eq) {
        return moment(startValue).valueOf() > moment(unref(endValue)).valueOf();
      }
      return moment(startValue).endOf('day').valueOf() >= moment(unref(endValue)).endOf('day').valueOf();
    }

    onUnmounted(() => {
      $bus.$off(props.startSymbol)
      $bus.$off(props.endSymbol)
    })

    return {
      change,
      disabledStartDate,
      endValue
    }
  }
})
</script>

EndDate组件

<template>
  <a-date-picker :placeholder="placeholder" :value="value" @change="change" valueFormat="YYYY-MM-DD" :disabled-date="disabledEndDate"
                 :disabled="disabled" :allowClear="allowClear"/>
</template>

<script lang="ts">
import {defineComponent, onUnmounted, ref, unref, watch} from "@vue/composition-api";
import moment from "moment";
import {$bus, START_VALUE, END_VALUE} from "./hooks/bus";

export default defineComponent({
  name: "StartDate",
  model: {
    prop: 'value',
    event: 'change'
  },
  props: {
    placeholder: String,
    value: {
      type: String,
      required: true
    },
    startSymbol: {
      type: Symbol,
      default: START_VALUE
    },
    endSymbol: {
      type: Symbol,
      default: END_VALUE
    },
    disabled: {
      type: Boolean,
      default: false
    },
    allowClear: {
      type: Boolean,
      default: false
    },
    /**
     * 是否可以等于
     */
    eq: {
      type: Boolean,
      default: false
    }
  },
  setup(props, {emit}) {
    const startValue = ref('');

    const change = (value: string) => {
      emit('change', value)
    }

    watch(() => props.value, (value: string) => {
      setTimeout(() => $bus.$emit(props.endSymbol, value))
    }, {
      immediate: true
    })

    $bus.$on(props.startSymbol, (value: string) => {
      startValue.value = value;
    })

    onUnmounted(() => {
      $bus.$off(props.startSymbol)
      $bus.$off(props.endSymbol)
    })

    const disabledEndDate = (endValue: string) => {
      if (!endValue || !unref(startValue)) {
        return false;
      }
      if(props.eq) {
        return moment(unref(startValue)).endOf('day').valueOf() > moment(endValue).endOf('day').valueOf();
      }
      return moment(unref(startValue)).endOf('day').valueOf() >= moment(endValue).endOf('day').valueOf();
    }

    return {
      change,
      disabledEndDate,
      startValue
    }
  }
})
</script>

bus

// @ts-nocheck 为保持和vue2版本中使用bus一致,emit,on,off前面都加了$
export type EventType = string | symbol;
export type Handler<T = any> = (event: T) => void;
export type EventMap = { [key: EventType]: Array<Handler> };
class Bus {
    private readonly list: EventMap;
    constructor() {
        // 收集订阅信息,调度中心
        this.list = {} as EventMap;
    }

    // 订阅
    $on(name: EventType, fn: Handler) {
        this.list[name] = this.list[name] || [];
        this.list[name].push(fn);
    }

    // 发布
    $emit(name: EventType, data?: any) {
        if (this.list[name]) {
            this.list[name].forEach((fn: Handler) => {
                fn(data);
            });
        }
    }

    // 取消订阅
    $off(name: EventType) {
        if (this.list[name]) {
            delete this.list[name];
        }
    }
}
export default Bus;

You May Also Like

2 Comments

回复 一个辣椒 取消回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注