Vue中使用派发器编写计算器组件

277 阅读1分钟

Vue中使用派发器编写计算器组件

    <!-- src/components/calculator/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' :currMethod='currMethod' @dispatch='dispatch' />
                <cal-button innerText='-' method='minus' :currMethod='currMethod' @dispatch='dispatch' />
                <cal-button innerText='*' method='mul' :currMethod='currMethod' @dispatch='dispatch' />
                <cal-button innerText='/' method='div' :currMethod='currMethod' @dispatch='dispatch' />
            </div>
        </div>
    </template>

    <script>
    import CalResult from './Result'
    import CalInput from './Input'
    import CalButton from './Button'

    import dispatch from '@/dispatchers/calculator';

    export default {
        name: 'CalCulator',
        components: {
            CalResult,
            CalInput,
            CalButton
        },
        data () {
            return {
                firstNumber: 0,
                secondNumber: 0,
                result: 0,
                currMethod: 'plus'
            }
        },
        methods: {
            dispatch (...args) {
                dispatch(this)(...args);
            }
        }
    }
    </script>
    <!-- src/components/calculator/Result.vue -->
    <template>
        <h1>{{result}}</h1>
    </template>
    <script>
    export default {
        name: 'CalResult',
        props: {
            result: Number
        }
    }
    </script>
    <!-- src/components/calculator/Input.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);
                this.$emit('dispatch', 'SET_NUMBER', this.field, val);
            }
        }
    }
    </script>
    <!-- src/components/calculator/Button.vue -->
    <template>
        <button :method='method' :class='{current: method === currMethod}' @click='changeMethod'>
            {{innerText}}
        </button>
    </template>

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

    <style>
        .current {
            background-color: orange;
            color: #fff;
        }
    </style>
    <!-- src/actions/calculator.js -->
    const SET_NUMBER = 'SET_NUMBER';
    const CHANGE_METHOD = 'CHANGE_METHOD';

    export {
        SET_NUMBER,
        CHANGE_METHOD
    }
    <!-- src/reducers/calculator.js -->
    import { compute } from '@/libs/utils';

    function calculatorReducers (data) {
        function setNumber (field, value) {
            if (typeof(value) !== number) {
                value = Number(value);
            }
            
            data[field] = value;
            return compute(data.currMethod, data.firstNumber, data.secondNumber);
        }
        function changeMethod (method) {
            data.currMethod = method;
            return compute(data.currMethod, data.firstNumber, data.secondNumber);
        }

        return {
            setNumber,
            changeMethod
        }
    }

    export default calculatorReducers;
    <!-- src/dispatchers/calculator.js -->
    import calculatorReducers from '@/reducers/calculator';
    import { SET_NUMBER, CHANGE_METHOD } from '@/actions/calculator';

    export default (ctx) => {
        const {
            setNumber,
            changeMethod
        } = calculatorReducers(ctx.$data);

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