ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت — از صفر تا صد

۲۶۵ بازدید
آخرین به‌روزرسانی: ۰۷ شهریور ۱۴۰۲
زمان مطالعه: ۱۱ دقیقه
ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت — از صفر تا صد

ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت یکی از بهترین مثال‌های کاربردی برای آشنایی با این زبان برنامه‌نویسی محسوب می‌شود. ما هرگز یک زبان برنامه‌نویسی را به خوبی یاد نخواهیم گرفت، مگر این که شخصاً چیزی را با آن بسازیم. بنابراین با ما همراه باشید تا با بررسی یک مثال عملی با این زبان بیشتر آشنا شویم. در این مقاله فرض شده است که خواننده محترم دانشی ابتدایی از HTML ‌،CSS ،Bootstrap 4 و جاوا اسکریپت دارد.

مقدمه‌ای بر ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت

ما در این راهنما قصد داریم یک اپلیکیشن جاوا اسکریپت طراحی کنیم که با استفاده از آن بتوانیم میزان مصارف هزینه‌ای یک فرد را در طی بازه‌های مشخصی اندازه‌گیری کرده و بفهمیم که چه مقدار از درآمد فرد صرف پس‌انداز، چه مقدار صرف سرمایه‌گذاری و چه مقدار هزینه شده است.

طراحی رابط کاربری اپلیکیشن مدیریت هزینه

نخستین مرحله‌ی کار، طراحی یک UI برای اپلیکیشن مدیریت هزینه است. شما می‌توانید از ایده‌های خود استفاده کنید و یا سری به وب‌سایت‌های Dribbble یا Behance بزنید تا ایده‌ای از طراحی‌های مختلف به دست آورید. برای ایجاد UI می‌توانید از نرم‌افزار Figma استفاده کنید. دلیل این که کار را از طراحی UI آغاز می‌کنیم این است که کدنویسی ساده‌تر است. انتخاب یک طراحی موجب می‌شود که تفکر شما نظم و سازمان‌دهی پیدا کند و در نتیجه سرعت توسعه اپلیکیشن افزایش می‌یابد.

ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت

کدهای HTML موردنیاز

در ادامه کار خود را با ایجاد یک فایل index.html در پوشه پروژه آغاز می‌کنیم. ابتدا باید بوت‌استرپ را به پروژه خود اضافه کنید. به این منظور می‌توانید از راهنمایی‌های مستندات رسمی آن (+) بهره بگیرید. همچنین ما از فونت Open Sans برای طراحی ظاهر بهتر استفاده می‌کنیم. این گزینه کاملاً اختیاری است.

اکنون که اسکریپت‌ها آماده است، اقدام به تحلیل طراحی خود می‌کنیم. برای شروع باید دو کانتینر داشته باشیم که کانتینر آبی در سمت چپ حدود 40% فضای صفحه را اشغال و کانتینر سمت راست بقیه صفحه را پر می‌کند. پیاده‌سازی این حالت به کمک Bootstrap Grid کار آسانی است. در ادامه کار خود را با کانتینر آبی سمت راست آغاز می‌کنیم. کد HTML ما به شکل زیر است:

1<!DOCTYPE html>
2<html lang="en">
3<head>
4    <meta charset="UTF-8">
5    <title>Expense Manager</title>
6    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
7          integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
8    <link rel="stylesheet" href="style.css">
9    <link href="https://fonts.googleapis.com/css2?family=Open+Sans:wght@400;700&display=swap" rel="stylesheet">
10    <link href="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.css" rel="stylesheet">
11    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
12            integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
13            crossorigin="anonymous"></script>
14    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
15            integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
16            crossorigin="anonymous"></script>
17    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
18            integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
19            crossorigin="anonymous"></script>
20    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js" crossorigin="anonymous"></script>
21
22</head>
23<body>
24<div class="row">
25    <div class="col-4 left-container">
26        <div class="month-container">
27            <div class="header fs-white">Your Budget</div>
28            <div id="current-month" class="sub-text fs-white"></div>
29            <div class="budget-container p-2 mt-4">
30                <span id="month-budget" class="month-amount">0</span>
31            </div>
32        </div>
33
34        <div class="chart-container">
35            <canvas id="expense-chart"></canvas>
36        </div>
37    </div>
38    <div class="col-8 right-container">
39        <div class="calc-container">
40            <div class="header fs-dark-grey">Track Your Budget</div>
41            <div class="dropdown open">
42                <button class="btn btn-info dropdown-toggle"
43                        type="button" id="dropdownMenu3" data-toggle="dropdown"
44                        aria-haspopup="true" aria-expanded="false">
45                    Expense Type
46                </button>
47                <div class="dropdown-menu">
48                    <a class="dropdown-item" id="type-savings">Savings</a>
49                    <a class="dropdown-item" id="type-expense">Expense</a>
50                    <a class="dropdown-item" id="type-investment">Investment</a>
51                </div>
52            </div>
53            <div class="mt-3 tracking-text text-capitalize sub-text bottom-border">Tracking Savings ?</div>
54
55            <div class="row mt-4">
56                <div class="col-7">
57                    <input class="form-control input-expense-description" type="text" placeholder="Description">
58                </div>
59                <div class="col-4">
60                    <input class="form-control input-expense-value" type="number" placeholder="Value">
61                </div>
62                <div class="col-1">
63                    <button type="button" class="btn btn-success btn-submit-expense"></button>
64                </div>
65            </div>
66            <div class="expense-list mt-4">
67
68            </div>
69
70        </div>
71    </div>
72</div>
73
74<script src="app.js"></script>
75</body>
76</html>

کد درون تگ body کارهای زیر را انجام می‌دهد:

  1. یک کانتینر به نام left-container ایجاد می‌کند که شامل month-container است.
  2. این کانتینر دارای title و current month و همچنین budget واقعی برای ماه مربوطه است.

همچنین از پول محلی استفاده خواهیم کرد.

سپس به سراغ بخش افزودن پس‌انداز یا مصارف می‌رسیم. این کانتینر شامل یک عنوان، یک منوی بازشدنی برای انتخاب نوع هزینه و چند فیلد ورودی برای ثبت هزینه‌ها و همچنین یک لیست برای نمایش مداخل بر اساس تاریخ است. این کد زیر left-container قرار دارد.

بدین ترتیب فایل HTML ما آماده است. اینک یکی از سه فایل مورد نیاز اپلیکیشن خود را تکمیل کرده‌ایم. در ادامه باید این فایل HTML را استایل‌بندی کنیم. آیا متوجه فایل style.css که در تگ <head> ایمپورت کرده‌ایم شدید؟ در ادامه صفحه وب خود را با یک استایل ساده و زیبا استایل‌بندی می‌کنیم.

کدهای CSS مورد نیاز

از آنجا که در این پروژه از بوت‌استرپ استفاده کرده‌ایم، اغلب بخش‌های CSS به صورت خودکار برای ما ایجاد شده‌اند. بوت‌استرپ بخش زیادی از موقعیت‌یابی و طراحی را انجام می‌دهد و از این رو کار زیادی برای انجام نمانده و صرفاً باید حاشیه‌ها، اندازه‌های فونت و رنگ و ظاهر صفحه وب را تغییر دهیم.

فایل CSS ما به شکل زیر است:

1* {
2    margin: 0;
3    padding: 0;
4    box-sizing: border-box;
5}
6
7.clearfix::after {
8    content: "";
9    display: table;
10    clear: both;
11}
12
13body {
14    color: #555;
15    font-family: Open Sans;
16    font-size: 16px;
17    position: relative;
18    height: 100vh;
19    font-weight: 400;
20}
21
22.left-container {
23    height: 100vh;
24    background-image: linear-gradient(#0277BD, #03A9F4);
25    background-size: cover;
26    background-position: center;
27    position: relative;
28}
29
30.right-container {
31    height: 100vh;
32    width: 100%;
33    position: relative;
34}
35
36.header {
37    font-weight: 700;
38    font-size: 36px;
39}
40
41.sub-text {
42    font-size: 22px;
43    font-weight: 400;
44}
45
46.month-container {
47    padding-top: 25%;
48    padding-left: 5%;
49    padding-right: 5%;
50}
51
52.calc-container {
53    padding-top: 12%;
54    padding-left: 5%;
55    padding-right: 5%;
56}
57
58.fs-white {
59    color: #ffffff;
60}
61
62.fs-dark-grey {
63    color: #4e4e4e;
64}
65
66.budget-container {
67    display: inline-block;
68    background: #ffffff;
69    border-radius: 8px;
70    box-shadow: 0 6px 4px #000000;
71}
72
73.month-amount {
74    font-size: 36px;
75    font-weight: 700;
76}
77
78.bottom-border {
79    border-bottom: 1px solid #00446D;
80}
81
82.expense-row {
83    padding: 10px;
84}
85
86.expense-date {
87    color: #077CC1;
88}
89
90.expense-text {
91    color: #077CC1;
92}
93
94.expense-list {
95    overflow-y: scroll;
96}
97
98.fs-15 {
99    font-size: 15px;
100}
101
102.expense-value {
103    text-align: end;
104}
105
106.expense-saving {
107    color: #039300;
108}
109
110.expense-cost {
111    color: #E40000;
112}
113
114.expense-investment {
115    color: #f48803;
116}
117
118#expense-chart {
119    margin: 20% 0;
120}
121
122.btn-submit-expense {
123    border-radius: 50%;
124}
125
126.currency-select {
127    margin: 0 4%;
128}
129
130.selected-currency {
131    color: #ffffff;
132    font-size: 12px;
133    font-weight: 700;
134    margin-top: 1%;
135}

یکی از مشخصه‌های جالب CSS، قابلیت ایجاد پس‌زمینه‌های گرادیانی است. این قابلیت به طور خاص در مواردی به کار می‌آید که بخواهیم کمی رنگ به پروژه خود اضافه کنیم.

اگر در فایل فوق CSS مربوط به left-container را بررسی کنید، می‌بینید که مشخصه پس‌زمینه تابع liner-gradient را می‌گیرد که یک جهت و رنگ‌های مورد استفاده در گرادیان را می‌پذیرد.

1background: linear-gradient(direction, colour-1, colour-2,);

جهت گرادیان دارای مقدار پیش‌فرض top-to-bottom است.

ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت

با این حال برخی اوقات یک گرادیان دقیقاً مطابق آن چه در ذهن شما است عمل نمی‌کند. در این موارد می‌توانید از مشخصه radial-gradient در CSS بهره بگیرید.

به این ترتیب کار ما در بخش‌های HTML و CSS پروژه پایان یافته است. در ادامه روی فایل app.js کار می‌کنیم و تعامل‌ها و کارکردهای پروژه را به آن اضافه می‌کنیم.

توسعه اپلیکیشن مدیریت هزینه با جاوا اسکریپت

جاوا اسکریپت مهم‌ترین بخش این پروژه است. بخش‌های HTML و CSS شیوه نمایش ظاهر پروژه مدیریت هزینه را تعیین کردند، اما اینک باید روی منطق اجرایی آن کار کنیم. فایل app.js جایی است که همه اتفاقات مهم رخ می‌دهند.

پیش از آغاز، زمانی را صرف تأمل در این خصوص بکنید که چه کارکردهایی را باید به فایل app.js اضافه کنیم. در حال حاضر زمانی که یک نوع هزینه را انتخاب می‌کنیم یا یک توضیح و مقدار هزینه را اضافه کرده و روی دکمه‌ها کلیک می‌کنیم، هیچ اتفاقی نمی‌افتد. همان طور که حدس می‌زنید باید eventListeners را اضافه کرده و ماه جاری را نمایش دهیم.

ابتدا باید تابع‌های مختلفی بنویسیم. برخی از این تابع‌ها صرفاً مسئول مدیریت UI و منطق هستند و بودجه ماهانه را محاسبه می‌کنند. این تابع‌ها را کنترلر می‌نامیم. پروژه ما 3 کنترلر خواهد داشت:

  1. کنترلر اصلی: این کنترلر تعامل‌های اولیه و کلی اپلیکیشن مدیریت هزینه را کنترل می‌کند.
  2. کنترلر UI: عناصر UI از قبیل تغییر دادن رنگ فونت و ایجاد لیست مداخل و غیره را کنترل می‌کند.
  3. کنترلر هزینه: بخش محاسبه را کنترل می‌کند و مقادیر کاربر را گرفته و بودجه ماه جاری را محاسبه می‌کند.

به این ترتیب باید یک فایل به نام app.js بسازیم. تگ اسکریپت مربوطه را به انتهای فایل index.html و درست پس از تگ پایانی body اضافه کرده‌ایم.

1<script src="app.js"></script>

فایل app.js ما به صورت زیر خواهد بود:

1let ExpenseController = (() => {
2    let total = 0, savings = 0, expenses = 0, investments = 0;
3
4    return {
5        inputEntry(userInput) {
6            if (userInput['expenseType'] === 'savings') {
7                savings += userInput['value'];
8                total += userInput['value'];
9            }
10            if (userInput['expenseType'] === 'investment') {
11                investments += userInput['value'];
12                total -= userInput['value'];
13            }
14            if (userInput['expenseType'] === 'expense') {
15                expenses += userInput['value'];
16                total -= userInput['value'];
17            }
18        },
19
20        getSavingsData() {
21            return savings;
22        },
23
24        getExpensesData() {
25            return expenses;
26        },
27
28        getInvestmentData() {
29            return investments;
30        },
31
32        getTotalData() {
33            return total;
34        }
35    }
36
37})();
38
39let UIController = (() => {
40    let expenseType = 'savings';
41
42    let HTMLStrings = {
43        inExpenseDescription: '.input-expense-description',
44        inExpenseValue: '.input-expense-value',
45        btnSubmitExpense: '.btn-submit-expense',
46        expenseList: '.expense-list',
47        currentMonth: '#current-month',
48        typeExpense: '#type-expense',
49        typeSavings: '#type-savings',
50        typeInvestment: '#type-investment',
51        trackingText: '.tracking-text',
52        expenseChart: '#expense-chart',
53        monthBudget: '#month-budget'
54    };
55
56    return {
57        numberFormat(number) {
58            return Intl.NumberFormat('en-IN').format(number);
59        },
60        showCurrentMonth() {
61            let now, month, year, months;
62
63            now = new Date();
64            month = now.getMonth();
65            year = now.getFullYear();
66            months = [
67                'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October',
68                'November', 'December'
69            ];
70            document.querySelector(HTMLStrings.currentMonth).textContent = months[month] + " " + year;
71        },
72
73        getHTMLStrings() {
74            return HTMLStrings;
75        },
76
77        setExpenseType(type) {
78            console.log('here', type);
79            this.expenseType = type;
80            let emoji ="?";
81            if (type === 'savings') {
82                emoji ="?";
83                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-warning')) {
84                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-warning');
85                }
86                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-danger')) {
87                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-danger');
88                }
89                if (!document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-success')) {
90                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.add('btn-success');
91                }
92            }
93
94            if (type === 'expense') {
95                emoji = "?";
96                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-warning')) {
97                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-warning');
98                }
99                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-success')) {
100                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-success');
101                }
102                if (!document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-danger')) {
103                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.add('btn-danger');
104                }
105            }
106            if (type === 'investment') {
107                emoji = "?";
108                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-danger')) {
109                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-danger');
110                }
111                if (document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-success')) {
112                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.remove('btn-success');
113                }
114                if (!document.querySelector(HTMLStrings.btnSubmitExpense).classList.contains('btn-warning')) {
115                    document.querySelector(HTMLStrings.btnSubmitExpense).classList.add('btn-warning');
116                }
117            }
118
119            document.querySelector(HTMLStrings.trackingText).textContent = "Tracking " + type + " " + emoji;
120
121        },
122
123        getUserExpenseInput() {
124            return {
125                description: document.querySelector(HTMLStrings.inExpenseDescription).value,
126                value: parseInt(document.querySelector(HTMLStrings.inExpenseValue).value),
127                date: new Date().toLocaleDateString(),
128                expenseType: this.expenseType ? this.expenseType : 'savings'
129            }
130        },
131
132        addListItem (inputObj) {
133            let html, element;
134            element = HTMLStrings.expenseList;
135
136            if (inputObj['expenseType'] === 'savings') {
137                html = '<div class="bottom-border"> <div class="row expense-row"><div class="col-2 expense-date fs-15">' + inputObj['date'] + ' </div><div class="col-8 expense-text fs-15"> ' + inputObj['description'] + ' </div><div class="col-2 expense-value expense-saving fs-15"> ₹ ' + this.numberFormat(inputObj['value']) + ' </div></div>'
138            } else if (inputObj['expenseType'] === 'expense') {
139                html = '<div class="bottom-border"> <div class="row expense-row"><div class="col-2 expense-date fs-15">' + inputObj['date'] + ' </div><div class="col-8 expense-text fs-15"> ' + inputObj['description'] + ' </div><div class="col-2 expense-value expense-cost fs-15"> ₹ ' + this.numberFormat(inputObj['value']) + ' </div></div>'
140            } else if (inputObj['expenseType'] === 'investment') {
141                html = '<div class="bottom-border"> <div class="row expense-row"><div class="col-2 expense-date fs-15">' + inputObj['date'] + ' </div><div class="col-8 expense-text fs-15"> ' + inputObj['description'] + ' </div><div class="col-2 expense-value expense-investment fs-15"> ₹ ' + this.numberFormat(inputObj['value']) + ' </div></div>'
142            }
143
144            // Add the new element
145            document.querySelector(element).insertAdjacentHTML('beforeend', html);
146
147            // Clear the input fields after adding element
148            document.querySelector(HTMLStrings.inExpenseValue).value = "";
149            document.querySelector(HTMLStrings.inExpenseDescription).value = "";
150        },
151
152        updateOverallTotal(totalValue) {
153            document.querySelector(HTMLStrings.monthBudget).textContent  = "₹ " + this.numberFormat(totalValue);
154
155            if (totalValue > 0) {
156                if (document.querySelector(HTMLStrings.monthBudget).classList.contains('expense-cost')) {
157                    document.querySelector(HTMLStrings.monthBudget).classList.remove('expense-cost');
158                }
159                document.querySelector(HTMLStrings.monthBudget).classList.add('expense-saving');
160            } else {
161                if (document.querySelector(HTMLStrings.monthBudget).classList.contains('expense-saving')) {
162                    document.querySelector(HTMLStrings.monthBudget).classList.remove('expense-saving');
163                }
164                document.querySelector(HTMLStrings.monthBudget).classList.add('expense-cost');
165            }
166        },
167
168        displayChart(savings = 0, expenses = 0, investments = 0) {
169            let ctx = document.querySelector(HTMLStrings.expenseChart);
170            let expenseChart = new Chart(ctx, {
171                type: 'doughnut',
172                data: {
173                    labels: ['Savings', 'Expenses', 'Investments'],
174                    datasets: [{
175                        data: [savings, expenses, investments],
176                        backgroundColor: [
177                            'rgba(32, 137, 56, 1)',
178                            'rgba(255, 84, 98, 1)',
179                            'rgba(255, 206, 86, 1)'
180                        ],
181                        borderWidth: 0.5
182                    }]
183                },
184                options: {
185                    legend: {
186                        labels: {
187                            fontColor: 'white'
188                        }
189                    }
190                }
191            });
192        }
193    }
194})();
195
196((UIController, ExpenseController) => {
197
198    let HTMLStrings = UIController.getHTMLStrings();
199    let setupEventListeners = () => {
200        document.querySelector(HTMLStrings.btnSubmitExpense).addEventListener('click', addExpense);
201        document.querySelector(HTMLStrings.typeExpense).addEventListener('click', () => {
202            setExpenseType('expense')
203        });
204        document.querySelector(HTMLStrings.typeInvestment).addEventListener('click', () => {
205            setExpenseType('investment')
206        });
207        document.querySelector(HTMLStrings.typeSavings).addEventListener('click', () => {
208            setExpenseType('savings')
209        });
210    };
211
212    let setExpenseType = (type) => {
213        UIController.setExpenseType(type);
214    }
215
216    let addExpense = () => {
217        let input = UIController.getUserExpenseInput();
218        console.log(input);
219
220        if (input.description !== "" && !isNaN(input.value) && input.value > 0) {
221            console.log('Adding item');
222            UIController.addListItem(input);
223            ExpenseController.inputEntry(input);
224            UIController.updateOverallTotal(ExpenseController.getTotalData());
225            UIController.displayChart(ExpenseController.getSavingsData(), ExpenseController.getExpensesData(),
226                ExpenseController.getInvestmentData());
227        }
228    }
229
230    let init = () => {
231        console.log('Initializing...');
232        setupEventListeners();
233        UIController.showCurrentMonth();
234    }
235
236    init();
237
238})(UIController, ExpenseController);

در ادامه بخش‌های مختلف این فایل را توضیح می‌دهیم.

عبارت‌های تابع با اجرای بی‌درنگ (IIFE)

IIFE-ها تابع‌هایی در جاوا اسکریپت هستند که به محض تعریف شدن، اجرا می‌شوند. این تابع‌ها در زمان اجرای فایل اسکریپت بی‌درنگ فراخوانی می‌شوند. از این رو نیازی به تابع دیگر برای فراخوانی شدن ندارند. تا پیش از ES6 شکل آن‌ها چنین بود:

1(function(){
2    console.log('Welcome, this is an IIFE!');
3})();

در ES6 شکل آن‌ها چنین است:

1(() => {
2    console.log('Welcome, this is an IIFE!')
3})();

در ادامه منطق تجاری اپلیکیشن خود را بررسی می‌کنیم. نخست کار را با بررسی کنترلرها آغاز می‌کنیم.

کنترلر اصلی وظایف زیر را بر عهده دارد:

  1. مقداردهی پروژه.
  2. راه‌اندازی شنونده‌های کلیک.
  3. برقراری ارتباط بین UI و کنترلرهای هزینه.

کنترلر UI روی وجوه زیر تمرکز دارد:

  1. افزودن آیتم‌های لیست.
  2. تنظیم ماه جاری.
  3. تنظیم نوع ورودی (هزینه، پس‌انداز، سرمایه‌گذاری).
  4. دریافت ورودی کاربر.
  5. رندر کردن نمودار دایره‌ای.

کنترلر هزینه کارهای زیر را انجام می‌دهد:

  1. محاسبه مجموع بخش‌های پس‌انداز، هزینه‌ها و سرمایه‌گذاری.
  2. محاسبه بودجه کلی ماهانه.

کنترلر اصلی دو پارامتر می‌گیرد که شامل کنترلر UI و کنترلر هزینه است. به این ترتیب کنترلر اصلی گردش داده بین آن‌ها را کنترل می‌کند.

تابع HTMLStrings یک شیء است که رد نام‌ها کلاس و شناسه عناصر مورد استفاده در فایل HTML را نگهداری می‌کند. این کار به این جهت انجام یافته که بازسازی عناصر HTML در پروژه آسان باشد و زمان مورد نیاز برای دیباگ احتمالی جهت یافتن خطاهای مختلف کاهش یابد.

کنترلر اصلی

اینک eventListeners را تنظیم می‌کنیم. ابتدا عناصری که نیازمند یک شنونده کلیک هستند را لیست می‌کنیم. این موارد شامل گزینه‌های بازشدنی نوع هزینه و دکمه Submit هستند. در همین راستا تابع‌هایی را ایجاد می‌کنیم که در زمان تریگر شدن شنونده‌های رویداد فراخوانی خواهند شد. در ادامه هر یک از این تابع‌ها را بررسی می‌کنیم.

تابع setupEventListeners عناصر منوی بازشدنی را انتخاب می‌کند و دکمه submit یک شنونده کلیک به هر یک از آن‌ها اضافه می‌کند. این شنونده‌ها زمانی که رویشان کلیک کنید فعال می‌شوند. هر شنونده کلیک یک وظیفه خاص از قبیل تنظیم نوع هزینه یا صدور دستور اجرای وظیفه خاصی به دو کنترلر دیگر را بر عهده دارد.

تابع addExpense کنترلر UI را می‌گیرد تا ورودی کاربر را از HTML دریافت کند، معتبر بودن آن را بررسی کند و از کنترلر UI بخواهد که یک آیتم لیست جدید به ورودی صحیح اضافه کند. همچنین کنترلر هزینه را برای محاسبه مجدد مقادیر از ورودی جدید می‌پرسد. سپس از کنترلر UI می‌خواهد که هزینه کلی ماه را به‌روزرسانی کند.

شاید تعجب کنید که اجازه می‌دهیم کنترلرهای UI و هزینه به صورت مستقیم با همدیگر صحبت کنند. حق با شما است و این رویه مناسبی نیست. کنترلرها به جز کنترلر اصلی باید مستقل از همدیگر بمانند. به این ترتیب توسعه‌دهنده آن‌ها را آسان‌تر درک کرده و به شیوه‌ای ساده‌تر دیباگ می‌کند. اکنون کار ما با کنترلر اصلی پایان یافته است.

کنترلر UI

کنترلر UI بزرگ‌ترین کنترلر ما است و با کلاس‌های HTML و CSS کار می‌کند تا ظاهر مناسبی برای پروژه فراهم سازد. در ادامه به بررسی همه تابع‌های آن می‌پردازیم:

  1. numberFormat – این تابع به قالب‌بندی ورودی‌های عددی بر اساس locale کاربر کمک می‌کند.
  2. showCurrentMonth – یک تابع ساده است که ماه را از تاریخ جاری بازیابی کرده و در فیلد ماه کنونی نمایش می‌دهد.
  3. setExpenseType – این تابع با کلاس‌های CSS کار می‌کند. این تابع بر اساس نوع هزینه کلاس‌های مناسب را به دکمه submit-expense حذف یا اضافه می‌کند. به این ترتیب رنگ قرمز برای هزینه‌ها، رنگ زرد برای سرمایه‌گذاری و سبز برای پس‌انداز استفاده می‌شود.
  4. addListItem – این تابع HTML مورد نیاز برای آیتم لیست را بر اساس نوع هزینه ایجاد کرده و ردیف جدیدی در هزینه‌های ثبت شده اضافه می‌کند. insertAdjacentHTML موقعیت نسبی خود را نسبت به والدین و متن HTML که باید در آن موقعیت درج شود را دریافت می‌کند. ما می‌خواهیم ردیف جدید را در انتها درج کنیم و از این رو از beforeEnd استفاده می‌کنیم.
  5. updateOverallTotal – این تابع بودجه کلی ماهانه را به‌روزرسانی می‌کند. اگر در این ماه بدهکار شوید، به رنگ قرمز درمی‌آید و در غیر این صورت سبز رنگ است.

کنترلر هزینه

کنترلر هزینه یک وظیفه ساده دارد و آن این است که چهار مقدار «پس‌انداز» (savings)، «سرمایه‌گذاری» (investments)‌، «هزینه‌ها» (investments) و «بودجه کلی ماهانه» ‌ (total monthly budget) ‌‌را نگهداری می‌کند.

به این ترتیب موفق شدیم کارکردهای مقدماتی اپلیکیشن مدیریت هزینه را کامل کنیم. هم اکنون می‌توانیم مدخل‌هایی را در بخش‌های مختلف هزینه‌ای وارد کنیم و بر همین اساس بودجه ماهانه محاسبه می‌شود. اینک می‌توانیم به بخش‌های فرعی بپردازیم.

نمودار دایره‌ای

کتابخانه‌های زیادی برای جاوا اسکریپت عرضه شده‌اند که امکان ایجاد نمودارهای زیبایی را فراهم می‌سازند. این کتابخانه‌ها موجب می‌شوند سریع‌تر به هدف خود برسیم و همواره گزینه بهتری نسبت به نوشتن این قابلیت‌ها از صفر محسوب می‌شوند.

ما در این پروژه از کتابخانه Chart.js (https://www.chartjs.org/) استفاده می‌کنیم که یک کتابخانه ساده و انعطاف‌پذیر برای طراحان و توسعه‌دهندگان است. این کتابخانه از عنصر <canvas> در HTML برای رندر کردن نمودارها بهره می‌گیرد. به این منظور باید یک div جدید در HTML اضافه کنیم و نمودار را در بخش انتهای left-container در خود جای دهد. کد آن چنین است:

1<div class="chart-container">
2    <canvas id="expense-chart"></canvas>
3</div>

همچنین باید کنترلرها را لینک کنیم تا هر زمان که رکورد جدیدی در اپلیکیشن ما وارد می‌شود، نمودار نیز به‌روزرسانی شود. در تابع the addExpense در کنترلر اصلی یک فراخوانی تابع جدید اضافه می‌کنیم که به کنترلر UI دستور می‌دهد تا نمودار را با مقادیر جدید به‌روزرسانی کند.

1UIController.displayChart(ExpenseController.getSavingsData(), ExpenseController.getExpensesData(),
2    ExpenseController.getInvestmentData());

displayChart در متد کنترلر UI یک نمودار جدید ایجاد می‌کند. ما باید نوع نمودار، داده‌ها (برچسب‌ها و دیتاست‌ها) و برخی گزینه‌های مورد نیاز برای سفارشی‌سازی نمودار را به آن ارسال کنیم. اینک با وارد کردن برخی مقادیر در اپلیکیشن می‌بینید که گراف دایره‌ای زیبایی ترسیم می‌شود. در نهایت اپلیکیشن شما باید به صورت زیر درآمده باشد:

ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
gitconnected
۱ دیدگاه برای «ساخت اپلیکیشن مدیریت هزینه با جاوا اسکریپت — از صفر تا صد»

برای من پرش داره اصلا نمیاره

نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *