第十八章-派发器计算器(二)

28 阅读1分钟

不用派发器的目录如下

image.png

pages/Index.vue

<template>
    <div id="app">
      <Calculator />
    </div>
  </template>
  
<script>
  import Calculator from '@/components/Calculator/index.vue'
  
  export default {
    name: 'PageIndex',
    components: {
      Calculator
    }
  }
</script>

Calculator目录

  • index.vue
<template>
  <div>
    <cal-result :result="result" />
    <div class="inputs">
      <cal-input field="firstNumber" @setNumber="setNumber"/>
      <cal-input field="secondNumber" @setNumber="setNumber"/>
    </div>
    <div class="buttons">
      <cal-button innerText="+" method="plus" :curMethod="curMethod" @changeMethod="changeMethod"/>
      <cal-button innerText="-" method="minus" :curMethod="curMethod" @changeMethod="changeMethod"/>
      <cal-button innerText="*" method="mul" :curMethod="curMethod" @changeMethod="changeMethod"/>
      <cal-button innerText="/" method="div" :curMethod="curMethod" @changeMethod="changeMethod"/>
    </div>
  </div>
</template>

<script>
import CalResult from "./CalResult.vue";
import CalInput from "./CalInput.vue";
import CalButton from "./CalButton.vue";

export default {
  name: "Calculator",
  components: {
    CalResult,
    CalInput,
    CalButton,
  },
  data() {
    return {
      result: 0,
      firstNumber: 0,
      secondNumber: 0,
      curMethod: 'plus'
    };
  },
  methods: {
    compute(method, fNumber, sNumber) {
        switch (method) {
            case 'plus':
                return fNumber + sNumber;
            case 'minus':
                return fNumber - sNumber;
            case 'mul':
                return fNumber * sNumber;
            case 'div':
                return fNumber / sNumber;       
            default:
                break;
        }
    },
    setNumber(field, value) {
        this[field] = value;
        this.setResult();
    },
    changeMethod(method) {
        this.curMethod = method;
        this.setResult();
    },
    setResult() {
        this.result = this.compute(this.curMethod, this.firstNumber, this.secondNumber);
    }
  }
};
</script>
<style scoped>
.inputs {
    margin-bottom: 8px;
}
</style>
  • CalResult.vue
<template>
    <h1>{{ result }}</h1>
</template>
<script>
  export default {
    name: "CalResult",
    props: {
      result: {
        type: Number,
        default: 0,
      },
    },
  };
</script>
  • CalInput.vue
<template>
    <input 
        type="text"
        value="0"
        @input="setNumber"
    />
</template>

<script>
export default {
    name: "CalInput",
    props: {
        field: String
    },
    methods: {
        setNumber(e) {
            const val = Number(e.target.value || 0);
            this.$emit('setNumber', this.field, val);
        }
    }
}
</script>
  • CalButton.vue
<template>
    <button
        :method="method"
        :class="{current: method === curMethod}"
        @click="changeMethod"
    >
        {{ innerText }}
    </button>
</template>

<script>
export default {
    name: "CalButton",
    props: {
        method: String,
        curMethod: String,
        innerText: String
    },
    methods: {
        changeMethod() {
            this.$emit('changeMethod', this.method);
        }
    }
}
</script>

<style scoped>
.current {
    background-color: yellow;
}
</style>

image.png

用派发器进行改造

新增文件夹目录如下: image.png actions/calculator.js

const SET_NUMBER = 'SET_NUMBER';
const CHANGE_METHOD = 'CHANGE_METHOD';

export {
    SET_NUMBER,
    CHANGE_METHOD
}

reducers/calculator.js

import { compute } from "@/libs/utils";
function calculatorReducer(data) {// data就是组件实例对象
  function setNumber(field, value) {
    data[field] = value;
    return compute(
        data.curMethod, 
        data.firstNumber, 
        data.secondNumber
    );
  }

  function changeMethod(method) {
    data.curMethod = method;
    return compute(
        data.curMethod, 
        data.firstNumber, 
        data.secondNumber
    );
  }

  return {
    setNumber,
    changeMethod,
  };
}

export default calculatorReducer;

dispatch/calculator.js

import reducer from '@/reducers/calculator';
import {
    SET_NUMBER,
    CHANGE_METHOD
} from '@/actions/calculator';

export default (ctx) => {
    const { setNumber, changeMethod } = reducer(ctx);

    return function(type, ...args) {
        switch(type) {
            case SET_NUMBER:
                ctx.result = setNumber(...args);
                break;
            case CHANGE_METHOD:
                ctx.result = changeMethod(...args);
                break;
            default:
                break;
        }
    }
}

libs/utils.js

function compute(method, fNumber, sNumber) {
  switch (method) {
    case "plus":
      return fNumber + sNumber;
    case "minus":
      return fNumber - sNumber;
    case "mul":
      return fNumber * sNumber;
    case "div":
      return fNumber / sNumber;
    default:
      break;
  }
}

export {
    compute
}

接下来就是使用了

  • 先对组件进行改造一下, todo部分就是修改的部分

CalInput.vue

<template>
    <input 
        type="text"
        value="0"
        @input="setNumber"
    />
</template>

<script>
import { SET_NUMBER } from '@/actions/calculator';// todo
export default {
    name: "CalInput",
    props: {
        field: String
    },
    methods: {
        setNumber(e) {
            const val = Number(e.target.value || 0);
            // todo
            this.$emit('dispatch', SET_NUMBER, this.field, val);
        }
    }
}
</script>

CalButton.vue

<template>
    <button
        :method="method"
        :class="{current: method === curMethod}"
        @click="changeMethod"
    >
        {{ innerText }}
    </button>
</template>

<script>
import { CHANGE_METHOD } from '@/actions/calculator';// todo
export default {
    name: "CalButton",
    props: {
        method: String,
        curMethod: String,
        innerText: String
    },
    methods: {
        changeMethod() {
            // todo
            this.$emit('dispatch', CHANGE_METHOD, this.method);
        }
    }
}
</script>

<style scoped>
.current {
    background-color: yellow;
}
</style>

index.vue中使用

<template>
  <div>
    <cal-result :result="result" />
    <div class="inputs">
      <cal-input field="firstNumber" @dispatch="dispatch"/>
      <cal-input field="secondNumber" @dispatch="dispatch"/>
    </div>
    <div class="buttons">
      <cal-button innerText="+" method="plus" :curMethod="curMethod" @dispatch="dispatch"/>
      <cal-button innerText="-" method="minus" :curMethod="curMethod" @dispatch="dispatch"/>
      <cal-button innerText="*" method="mul" :curMethod="curMethod" @dispatch="dispatch"/>
      <cal-button innerText="/" method="div" :curMethod="curMethod" @dispatch="dispatch"/>
    </div>
  </div>
</template>

<script>
import CalResult from "./CalResult.vue";
import CalInput from "./CalInput.vue";
import CalButton from "./CalButton.vue";
import dispatch from '@/dispatch/calculator';

export default {
  name: "Calculator",
  components: {
    CalResult,
    CalInput,
    CalButton,
  },
  data() {
    return {
      result: 0,
      firstNumber: 0,
      secondNumber: 0,
      curMethod: 'plus'
    };
  },
  methods: {
    dispatch(...args) {
        dispatch(this)(...args);
    }
  }
};
</script>
<style scoped>
.inputs {
    margin-bottom: 8px;
}
</style>

image.png