


Dari Sifar ke Etalase: Perjalanan Saya Membina Laman Web Sewa Kereta dan Apl Mudah Alih
Nov 26, 2024 am 12:26 AMKandungan
- Pengenalan
- Timbunan Teknologi
- Ikhtisar Pantas
- API
- Hadapan
- Apl Mudah Alih
- Papan Pemuka Pentadbir
- Tempat Menarik
- Sumber
Kod sumber: https://github.com/aelassas/bookcars
Demo: https://bookcars.dynv6.net:3002
pengenalan
Idea muncul daripada keinginan untuk membina tanpa sempadan – tapak web sewa kereta yang boleh disesuaikan sepenuhnya dan apl mudah alih di mana setiap aspek berada dalam kawalan anda:
- Miliki UI/UX: Reka pengalaman pelanggan yang unik tanpa melawan had templat
- Kawal Bahagian Belakang: Laksanakan logik perniagaan tersuai dan struktur data yang sepadan dengan keperluan
- Master DevOps: Sebarkan, skala dan pantau aplikasi dengan alatan dan aliran kerja pilihan
- Perluas Secara Bebas: Tambahkan ciri dan penyepaduan baharu tanpa kekangan platform atau bayaran tambahan
Timbunan Teknologi
Berikut ialah susunan teknologi yang membolehkannya:
- Skrip Jenis
- Node.js
- MongoDB
- Bertindak balas
- MUI
- React Native
- Ekspo
- Belang
- Pelabuh
Keputusan reka bentuk utama telah dibuat untuk menggunakan TypeScript kerana banyak kelebihannya. TypeScript menawarkan penaipan, perkakasan dan penyepaduan yang kuat, menghasilkan kod berkualiti tinggi, berskala, lebih mudah dibaca dan boleh diselenggara yang mudah untuk nyahpepijat dan diuji.
Saya memilih React untuk keupayaan pemaparan yang berkuasa, MongoDB untuk pemodelan data yang fleksibel dan Stripe untuk pemprosesan pembayaran yang selamat.
Dengan memilih timbunan ini, anda bukan sahaja membina tapak web dan apl mudah alih – anda melabur dalam asas yang boleh berkembang mengikut keperluan anda, disokong oleh teknologi sumber terbuka yang teguh dan komuniti pembangun yang semakin berkembang.
React menonjol sebagai pilihan yang sangat baik kerana:
- Seni Bina Berasaskan Komponen
- Membolehkan anda memecahkan UI kompleks kepada bahagian yang lebih kecil dan boleh digunakan semula
- Menjadikan kod lebih mudah diselenggara dan lebih mudah untuk diuji
- Mendayakan organisasi kod yang lebih baik dan kebolehgunaan semula
- Prestasi DOM Maya
- DOM maya React mengemas kini dengan cekap hanya perkara yang perlu
- Menghasilkan pemuatan halaman yang lebih pantas dan pengalaman pengguna yang lebih baik
- Mengurangkan pemaparan semula yang tidak perlu
- Ekosistem Kaya
- Perpustakaan besar komponen pra-bina
- Peralatan yang luas
- Komuniti besar untuk sokongan dan sumber
- Pengalaman Pembangun Teguh
- Muat semula panas untuk maklum balas segera
- Alat penyahpepijatan yang sangat baik
- JSX menjadikan penulisan kod UI lebih intuitif
- Sokongan Industri
- Disokong oleh Meta (dahulunya Facebook)
- Digunakan oleh banyak syarikat besar
- Pembangunan dan penambahbaikan berterusan
- Fleksibiliti
- Berfungsi dengan baik untuk kedua-dua aplikasi kecil dan besar
- Boleh diintegrasikan secara beransur-ansur ke dalam projek sedia ada
- Menyokong berbilang strategi pemaparan (sebelah pelanggan, sebelah pelayan, statik)
Gambaran keseluruhan pantas
Dalam bahagian ini, anda akan melihat halaman utama bahagian hadapan, papan pemuka pentadbir dan apl mudah alih.
Bahagian hadapan
Dari bahagian hadapan, pengguna boleh mencari kereta yang tersedia, memilih kereta dan daftar keluar.
Di bawah ialah halaman utama bahagian hadapan di mana pengguna boleh memilih tempat pengambilan dan penghantaran serta masa serta mencari kereta yang tersedia.
Di bawah ialah hasil carian halaman utama yang membolehkan pengguna memilih kereta untuk disewa.
Di bawah ialah halaman daftar keluar di mana pengguna boleh menetapkan pilihan sewa dan pembayaran. Jika pengguna tidak berdaftar, dia boleh mendaftar keluar dan mendaftar pada masa yang sama. Dia akan menerima e-mel pengesahan dan pengaktifan untuk menetapkan kata laluannya jika dia belum berdaftar.
Di bawah ialah halaman log masuk. Pada pengeluaran, kuki pengesahan adalah httpSahaja, ditandatangani, selamat dan ketat samaSite.?Pilihan ini menghalang serangan XSS, CSRF dan MITM.?Kuki pengesahan dilindungi daripada serangan XST juga melalui perisian tengah tersuai.
Di bawah ialah halaman pendaftaran.
Di bawah ialah halaman yang membolehkan pengguna melihat dan mengurus tempahannya.
Di bawah ialah halaman yang membolehkan pengguna melihat tempahan secara terperinci.
Di bawah ialah halaman kenalan.
Di bawah ialah halaman lokasi sewa kereta.
Di bawah ialah halaman yang membolehkan pelanggan melihat dan mengurus pemberitahuannya.
Terdapat halaman lain tetapi ini adalah halaman utama bahagian hadapan.
Papan Pemuka Pentadbir
Terdapat tiga jenis pengguna:
- Pentadbir: Dia mempunyai akses penuh pada papan pemuka pentadbir. Dia boleh buat semuanya.
- Pembekal: Dia telah mengehadkan akses pada papan pemuka pentadbir. Dia hanya boleh menguruskan kereta dan tempahannya.
- Pengguna: Dia hanya mempunyai akses kepada bahagian hadapan dan apl mudah alih. Dia tidak boleh mengakses papan pemuka pentadbir.
Platform ini direka bentuk untuk berfungsi dengan berbilang pembekal. Setiap pembekal boleh menguruskan armada keretanya dan tempahan dari papan pemuka pentadbir. Platform ini juga boleh berfungsi dengan hanya satu pembekal.
Daripada papan pemuka pentadbir, pengguna pentadbir boleh membuat dan mengurus pembekal, kereta, lokasi, pengguna dan tempahan.
Apabila pengguna pentadbir mencipta pembekal baharu, pembekal akan menerima e-mel automatik untuk membuat akaunnya untuk mengakses papan pemuka pentadbir supaya dia boleh menguruskan armada dan tempahan keretanya.
Di bawah ialah halaman log masuk papan pemuka pentadbir.
Di bawah ialah halaman papan pemuka papan pemuka pentadbir tempat pentadbir dan pembekal boleh melihat dan mengurus tempahan.
Di bawah ialah halaman di mana armada kereta dipaparkan dan boleh diurus.
Di bawah ialah halaman di mana pentadbir dan pembekal boleh mencipta kereta baharu dengan memberikan imej dan maklumat kereta. Untuk pilihan kereta disertakan secara percuma, tetapkan 0 untuk pilihan kereta yang sepadan. Jika tidak, tetapkan harga pilihan atau biarkan ia kosong jika anda tidak mahu memasukkannya.
Di bawah ialah halaman tempat pentadbir dan pembekal boleh mengedit kereta.
Di bawah ialah halaman tempat pentadbir boleh mengurus pengguna platform.
Di bawah ialah halaman untuk mengedit tempahan.
Ada halaman lain tetapi ini adalah halaman utama papan pemuka pentadbir.
API
Api mendedahkan semua fungsi yang diperlukan untuk papan pemuka pentadbir, bahagian hadapan dan apl mudah alih. API mengikut corak reka bentuk MVC. JWT digunakan untuk pengesahan. Terdapat beberapa fungsi yang memerlukan pengesahan seperti fungsi yang berkaitan dengan pengurusan kereta, tempahan dan pelanggan, dan lain-lain yang tidak memerlukan pengesahan seperti mendapatkan semula lokasi dan kereta yang tersedia untuk pengguna yang tidak disahkan:
- ./api/src/models/ folder mengandungi model MongoDB.
- ./api/src/routes/ folder mengandungi laluan Ekspres.
- ./api/src/controllers/ folder mengandungi pengawal.
- ./api/src/middlewares/ folder mengandungi middlewares.
- ./api/src/config/env.config.ts mengandungi konfigurasi dan takrif jenis TypeScript.
- ./api/src/lang/ folder mengandungi penyetempatan.
- ./api/src/app.ts ialah pelayan utama tempat laluan dimuatkan.
- ./api/index.ts ialah titik masuk utama api.
index.ts ialah titik masuk utama api:
import 'dotenv/config' import process from 'node:process' import fs from 'node:fs/promises' import http from 'node:http' import https, { ServerOptions } from 'node:https' import * as env from './config/env.config' import * as databaseHelper from './common/databaseHelper' import app from './app' import * as logger from './common/logger' if ( await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG) && await databaseHelper.initialize() ) { let server: http.Server | https.Server if (env.HTTPS) { https.globalAgent.maxSockets = Number.POSITIVE_INFINITY const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8') const certificate = await fs.readFile(env.CERTIFICATE, 'utf8') const credentials: ServerOptions = { key: privateKey, cert: certificate } server = https.createServer(credentials, app) server.listen(env.PORT, () => { logger.info('HTTPS server is running on Port', env.PORT) }) } else { server = app.listen(env.PORT, () => { logger.info('HTTP server is running on Port', env.PORT) }) } const close = () => { logger.info('Gracefully stopping...') server.close(async () => { logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`) await databaseHelper.close(true) logger.info('MongoDB connection closed') process.exit(0) }) } ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close)) }
Ini ialah fail TypeScript yang memulakan pelayan menggunakan Node.js dan Express. Ia mengimport beberapa modul termasuk dotenv, proses, fs, http, https, mongoose dan aplikasi. Ia kemudian menyemak sama ada pembolehubah persekitaran HTTPS ditetapkan kepada benar, dan jika ya, mencipta pelayan HTTPS menggunakan modul https dan kunci peribadi serta sijil yang disediakan. Jika tidak, ia mencipta pelayan HTTP menggunakan modul http. Pelayan mendengar pada port yang dinyatakan dalam pembolehubah persekitaran PORT.
Fungsi tutup ditakrifkan untuk menghentikan pelayan dengan anggun apabila isyarat penamatan diterima. Ia menutup pelayan dan sambungan MongoDB, dan kemudian keluar dari proses dengan kod status 0. Akhir sekali, ia mendaftarkan fungsi tutup untuk dipanggil apabila proses menerima isyarat SIGINT, SIGTERM atau SIGQUIT.
app.ts ialah titik masuk utama api:
import express from 'express' import compression from 'compression' import helmet from 'helmet' import nocache from 'nocache' import cookieParser from 'cookie-parser' import i18n from './lang/i18n' import * as env from './config/env.config' import cors from './middlewares/cors' import allowedMethods from './middlewares/allowedMethods' import supplierRoutes from './routes/supplierRoutes' import bookingRoutes from './routes/bookingRoutes' import locationRoutes from './routes/locationRoutes' import notificationRoutes from './routes/notificationRoutes' import carRoutes from './routes/carRoutes' import userRoutes from './routes/userRoutes' import stripeRoutes from './routes/stripeRoutes' import countryRoutes from './routes/countryRoutes' import * as helper from './common/helper' const app = express() app.use(helmet.contentSecurityPolicy()) app.use(helmet.dnsPrefetchControl()) app.use(helmet.crossOriginEmbedderPolicy()) app.use(helmet.frameguard()) app.use(helmet.hidePoweredBy()) app.use(helmet.hsts()) app.use(helmet.ieNoOpen()) app.use(helmet.noSniff()) app.use(helmet.permittedCrossDomainPolicies()) app.use(helmet.referrerPolicy()) app.use(helmet.xssFilter()) app.use(helmet.originAgentCluster()) app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' })) app.use(helmet.crossOriginOpenerPolicy()) app.use(nocache()) app.use(compression({ threshold: 0 })) app.use(express.urlencoded({ limit: '50mb', extended: true })) app.use(express.json({ limit: '50mb' })) app.use(cors()) app.options('*', cors()) app.use(cookieParser(env.COOKIE_SECRET)) app.use(allowedMethods) app.use('/', supplierRoutes) app.use('/', bookingRoutes) app.use('/', locationRoutes) app.use('/', notificationRoutes) app.use('/', carRoutes) app.use('/', userRoutes) app.use('/', stripeRoutes) app.use('/', countryRoutes) i18n.locale = env.DEFAULT_LANGUAGE await helper.mkdir(env.CDN_USERS) await helper.mkdir(env.CDN_TEMP_USERS) await helper.mkdir(env.CDN_CARS) await helper.mkdir(env.CDN_TEMP_CARS) await helper.mkdir(env.CDN_LOCATIONS) await helper.mkdir(env.CDN_TEMP_LOCATIONS) export default app
Pertama sekali, kami mendapatkan semula rentetan sambungan MongoDB, kemudian kami mewujudkan sambungan dengan pangkalan data MongoDB. Kemudian kami mencipta apl Express dan memuatkan perisian tengah seperti cors, mampatan, topi keledar dan nocache. Kami menyediakan pelbagai langkah keselamatan menggunakan perpustakaan middleware topi keledar. kami juga mengimport pelbagai fail laluan untuk bahagian aplikasi yang berbeza seperti Laluan pembekal, Laluan tempahan, Laluan lokasi, Laluan pemberitahuan, Laluan kereta dan Laluan pengguna. Akhir sekali, kami memuatkan laluan Ekspres dan apl eksport.
Terdapat 8 laluan dalam api. Setiap laluan mempunyai pengawal sendiri mengikut corak reka bentuk MVC dan prinsip SOLID. Di bawah adalah laluan utama:
- userRoutes: Menyediakan fungsi REST yang berkaitan dengan pengguna
- supplierRoutes: Menyediakan fungsi REST yang berkaitan dengan pembekal
- countryRoutes: Menyediakan fungsi REST yang berkaitan dengan negara
- Laluan lokasi: Menyediakan fungsi REST yang berkaitan dengan lokasi
- CarRoutes: Menyediakan fungsi REST yang berkaitan dengan kereta
- laluan tempahan: Menyediakan fungsi REST yang berkaitan dengan tempahan
- Laluan pemberitahuan: Menyediakan fungsi REST yang berkaitan dengan pemberitahuan
- stripeRoutes: Menyediakan fungsi REST yang berkaitan dengan gerbang pembayaran Stripe
Kami tidak akan menerangkan setiap laluan satu demi satu. Kami akan mengambil, sebagai contoh, countryRoutes dan melihat cara ia dibuat:
import express from 'express' import routeNames from '../config/countryRoutes.config' import authJwt from '../middlewares/authJwt' import * as countryController from '../controllers/countryController' const routes = express.Router() routes.route(routeNames.validate).post(authJwt.verifyToken, countryController.validate) routes.route(routeNames.create).post(authJwt.verifyToken, countryController.create) routes.route(routeNames.update).put(authJwt.verifyToken, countryController.update) routes.route(routeNames.delete).delete(authJwt.verifyToken, countryController.deleteCountry) routes.route(routeNames.getCountry).get(authJwt.verifyToken, countryController.getCountry) routes.route(routeNames.getCountries).get(authJwt.verifyToken, countryController.getCountries) routes.route(routeNames.getCountriesWithLocations).get(countryController.getCountriesWithLocations) routes.route(routeNames.checkCountry).get(authJwt.verifyToken, countryController.checkCountry) routes.route(routeNames.getCountryId).get(authJwt.verifyToken, countryController.getCountryId) export default routes
Pertama sekali, kami mencipta Penghala Ekspres. Kemudian, kami mencipta laluan menggunakan nama, kaedah, perisian tengah dan pengawalnya.
Nama laluan mengandungi nama laluan countryRoutes:
const routes = { validate: '/api/validate-country', create: '/api/create-country', update: '/api/update-country/:id', delete: '/api/delete-country/:id', getCountry: '/api/country/:id/:language', getCountries: '/api/countries/:page/:size/:language', getCountriesWithLocations: '/api/countries-with-locations/:language/:imageRequired/:minLocations', checkCountry: '/api/check-country/:id', getCountryId: '/api/country-id/:name/:language', } export default routes
countryController mengandungi logik perniagaan utama berkenaan negara. Kami tidak akan melihat semua kod sumber pengawal kerana ia agak besar tetapi kami akan mengambil fungsi pengawal sebagai contoh.
Di bawah ialah model Country:
import { Schema, model } from 'mongoose' import * as env from '../config/env.config' const countrySchema = new Schema<env.Country>( { values: { type: [Schema.Types.ObjectId], ref: 'LocationValue', required: [true, "can't be blank"], validate: (value: any): boolean => Array.isArray(value), }, }, { timestamps: true, strict: true, collection: 'Country', }, ) const Country = model<env.Country>('Country', countrySchema) export default Country
Di bawah ialah env.Country TypeScript type:
export interface Country extends Document { values: Types.ObjectId[] name?: string }
Negara mempunyai pelbagai nilai. Satu setiap bahasa. Secara lalai, bahasa Inggeris dan Perancis disokong.
Di bawah ialah model LocationValue:
import 'dotenv/config' import process from 'node:process' import fs from 'node:fs/promises' import http from 'node:http' import https, { ServerOptions } from 'node:https' import * as env from './config/env.config' import * as databaseHelper from './common/databaseHelper' import app from './app' import * as logger from './common/logger' if ( await databaseHelper.connect(env.DB_URI, env.DB_SSL, env.DB_DEBUG) && await databaseHelper.initialize() ) { let server: http.Server | https.Server if (env.HTTPS) { https.globalAgent.maxSockets = Number.POSITIVE_INFINITY const privateKey = await fs.readFile(env.PRIVATE_KEY, 'utf8') const certificate = await fs.readFile(env.CERTIFICATE, 'utf8') const credentials: ServerOptions = { key: privateKey, cert: certificate } server = https.createServer(credentials, app) server.listen(env.PORT, () => { logger.info('HTTPS server is running on Port', env.PORT) }) } else { server = app.listen(env.PORT, () => { logger.info('HTTP server is running on Port', env.PORT) }) } const close = () => { logger.info('Gracefully stopping...') server.close(async () => { logger.info(`HTTP${env.HTTPS ? 'S' : ''} server closed`) await databaseHelper.close(true) logger.info('MongoDB connection closed') process.exit(0) }) } ['SIGINT', 'SIGTERM', 'SIGQUIT'].forEach((signal) => process.on(signal, close)) }
Di bawah ialah jenis env.LocationValue TypeScript:
import express from 'express' import compression from 'compression' import helmet from 'helmet' import nocache from 'nocache' import cookieParser from 'cookie-parser' import i18n from './lang/i18n' import * as env from './config/env.config' import cors from './middlewares/cors' import allowedMethods from './middlewares/allowedMethods' import supplierRoutes from './routes/supplierRoutes' import bookingRoutes from './routes/bookingRoutes' import locationRoutes from './routes/locationRoutes' import notificationRoutes from './routes/notificationRoutes' import carRoutes from './routes/carRoutes' import userRoutes from './routes/userRoutes' import stripeRoutes from './routes/stripeRoutes' import countryRoutes from './routes/countryRoutes' import * as helper from './common/helper' const app = express() app.use(helmet.contentSecurityPolicy()) app.use(helmet.dnsPrefetchControl()) app.use(helmet.crossOriginEmbedderPolicy()) app.use(helmet.frameguard()) app.use(helmet.hidePoweredBy()) app.use(helmet.hsts()) app.use(helmet.ieNoOpen()) app.use(helmet.noSniff()) app.use(helmet.permittedCrossDomainPolicies()) app.use(helmet.referrerPolicy()) app.use(helmet.xssFilter()) app.use(helmet.originAgentCluster()) app.use(helmet.crossOriginResourcePolicy({ policy: 'cross-origin' })) app.use(helmet.crossOriginOpenerPolicy()) app.use(nocache()) app.use(compression({ threshold: 0 })) app.use(express.urlencoded({ limit: '50mb', extended: true })) app.use(express.json({ limit: '50mb' })) app.use(cors()) app.options('*', cors()) app.use(cookieParser(env.COOKIE_SECRET)) app.use(allowedMethods) app.use('/', supplierRoutes) app.use('/', bookingRoutes) app.use('/', locationRoutes) app.use('/', notificationRoutes) app.use('/', carRoutes) app.use('/', userRoutes) app.use('/', stripeRoutes) app.use('/', countryRoutes) i18n.locale = env.DEFAULT_LANGUAGE await helper.mkdir(env.CDN_USERS) await helper.mkdir(env.CDN_TEMP_USERS) await helper.mkdir(env.CDN_CARS) await helper.mkdir(env.CDN_TEMP_CARS) await helper.mkdir(env.CDN_LOCATIONS) await helper.mkdir(env.CDN_TEMP_LOCATIONS) export default app
LocationValue mempunyai kod bahasa (ISO 639-1) dan nilai rentetan.
Di bawah ialah cipta fungsi pengawal:
import express from 'express' import routeNames from '../config/countryRoutes.config' import authJwt from '../middlewares/authJwt' import * as countryController from '../controllers/countryController' const routes = express.Router() routes.route(routeNames.validate).post(authJwt.verifyToken, countryController.validate) routes.route(routeNames.create).post(authJwt.verifyToken, countryController.create) routes.route(routeNames.update).put(authJwt.verifyToken, countryController.update) routes.route(routeNames.delete).delete(authJwt.verifyToken, countryController.deleteCountry) routes.route(routeNames.getCountry).get(authJwt.verifyToken, countryController.getCountry) routes.route(routeNames.getCountries).get(authJwt.verifyToken, countryController.getCountries) routes.route(routeNames.getCountriesWithLocations).get(countryController.getCountriesWithLocations) routes.route(routeNames.checkCountry).get(authJwt.verifyToken, countryController.checkCountry) routes.route(routeNames.getCountryId).get(authJwt.verifyToken, countryController.getCountryId) export default routes
Dalam fungsi ini, kami mendapatkan semula isi permintaan, kami mengulangi nilai yang disediakan dalam kandungan (satu nilai setiap bahasa) dan kami mencipta LocationValue. Akhir sekali, kami mencipta negara bergantung pada nilai lokasi yang dibuat.
Bahagian hadapan
Halaman hadapan ialah aplikasi web yang dibina dengan Node.js, React, MUI dan TypeScript. Dari bahagian hadapan, pelanggan boleh mencari kereta yang tersedia bergantung pada tempat pengambilan dan penghantaran serta masa, pilih kereta dan teruskan ke pembayaran:
- ./frontend/src/assets/ folder mengandungi CSS dan imej.
- ./frontend/src/pages/ folder mengandungi halaman React.
- ./frontend/src/komponen/ folder mengandungi komponen React.
- ./frontend/src/services/ mengandungi perkhidmatan klien api.
- ./frontend/src/App.tsx ialah Apl React utama yang mengandungi laluan.
- ./frontend/src/index.tsx ialah titik masuk utama bahagian hadapan.
Takrif jenis TypeScript ditakrifkan dalam pakej ./packages/bookcars-types.
App.tsx ialah Apl tindak balas utama:
const routes = { validate: '/api/validate-country', create: '/api/create-country', update: '/api/update-country/:id', delete: '/api/delete-country/:id', getCountry: '/api/country/:id/:language', getCountries: '/api/countries/:page/:size/:language', getCountriesWithLocations: '/api/countries-with-locations/:language/:imageRequired/:minLocations', checkCountry: '/api/check-country/:id', getCountryId: '/api/country-id/:name/:language', } export default routes
Kami menggunakan React lazy loading untuk memuatkan setiap laluan.
Kami tidak akan menutup setiap halaman bahagian hadapan, tetapi anda boleh membuka kod sumber dan melihat setiap satu jika anda mahu.
Apl Mudah Alih
Platform ini menyediakan apl mudah alih asli untuk Android dan iOS. Apl mudah alih dibina dengan React Native, Expo dan TypeScript. Seperti untuk bahagian hadapan, apl mudah alih membolehkan pelanggan mencari kereta yang tersedia bergantung pada tempat pengambilan dan penghantaran serta masa, pilih kereta dan teruskan ke pembayaran.
Pelanggan menerima pemberitahuan tolak jika tempahannya dikemas kini dari bahagian belakang. Pemberitahuan tolak dibina dengan Node.js, SDK Pelayan Ekspo dan Firebase.
- ./mudah alih/aset/ folder mengandungi imej.
- ./mudah alih/skrin/ folder mengandungi skrin React Native utama.
- ./mudah alih/komponen/ folder mengandungi komponen React Native.
- ./mobile/services/ mengandungi perkhidmatan pelanggan api.
- ./mobile/App.tsx ialah Apl React Native yang utama.
Takrif jenis TypeScript ditakrifkan dalam:
- ./mobile/types/index.d.ts
- ./mobile/types/env.d.ts
- ./mobile/miscellaneous/bookcarsTypes.ts
./mobile/types/ dimuatkan dalam ./mobile/tsconfig.json seperti berikut:
import { Schema, model } from 'mongoose' import * as env from '../config/env.config' const countrySchema = new Schema<env.Country>( { values: { type: [Schema.Types.ObjectId], ref: 'LocationValue', required: [true, "can't be blank"], validate: (value: any): boolean => Array.isArray(value), }, }, { timestamps: true, strict: true, collection: 'Country', }, ) const Country = model<env.Country>('Country', countrySchema) export default Country
App.tsx ialah pintu masuk utama apl React Native:
import 'react-native-gesture-handler' import React, { useCallback, useEffect, useRef, useState } daripada 'react' import { RootSiblingParent } daripada 'react-native-root-siblings' import { NavigationContainer, NavigationContainerRef } daripada '@react-navigation/native' import { StatusBar sebagai ExpoStatusBar } daripada 'expo-status-bar' import { SafeAreaProvider } daripada 'react-native-safe-area-context' import { Provider } daripada 'react-native-paper' import * sebagai SplashScreen daripada 'expo-splash-screen' import * sebagai Pemberitahuan daripada 'pemberitahuan ekspo' import { StripeProvider } daripada '@stripe/stripe-react-native' import DrawerNavigator daripada './components/DrawerNavigator' import * sebagai pembantu daripada './common/helper' import * sebagai NotificationService daripada './services/NotificationService' import * sebagai UserService daripada './services/UserService' import { GlobalProvider } daripada './context/GlobalContext' import * sebagai env daripada './config/env.config' Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowAlert: benar, shouldPlaySound: benar, shouldSetBadge: benar, }), }) // // Cegah skrin percikan asli daripada menyorok secara automatik sebelum pengisytiharan komponen Apl // SplashScreen.preventAutoHideAsync() .then((result) => console.log(`SplashScreen.preventAutoHideAsync() berjaya: ${result}`)) .catch(console.warn) // adalah baik untuk menangkap dan memeriksa sebarang ralat secara eksplisit const App = () => { const [appIsReady, setAppIsReady] = useState(false) const responseListener = useRef<Pemberitahuan.Langganan>() const navigationRef = useRef<NavigationContainerRef<StackParams>>(null) useEffect(() => { daftar const = tak segerak () => { const loggedIn = tunggu UserService.loggedIn() jika (log masuk) { const currentUser = menunggu UserService.getCurrentUser() jika (Pengguna semasa?._id) { tunggu helper.registerPushToken(currentUser._id) } lain { helper.error() } } } // // Daftar token pemberitahuan tolak // daftar() // // Pendengar ini dipecat apabila pengguna mengetik atau berinteraksi dengan pemberitahuan (berfungsi apabila apl di latar depan, berlatar belakang atau dimatikan) // responseListener.current = Notifications.addNotificationResponseReceivedListener(async (respons) => { cuba { jika (navigationRef.current) { const { data } = respons.notification.request.content jika (data.booking) { if (data.user && data.notification) { tunggu NotificationService.markAsRead(data.user, [data.notification]) } navigationRef.current.navigate('Booking', { id: data.booking }) } lain { navigationRef.current.navigate('Pemberitahuan', {}) } } } tangkap (err) { helper.error(err, false) } }) pulangan () => { Notifications.removeNotificationSubscription(responseListener.current!) } }, []) setTimeout(() => { setAppIsReady(benar) }, 500) const onReady = useCallback(async () => { jika (appIsReady) { // // Ini memberitahu skrin percikan untuk bersembunyi serta-merta! Jika kita memanggil ini selepas // `setAppIsReady`, maka kita mungkin melihat skrin kosong semasa apl itu // memuatkan keadaan awalnya dan memaparkan piksel pertamanya. Jadi sebaliknya, // kami menyembunyikan skrin percikan sebaik sahaja kami mengetahui paparan akar sudah ada // susun atur yang dilakukan. // tunggu SplashScreen.hideAsync() } }, [appIsReady]) jika (!appIsReady) { kembali null } kembali ( <Penyedia Global> <SafeAreaProvider> <Pembekal> <StripeProvider publishableKey={env.STRIPE_PUBLISHABLE_KEY} merchantIdentifier={env.STRIPE_MERCHANT_IDENTIFIER}> <RootSiblingParent> <NavigationContainer ref={navigationRef} onReady={onReady}> <ExpoStatusBar> <p>Kami tidak akan menutup setiap skrin apl mudah alih, tetapi anda boleh membuka kod sumber dan melihat setiap satu jika anda mahu.</p> <h2> Papan Pemuka Pentadbir </h2> <p>Papan pemuka pentadbir ialah aplikasi web yang dibina dengan Node.js, React, MUI dan TypeScript. Dari bahagian belakang, pentadbir boleh membuat dan mengurus pembekal, kereta, lokasi, pelanggan dan tempahan. Apabila pembekal baharu dibuat dari bahagian belakang, mereka akan menerima e-mel yang menggesa mereka untuk membuat akaun untuk mengakses bahagian belakang dan mengurus armada dan tempahan kereta mereka.</p>
- ./backend/assets/ folder mengandungi CSS dan imej.
- ./backend/pages/ folder mengandungi halaman React.
- ./backend/komponen/ folder mengandungi komponen React.
- ./backend/services/ mengandungi perkhidmatan pelanggan api.
- ./backend/App.tsx ialah Apl Reaksi utama yang mengandungi laluan.
- ./backend/index.tsx ialah titik masuk utama papan pemuka pentadbir.
Takrif jenis TypeScript ditakrifkan dalam pakej ./packages/bookcars-types.
App.tsx bahagian belakang mengikut logik yang serupa seperti App.tsx bahagian hadapan.
Kami tidak akan menutup setiap halaman papan pemuka pentadbir tetapi anda boleh membuka kod sumber dan melihat setiap satu jika anda mahu.
Tempat Menarik
Membina apl mudah alih dengan React Native dan Expo adalah sangat mudah. Ekspo menjadikan pembangunan mudah alih dengan React Native sangat mudah.
Menggunakan bahasa yang sama (TypeScript) untuk pembangunan hujung belakang, bahagian hadapan dan mudah alih adalah sangat mudah.
TypeScript ialah bahasa yang sangat menarik dan mempunyai banyak kelebihan. Dengan menambahkan penaipan statik pada JavaScript, kami boleh mengelakkan banyak pepijat dan menghasilkan kod berkualiti tinggi, berskala, lebih mudah dibaca dan boleh diselenggara yang mudah untuk nyahpepijat dan diuji.
Itu sahaja! Saya harap anda seronok membaca artikel ini.
Sumber
- Ikhtisar
- Seni Bina
- Memasang (Dihoskan sendiri)
- Memasang (VPS)
-
Memasang (Docker)
- Imej Docker
- SSL
- Sediakan Jalur
- Bina Apl Mudah Alih
-
Pangkalan Data Demo
- Windows, Linux dan macOS
- Pelabuh
- Larikan dari Sumber
-
Jalankan Apl Mudah Alih
- Prasyarat
- Arahan
- Pemberitahuan Tolak
- Tukar Mata Wang
- Tambah Bahasa Baharu
- Ujian Unit dan Liputan
- Balak
Atas ialah kandungan terperinci Dari Sifar ke Etalase: Perjalanan Saya Membina Laman Web Sewa Kereta dan Apl Mudah Alih. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Terdapat tiga cara biasa untuk memulakan permintaan HTTP dalam node.js: Gunakan modul terbina dalam, axios, dan nod-fetch. 1. Gunakan modul HTTP/HTTPS terbina dalam tanpa kebergantungan, yang sesuai untuk senario asas, tetapi memerlukan pemprosesan manual jahitan data dan pemantauan ralat, seperti menggunakan https.get () untuk mendapatkan data atau menghantar permintaan pos melalui .write (); 2.AXIOS adalah perpustakaan pihak ketiga berdasarkan janji. Ia mempunyai sintaks ringkas dan fungsi yang kuat, menyokong async/menunggu, penukaran JSON automatik, pemintas, dan lain -lain. Adalah disyorkan untuk memudahkan operasi permintaan tak segerak; 3.Node-Fetch menyediakan gaya yang serupa dengan pengambilan penyemak imbas, berdasarkan janji dan sintaks mudah

Jenis data JavaScript dibahagikan kepada jenis primitif dan jenis rujukan. Jenis primitif termasuk rentetan, nombor, boolean, null, undefined, dan simbol. Nilai -nilai tidak berubah dan salinan disalin apabila memberikan nilai, jadi mereka tidak mempengaruhi satu sama lain; Jenis rujukan seperti objek, tatasusunan dan fungsi menyimpan alamat memori, dan pembolehubah menunjuk objek yang sama akan mempengaruhi satu sama lain. Typeof dan Instanceof boleh digunakan untuk menentukan jenis, tetapi memberi perhatian kepada isu -isu sejarah TypeOfNull. Memahami kedua -dua jenis perbezaan ini dapat membantu menulis kod yang lebih stabil dan boleh dipercayai.

Helo, pemaju JavaScript! Selamat datang ke berita JavaScript minggu ini! Minggu ini kami akan memberi tumpuan kepada: Pertikaian tanda dagangan Oracle dengan Deno, objek masa JavaScript baru disokong oleh pelayar, kemas kini Google Chrome, dan beberapa alat pemaju yang kuat. Mari mulakan! Pertikaian tanda dagangan Oracle dengan percubaan Deno Oracle untuk mendaftarkan tanda dagangan "JavaScript" telah menyebabkan kontroversi. Ryan Dahl, pencipta Node.js dan Deno, telah memfailkan petisyen untuk membatalkan tanda dagangan, dan dia percaya bahawa JavaScript adalah standard terbuka dan tidak boleh digunakan oleh Oracle

Janji adalah mekanisme teras untuk mengendalikan operasi tak segerak dalam JavaScript. Memahami panggilan rantaian, pengendalian ralat dan gabungan adalah kunci untuk menguasai aplikasi mereka. 1. Panggilan rantai mengembalikan janji baru melalui .then () untuk merealisasikan persamaan proses tak segerak. Setiap .then () menerima hasil sebelumnya dan boleh mengembalikan nilai atau janji; 2. Pengendalian ralat harus menggunakan .catch () untuk menangkap pengecualian untuk mengelakkan kegagalan senyap, dan boleh mengembalikan nilai lalai dalam tangkapan untuk meneruskan proses; 3. Gabungan seperti janji.all () (berjaya hanya berjaya selepas semua kejayaan), janji.race () (penyempurnaan pertama dikembalikan) dan janji.allsettled () (menunggu semua penyelesaian)

CACHEAPI adalah alat yang disediakan oleh penyemak imbas kepada permintaan rangkaian cache, yang sering digunakan bersempena dengan ServiceWorker untuk meningkatkan prestasi laman web dan pengalaman luar talian. 1. Ia membolehkan pemaju menyimpan sumber secara manual seperti skrip, helaian gaya, gambar, dan lain -lain; 2. Ia boleh memadankan tindak balas cache mengikut permintaan; 3. Ia menyokong memotong cache tertentu atau membersihkan seluruh cache; 4. Ia boleh melaksanakan keutamaan cache atau strategi keutamaan rangkaian melalui perkhidmatan pekerja yang mendengar acara mengambil; 5. Ia sering digunakan untuk sokongan luar talian, mempercepat kelajuan akses berulang, sumber utama dan kandungan kemas kini latar belakang; 6. Apabila menggunakannya, anda perlu memberi perhatian kepada kawalan versi cache, sekatan penyimpanan dan perbezaan dari mekanisme caching HTTP.

Gelung acara JavaScript menguruskan operasi tak segerak dengan menyelaraskan susunan panggilan, webapis, dan barisan tugas. 1. Stack panggilan melaksanakan kod segerak, dan ketika menghadapi tugas -tugas yang tidak segerak, ia diserahkan kepada Webapi untuk diproses; 2. Selepas Webapi melengkapkan tugas di latar belakang, ia meletakkan panggil balik ke dalam barisan yang sama (tugas makro atau tugas mikro); 3. Loop acara memeriksa sama ada timbunan panggilan kosong. Jika ia kosong, panggilan balik diambil dari barisan dan ditolak ke dalam tumpukan panggilan untuk pelaksanaan; 4. Tugas -tugas mikro (seperti janji. 5. Memahami gelung acara membantu mengelakkan menyekat benang utama dan mengoptimumkan pesanan pelaksanaan kod.

Gelembung peristiwa menyebarkan dari elemen sasaran ke luar ke nod nenek moyang, sementara penangkapan peristiwa menyebarkan dari lapisan luar ke dalam ke elemen sasaran. 1. Bubbles Acara: Selepas mengklik elemen kanak -kanak, acara itu mencetuskan pendengar elemen induk ke atas. Sebagai contoh, selepas mengklik butang, ia mengeluarkan anak -anak terlebih dahulu, dan kemudian ParentClicked. 2. Tangkap Acara: Tetapkan parameter ketiga menjadi benar, supaya pendengar dilaksanakan di peringkat penangkapan, seperti mencetuskan pendengar penangkapan elemen induk sebelum mengklik butang. 3. Penggunaan praktikal termasuk pengurusan bersatu peristiwa elemen kanak -kanak, pemprosesan pemintasan dan pengoptimuman prestasi. 4. Aliran acara DOM dibahagikan kepada tiga peringkat: menangkap, sasaran dan gelembung, dan pendengar lalai dilaksanakan di peringkat gelembung.

Dalam tatasusunan JavaScript, sebagai tambahan kepada peta dan penapis, terdapat kaedah lain yang kuat dan jarang digunakan. 1. Mengurangkan bukan sahaja dapat jumlah, tetapi juga mengira, kumpulan, array meratakan, dan membina struktur baru; 2. Cari dan FindIndex digunakan untuk mencari elemen atau indeks individu; 3. Beberapa dan segala -galanya digunakan untuk menentukan sama ada keadaan wujud atau semua memenuhi; 4.Sort boleh disusun tetapi akan mengubah array asal; 5. Beri perhatian untuk menyalin array apabila menggunakannya untuk mengelakkan kesan sampingan. Kaedah ini menjadikan kod lebih ringkas dan cekap.
