برنامه نویسی

🌷ایجاد اپلیکیشن گالری در جاوا اسکریپت با HMPL

Summarize this content to 400 words in Persian Lang
سلام به همه! در این مقاله روند ایجاد یک برنامه گالری را شرح خواهم داد. شما می توانید با خیال راحت این برنامه را بردارید و آن را همانطور که می خواهید ویرایش کنید (فقط می توانید تصاویر را در آنجا تغییر دهید، زیرا مجوز وجود دارد). از نظر عملکرد کوچک است ، اما به نظر من برای نمونه کار کاملاً مناسب است.

ظاهر اپلیکیشن چیست و چه کاربردی دارد؟

برنامه یک لیست کوچک از تصاویر است که می توان در صفحات آن پیمایش کرد. رابط کاربری به شکل زیر است:

دسکتاپ

موبایل

از نظر کارایی می توانید روی دکمه Next کلیک کنید و به صفحه بعد بروید و با زدن دکمه Previous به صفحه اول بازگردید.

همچنین، اگر روی هر یک از تصاویر کلیک کنید، می توانید آن را به صورت کامل مشاهده کنید:

این قابلیت اصلی است که در برنامه موجود است.

ظرافت های برنامه

یکی از ویژگی های اصلی این اپلیکیشن این است که تصاویر، مانند متن عنوان، از سرور می آیند. یعنی 10 تصویر را در مخزن سایت روی کلاینت ذخیره نمی کنیم. همه آنها از سرور می آیند. این را می توان با رویکردی به دست آورد که در آن HTML محتوای اصلی را روی سرور ذخیره می کنیم و در مشتری آن را به برخی سلول ها خروجی می دهیم که در اصل فضای کمی را روی دیسک اشغال می کنند.

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

همچنین، روی کلاینت در مرورگر، اگر بارگذاری برنامه را بگیریم، می تواند برای اولین بار در هنگام ورود کاربر به سایت، برای چند ثانیه بارگذاری شود. او می تواند این منبع را ببندد و به سراغ منبع دیگری برود، بنابراین از نظر پولی این می تواند در برخی موارد در بودجه شما صرفه جویی کند.

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

در هر صورت امروزه چنین راهی برای ایجاد یک وب سایت وجود دارد و کاملا راحت است و مزایای خود را دارد. امروزه بسیاری از کتابخانه ها عملکرد مشابهی را اجرا می کنند. یکی از این موارد HMPL است.

فرآیند توسعه و خود کد

اول از همه، شما باید پلتفرم هایی را انتخاب کنید که برنامه روی آنها نوشته شود. منظور ما از پلتفرم هاست Express.js برای باطن، و به طور کلی Node.js، به ترتیب، و در مشتری ما یک ساده خواهیم داشت بسته وب مونتاژ

سمت مشتری

رویکردهای متفاوتی برای شروع از کجا وجود دارد. از سرور یا از مشتری. در مورد ما، بهتر است از مشتری شروع کنیم، زیرا در سرور می دانیم که لیست تصاویر و عنوان قبلاً تولید می شود، اما چگونه آنها را به بهترین نحو در DOM ادغام کنیم – این دقیقاً همان چیزی است که باید انجام دهیم. اول بفهم

بیایید به فایل HTML اصلی برویم:

index.html

lang=”en”https://dev.to/anthonymax/>

charset=”UTF-8″ />
name=”viewport” content=”width=device-width, initial-scale=1.0″ />
Gallery App

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

به نظر می رسد که اینجا چیزی نیست، و بله، شما درست می گویید. مؤلفه هایی که محتوا خواهند بود در این فایل بارگذاری می شوند. ما آنها را در ایجاد خواهیم کرد .hmpl فایل های پسوندی که کمی قابلیت های html را گسترش می دهند.

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

Gallery.hmpl

class=”gallery-initial” id=”gallery-initial”https://dev.to/anthonymax/>
{
{
src: “http://localhost:8000/api/images”,
method: “POST”
}
}

class=”gallery” id=”gallery”https://dev.to/anthonymax/>
{
{
src: “http://localhost:8000/api/images”,
after:
“click:.navigation-button”,
method: “POST”
}
}

class=”pagination”https://dev.to/anthonymax/>
class=”navigation-button” data-page=”1″ id=”previous” disabled>
Previous

class=”navigation-button” data-page=”2″ id=”next”https://dev.to/anthonymax/>Next

class=”modal” id=”modal”https://dev.to/anthonymax/>

src=”https://raw.githubusercontent.com/hmpl-language/media/refs/heads/main/logo.png”
alt=””
/>

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

عنوان.hmpl

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا، اشیاء از سرور به HTML تغییر خواهند کرد. در حال حاضر، آنها باید متصل شوند. برای انجام این کار، آنها را به main.js وارد کنید:

import “https://dev.to/anthonymax/./index.scss”https://dev.to/anthonymax/;
import GalleryTemplate from “https://dev.to/anthonymax/./components/Gallery/Gallery.hmpl”https://dev.to/anthonymax/;
import TitleTemplate from “https://dev.to/anthonymax/./components/Title/Title.hmpl”https://dev.to/anthonymax/;

const { response: Title } = TitleTemplate();

const { response: Gallery } = GalleryTemplate(({ request: { event } }) => {
return {
headers: {
“https://dev.to/anthonymax/Content-Type”https://dev.to/anthonymax/: “https://dev.to/anthonymax/application/json”https://dev.to/anthonymax/,
},
body: JSON.stringify({
page: event ? Number(event.target.getAttribute(“https://dev.to/anthonymax/data-page”https://dev.to/anthonymax/)) : 1,
}),
};
});

document.body.append(Title);
document.body.append(Gallery);

const gallery = document.querySelector(“https://dev.to/anthonymax/#gallery”https://dev.to/anthonymax/);
const galleryInitial = document.querySelector(“https://dev.to/anthonymax/#gallery-initial”https://dev.to/anthonymax/);
const modal = document.querySelector(“https://dev.to/anthonymax/#modal”https://dev.to/anthonymax/);
const modalImg = modal.querySelector(“https://dev.to/anthonymax/img”https://dev.to/anthonymax/);
const navigationButtons = document.querySelectorAll(“https://dev.to/anthonymax/.navigation-button”https://dev.to/anthonymax/);

const setActive = (e) => {
if (e.target.tagName === “https://dev.to/anthonymax/IMG”https://dev.to/anthonymax/) {
modalImg.src = e.target.src;
modal.classList.add(“https://dev.to/anthonymax/active”https://dev.to/anthonymax/);
}
};

modal.addEventListener(“https://dev.to/anthonymax/click”https://dev.to/anthonymax/, () => {
modal.classList.remove(“https://dev.to/anthonymax/active”https://dev.to/anthonymax/);
});

galleryInitial.addEventListener(“https://dev.to/anthonymax/click”https://dev.to/anthonymax/, (e) => {
setActive(e);
});

gallery.addEventListener(“https://dev.to/anthonymax/click”https://dev.to/anthonymax/, (e) => {
setActive(e);
});

for (let i = 0; i < navigationButtons.length; i++) {
const btn = navigationButtons[i];
btn.addEventListener(“https://dev.to/anthonymax/click”https://dev.to/anthonymax/, () => {
if (!galleryInitial.classList.contains(“https://dev.to/anthonymax/hidden”https://dev.to/anthonymax/))
galleryInitial.classList.add(“https://dev.to/anthonymax/hidden”https://dev.to/anthonymax/);
btn.setAttribute(“https://dev.to/anthonymax/disabled”https://dev.to/anthonymax/, “”https://dev.to/anthonymax/);
navigationButtons[i === 0 ? 1 : 0].removeAttribute(“https://dev.to/anthonymax/disabled”https://dev.to/anthonymax/);
});
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، در main.js ما منطق برنامه را شرح خواهیم داد. در اینجا ما درخواستی را به سرور ارسال می کنیم و HTML را دریافت می کنیم که هنوز آن را آماده نکرده ایم اما در طی مراحل توسعه آن را آماده خواهیم کرد. از آنجایی که HTML سرور در div بلوک، ما به راحتی می توانیم اجزایی را به DOM اضافه کنیم بدون اینکه منتظر پاسخ باشیم.

در اینجا باید سوییچ دیگری بین آن اضافه کنید disabled ویژگی برای دکمه ها در حالت ایده آل، ارزش دریافت تعداد صفحات از سرور و تمرکز روی آن را دارد، اما از آنجایی که برنامه خود کوچک است و همه ثابت ها از قبل مشخص هستند، بهتر است آن را با کد اضافی اضافه نکنید. به هر حال، تغییر تصویر به طور خودکار و در صورت درخواست به API اتفاق می افتد.

و همچنین لازم است تصویر را روی کلیک نشان دهید – این کار با آویزان کردن یک رویداد بر روی برچسب wrapper و تعیین اینکه اگر یک کلیک روی تصویر باشد، بلوک باید بر این اساس فعال شود انجام می شود.

سبک هایی که ما اضافه می کنیم به شکل زیر هستند:

index.scss

body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f4f4f4;
}

h1 {
margin: 20px 0;
color: #333;
}

.gallery-initial.active {
display: flex;
}

.gallery,
.gallery-initial {
display: flex;
gap: 20px;
width: 90%;
max-width: 1000px;

@media (max-width:1023px) {
display: grid;
grid-template-columns: repeat(2, 1fr);
max-width: unset;
justify-content: center;
align-items: center;
width: 100%;
}
}

.hidden {
display: none;
}

.gallery img,
.gallery-initial img {
width: 150px;
height: 100px;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: transform 0.2s;
}

.gallery img:hover,
.gallery-initial img:hover {
transform: scale(1.05);
}

.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
justify-content: center;
align-items: center;
}

.modal img {
max-width: 90%;
max-height: 90%;
border-radius: 10px;
}

.modal.active {
display: flex;
}

.pagination {
margin: 20px 0;
display: flex;
gap: 10px;
align-items: center;
justify-content: center;
}

.pagination button {
padding: 10px 20px;
border: none;
background-color: #333;
color: #fff;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.2s;
}

.pagination button:hover {
background-color: #555;
}

.pagination button:disabled {
background-color: #ccc;
cursor: not-allowed;
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سبک ها مینیمال هستند، فقط به این دلیل که گالری کم و بیش قابل ارائه به نظر برسد.

همچنین، من معمولاً از مجموعه های آماده وب پک استفاده می کنم که مدت ها پیش ساخته بودم (باید یک وب سایت برای فریم ورک بسازم)، اما اکنون دیگر هیچ فایده ای ندارد که در مورد هر یک از مواردی که مسئول چه چیزی است صحبت کنم. webpack.config.js. فایل در اینجا قابل مشاهده است.

اکنون زمان آن رسیده است که به سمت باطن حرکت کنیم.

Backend

هنگام ایجاد یک Backend، اکنون می توانیم با آرامش به مشتری نگاه کنیم و بر این اساس مسیرهای مورد نیاز برای آن را ایجاد کنیم. فرض کنید من یک گالری ایجاد کردم – عالی است، سپس باید تصاویر را دانلود کنم و مسیری را که در آنجا توضیح داده شده است تنظیم کنم.

می بینیم که مسیری که باید ایجاد شود همین است /api/images:

src: “http://localhost:8000/api/images”,

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون، برای آن، فقط باید نشانه گذاری HTML را که در پاسخ صادر می شود، آماده کنید. علاوه بر این، روش برای مسیر خواهد بود POST، زیرا در body از RequestInit شما باید عبور کنید page با مقدار لازم بیایید یک مسیر مشابه را تعیین کنیم:

routes/post.js

const express = require(“https://dev.to/anthonymax/express”https://dev.to/anthonymax/);
const expressRouter = express.Router();

const imagePaths = [
“https://dev.to/anthonymax/http://localhost:8000/images/img1.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img2.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img3.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img4.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img5.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img6.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img7.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img8.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img9.jpg”https://dev.to/anthonymax/,
“https://dev.to/anthonymax/http://localhost:8000/images/img10.jpg”https://dev.to/anthonymax/,
];

const imagesController = (req, res) => {
const { page } = req.body;

if (!page || isNaN(page)) {
return res.status(400).send(“https://dev.to/anthonymax/Page number error”https://dev.to/anthonymax/);
}

const pageNumber = parseInt(page);
const itemsPerPage = 5;
const startIndex = (pageNumber – 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;

if (startIndex >= imagePaths.length || pageNumber < 1) {
return res.status(404).send(“https://dev.to/anthonymax/Page not found”https://dev.to/anthonymax/);
}

const imagesForPage = imagePaths.slice(startIndex, endIndex);

const htmlResponse = `
${imagesForPage
.map((img, index) => `${img}” alt=”تصویر${index}”/>`)
.join(“https://dev.to/anthonymax/\n”https://dev.to/anthonymax/)}
`;

res.send(htmlResponse);
};

expressRouter.post(“https://dev.to/anthonymax//images”https://dev.to/anthonymax/, imagesController);

module.exports = expressRouter;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

حالا، خیلی ساده است. هنگامی که ما یک GET درخواست برای دریافت عنوان، ما یک فایل html ساده ارسال می کنیم. در اینجا به صورت کد به نظر می رسد:

routes/get.js

const express = require(“https://dev.to/anthonymax/express”https://dev.to/anthonymax/);
const expressRouter = express.Router();
const path = require(“https://dev.to/anthonymax/path”https://dev.to/anthonymax/);

const titleController = (req, res) => {
res.sendFile(path.join(__dirname, “https://dev.to/anthonymax/../components/GET/title.html”https://dev.to/anthonymax/));
};

expressRouter.use(“https://dev.to/anthonymax//title”https://dev.to/anthonymax/, titleController);

module.exports = expressRouter;

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در فایل html فقط یک خواهیم داشت span با متن برنامه گالری و بس در اصل، امکان ایجاد یک POST درخواست کنید و چندزبانگی را به برنامه اضافه کنید، اما این بار دیگر بر روی برنامه کاربردی است. می خواستم آن را کم و بیش ساده و در عین حال زیبا و کاربردی کنم.

اکنون تنها چیزی که باقی می ماند این است که همه اینها را به یک فایل متصل کرده و سرور خود را راه اندازی کنیم. برای انجام این کار، بیایید فایل های خود را وارد کنیم و یک برنامه اکسپرس ایجاد کنیم:

app.js

const express = require(“https://dev.to/anthonymax/express”https://dev.to/anthonymax/);
const path = require(“https://dev.to/anthonymax/path”https://dev.to/anthonymax/);
const bodyParser = require(“https://dev.to/anthonymax/body-parser”https://dev.to/anthonymax/);
const cors = require(“https://dev.to/anthonymax/cors”https://dev.to/anthonymax/);

const PORT = 8000;
const app = express();

const getRoutes = require(“https://dev.to/anthonymax/./routes/get”https://dev.to/anthonymax/);
const postRoutes = require(“https://dev.to/anthonymax/./routes/post”https://dev.to/anthonymax/);

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors({ origin: true, credentials: true }));

const imagesFolder = path.join(__dirname, “https://dev.to/anthonymax/./images”https://dev.to/anthonymax/);
app.use(“https://dev.to/anthonymax//images”https://dev.to/anthonymax/, express.static(imagesFolder));

app.use(express.static(path.join(__dirname, “https://dev.to/anthonymax/src”https://dev.to/anthonymax/)));

app.get(“https://dev.to/anthonymax//”https://dev.to/anthonymax/, (req, res) => {
res.sendFile(path.join(__dirname, “https://dev.to/anthonymax/src/index.html”https://dev.to/anthonymax/));
});

app.use(“https://dev.to/anthonymax//api”https://dev.to/anthonymax/, getRoutes);
app.use(“https://dev.to/anthonymax//api”https://dev.to/anthonymax/, postRoutes);

app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا ما راه اندازی کردیم CORS تا بتوانیم از دیگری درخواست ارسال کنیم localhost پورت، و همچنین بارگذاری تصاویر از یک پوشه. به طور خاص، ما این کار را در اینجا انجام می دهیم:

const imagesFolder = path.join(__dirname, “https://dev.to/anthonymax/./images”https://dev.to/anthonymax/);
app.use(“https://dev.to/anthonymax//images”https://dev.to/anthonymax/, express.static(imagesFolder));

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، شما می توانید خود را مشخص کنید PORT برای سرور، اما من پیش فرض را مشخص کردم 8000. شما همچنین باید پیکربندی کنید bodyParser برای کار راحت با HTML و در واقع فقط مسیرها را به api متصل کنید. و اکنون، من فکر می کنم، شما می توانید با خیال راحت از برنامه استفاده کنید!

نتیجه گیری

این برنامه، حتی چنین به ظاهر کوچک، با توجه به اینکه حداقل عملکرد اجرا شده بود، بسیار پیچیده بود. اما، این نیز جالب است، زیرا زمینه ای برای تغییرات، مونتاژ با کیفیت بالا و ماژول های ساده مدرن وجود دارد. شما می توانید backend را در PHP یا چیز دیگری پیاده سازی کنید، معنی برای کلاینت تغییر چندانی نخواهد کرد، بنابراین فکر می کنم که این برنامه حتی می تواند به عنوان یک پروژه حیوان خانگی نیز به خوبی پیش برود.

از همه شما برای خواندن مقاله بسیار سپاسگزارم! خیلی بزرگ بود، حتی در موردی که سعی کردم روایت را در جایی کوتاه کنم، جایی که ظرافت ها را پوشش ندهد، اما با این وجود بسیار زیاد بود، اما، امیدوارم، برای شما جالب و مفید باشد!

مخزن پروژه

این پروژه در GitHub قرار دارد. در آنجا می توانید با جزئیات بیشتر با کد آشنا شوید. در آینده ممکن است پروژه های دیگری نیز وجود داشته باشد که مشابه و یا حتی سردتر باشند.

لیست برنامه های کاربردی در HMPL

این مخزن شامل لیستی از برنامه های آزمایشی است که با استفاده از زبان قالب HMPL نوشته شده اند. می توانید با خیال راحت آنها را بگیرید و آنها را تغییر دهید (فقط تصاویر باید جایگزین شوند).

برنامه گالری

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

همچنین، خوشحال خواهم شد که از آن حمایت کنید پروژه با ستاره شما. متشکرم

ستاره HMPL ☆

سلام به همه! در این مقاله روند ایجاد یک برنامه گالری را شرح خواهم داد. شما می توانید با خیال راحت این برنامه را بردارید و آن را همانطور که می خواهید ویرایش کنید (فقط می توانید تصاویر را در آنجا تغییر دهید، زیرا مجوز وجود دارد). از نظر عملکرد کوچک است ، اما به نظر من برای نمونه کار کاملاً مناسب است.

ظاهر اپلیکیشن چیست و چه کاربردی دارد؟

برنامه یک لیست کوچک از تصاویر است که می توان در صفحات آن پیمایش کرد. رابط کاربری به شکل زیر است:

دسکتاپ

دسکتاپ

موبایل

موبایل

از نظر کارایی می توانید روی دکمه Next کلیک کنید و به صفحه بعد بروید و با زدن دکمه Previous به صفحه اول بازگردید.

صفحه دوم

همچنین، اگر روی هر یک از تصاویر کلیک کنید، می توانید آن را به صورت کامل مشاهده کنید:

فرمت کامل

این قابلیت اصلی است که در برنامه موجود است.

ظرافت های برنامه

یکی از ویژگی های اصلی این اپلیکیشن این است که تصاویر، مانند متن عنوان، از سرور می آیند. یعنی 10 تصویر را در مخزن سایت روی کلاینت ذخیره نمی کنیم. همه آنها از سرور می آیند. این را می توان با رویکردی به دست آورد که در آن HTML محتوای اصلی را روی سرور ذخیره می کنیم و در مشتری آن را به برخی سلول ها خروجی می دهیم که در اصل فضای کمی را روی دیسک اشغال می کنند.

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

همچنین، روی کلاینت در مرورگر، اگر بارگذاری برنامه را بگیریم، می تواند برای اولین بار در هنگام ورود کاربر به سایت، برای چند ثانیه بارگذاری شود. او می تواند این منبع را ببندد و به سراغ منبع دیگری برود، بنابراین از نظر پولی این می تواند در برخی موارد در بودجه شما صرفه جویی کند.

hm

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

در هر صورت امروزه چنین راهی برای ایجاد یک وب سایت وجود دارد و کاملا راحت است و مزایای خود را دارد. امروزه بسیاری از کتابخانه ها عملکرد مشابهی را اجرا می کنند. یکی از این موارد HMPL است.

فرآیند توسعه و خود کد

اول از همه، شما باید پلتفرم هایی را انتخاب کنید که برنامه روی آنها نوشته شود. منظور ما از پلتفرم هاست Express.js برای باطن، و به طور کلی Node.js، به ترتیب، و در مشتری ما یک ساده خواهیم داشت بسته وب مونتاژ

سمت مشتری

رویکردهای متفاوتی برای شروع از کجا وجود دارد. از سرور یا از مشتری. در مورد ما، بهتر است از مشتری شروع کنیم، زیرا در سرور می دانیم که لیست تصاویر و عنوان قبلاً تولید می شود، اما چگونه آنها را به بهترین نحو در DOM ادغام کنیم – این دقیقاً همان چیزی است که باید انجام دهیم. اول بفهم

بیایید به فایل HTML اصلی برویم:

index.html


 lang="en"https://dev.to/anthonymax/>
  
     charset="UTF-8" />
     name="viewport" content="width=device-width, initial-scale=1.0" />
    </span>Gallery App<span class="nt"/>
  <span class="nt"/>
  <span class="nt"/>
<span class="nt"/>
</span></span></span></code></pre>
<div class="highlight__panel js-actions-panel">
<div class="highlight__panel-action js-fullscreen-code-action">
    <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>وارد حالت تمام صفحه شوید
    

از حالت تمام صفحه خارج شوید

به نظر می رسد که اینجا چیزی نیست، و بله، شما درست می گویید. مؤلفه هایی که محتوا خواهند بود در این فایل بارگذاری می شوند. ما آنها را در ایجاد خواهیم کرد .hmpl فایل های پسوندی که کمی قابلیت های html را گسترش می دهند.

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

Gallery.hmpl

class="gallery-initial" id="gallery-initial"https://dev.to/anthonymax/> { { src: "http://localhost:8000/api/images", method: "POST" } }

class="gallery" id="gallery"https://dev.to/anthonymax/> { { src: "http://localhost:8000/api/images", after: "click:.navigation-button", method: "POST" } }

class="pagination"https://dev.to/anthonymax/>

class="modal" id="modal"https://dev.to/anthonymax/> src="https://raw.githubusercontent.com/hmpl-language/media/refs/heads/main/logo.png" alt="" />
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

عنوان.hmpl


وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در اینجا، اشیاء از سرور به HTML تغییر خواهند کرد. در حال حاضر، آنها باید متصل شوند. برای انجام این کار، آنها را به main.js وارد کنید:

import "https://dev.to/anthonymax/./index.scss"https://dev.to/anthonymax/;
import GalleryTemplate from "https://dev.to/anthonymax/./components/Gallery/Gallery.hmpl"https://dev.to/anthonymax/;
import TitleTemplate from "https://dev.to/anthonymax/./components/Title/Title.hmpl"https://dev.to/anthonymax/;

const { response: Title } = TitleTemplate();

const { response: Gallery } = GalleryTemplate(({ request: { event } }) => {
  return {
    headers: {
      "https://dev.to/anthonymax/Content-Type"https://dev.to/anthonymax/: "https://dev.to/anthonymax/application/json"https://dev.to/anthonymax/,
    },
    body: JSON.stringify({
      page: event ? Number(event.target.getAttribute("https://dev.to/anthonymax/data-page"https://dev.to/anthonymax/)) : 1,
    }),
  };
});

document.body.append(Title);
document.body.append(Gallery);

const gallery = document.querySelector("https://dev.to/anthonymax/#gallery"https://dev.to/anthonymax/);
const galleryInitial = document.querySelector("https://dev.to/anthonymax/#gallery-initial"https://dev.to/anthonymax/);
const modal = document.querySelector("https://dev.to/anthonymax/#modal"https://dev.to/anthonymax/);
const modalImg = modal.querySelector("https://dev.to/anthonymax/img"https://dev.to/anthonymax/);
const navigationButtons = document.querySelectorAll("https://dev.to/anthonymax/.navigation-button"https://dev.to/anthonymax/);

const setActive = (e) => {
  if (e.target.tagName === "https://dev.to/anthonymax/IMG"https://dev.to/anthonymax/) {
    modalImg.src = e.target.src;
    modal.classList.add("https://dev.to/anthonymax/active"https://dev.to/anthonymax/);
  }
};

modal.addEventListener("https://dev.to/anthonymax/click"https://dev.to/anthonymax/, () => {
  modal.classList.remove("https://dev.to/anthonymax/active"https://dev.to/anthonymax/);
});

galleryInitial.addEventListener("https://dev.to/anthonymax/click"https://dev.to/anthonymax/, (e) => {
  setActive(e);
});

gallery.addEventListener("https://dev.to/anthonymax/click"https://dev.to/anthonymax/, (e) => {
  setActive(e);
});

for (let i = 0; i < navigationButtons.length; i++) {
  const btn = navigationButtons[i];
  btn.addEventListener("https://dev.to/anthonymax/click"https://dev.to/anthonymax/, () => {
    if (!galleryInitial.classList.contains("https://dev.to/anthonymax/hidden"https://dev.to/anthonymax/))
      galleryInitial.classList.add("https://dev.to/anthonymax/hidden"https://dev.to/anthonymax/);
    btn.setAttribute("https://dev.to/anthonymax/disabled"https://dev.to/anthonymax/, ""https://dev.to/anthonymax/);
    navigationButtons[i === 0 ? 1 : 0].removeAttribute("https://dev.to/anthonymax/disabled"https://dev.to/anthonymax/);
  });
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، در main.js ما منطق برنامه را شرح خواهیم داد. در اینجا ما درخواستی را به سرور ارسال می کنیم و HTML را دریافت می کنیم که هنوز آن را آماده نکرده ایم اما در طی مراحل توسعه آن را آماده خواهیم کرد. از آنجایی که HTML سرور در div بلوک، ما به راحتی می توانیم اجزایی را به DOM اضافه کنیم بدون اینکه منتظر پاسخ باشیم.

در اینجا باید سوییچ دیگری بین آن اضافه کنید disabled ویژگی برای دکمه ها در حالت ایده آل، ارزش دریافت تعداد صفحات از سرور و تمرکز روی آن را دارد، اما از آنجایی که برنامه خود کوچک است و همه ثابت ها از قبل مشخص هستند، بهتر است آن را با کد اضافی اضافه نکنید. به هر حال، تغییر تصویر به طور خودکار و در صورت درخواست به API اتفاق می افتد.

و همچنین لازم است تصویر را روی کلیک نشان دهید – این کار با آویزان کردن یک رویداد بر روی برچسب wrapper و تعیین اینکه اگر یک کلیک روی تصویر باشد، بلوک باید بر این اساس فعال شود انجام می شود.

سبک هایی که ما اضافه می کنیم به شکل زیر هستند:

index.scss

body {
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  background-color: #f4f4f4;
}

h1 {
  margin: 20px 0;
  color: #333;
}

.gallery-initial.active {
  display: flex;
}

.gallery,
.gallery-initial {
  display: flex;
  gap: 20px;
  width: 90%;
  max-width: 1000px;

  @media (max-width:1023px) {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
   max-width: unset;
   justify-content: center;
   align-items: center;
   width: 100%;
  }
}

.hidden {
  display: none;
}

.gallery img,
.gallery-initial img {
  width: 150px;
  height: 100px;
  border-radius: 5px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: transform 0.2s;
}

.gallery img:hover,
.gallery-initial img:hover {
  transform: scale(1.05);
}

.modal {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.8);
  justify-content: center;
  align-items: center;
}

.modal img {
  max-width: 90%;
  max-height: 90%;
  border-radius: 10px;
}

.modal.active {
  display: flex;
}

.pagination {
  margin: 20px 0;
  display: flex;
  gap: 10px;
  align-items: center;
  justify-content: center;
}

.pagination button {
  padding: 10px 20px;
  border: none;
  background-color: #333;
  color: #fff;
  border-radius: 5px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.pagination button:hover {
  background-color: #555;
}

.pagination button:disabled {
  background-color: #ccc;
  cursor: not-allowed;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سبک ها مینیمال هستند، فقط به این دلیل که گالری کم و بیش قابل ارائه به نظر برسد.

همچنین، من معمولاً از مجموعه های آماده وب پک استفاده می کنم که مدت ها پیش ساخته بودم (باید یک وب سایت برای فریم ورک بسازم)، اما اکنون دیگر هیچ فایده ای ندارد که در مورد هر یک از مواردی که مسئول چه چیزی است صحبت کنم. webpack.config.js. فایل در اینجا قابل مشاهده است.

اکنون زمان آن رسیده است که به سمت باطن حرکت کنیم.

Backend

هنگام ایجاد یک Backend، اکنون می توانیم با آرامش به مشتری نگاه کنیم و بر این اساس مسیرهای مورد نیاز برای آن را ایجاد کنیم. فرض کنید من یک گالری ایجاد کردم – عالی است، سپس باید تصاویر را دانلود کنم و مسیری را که در آنجا توضیح داده شده است تنظیم کنم.

می بینیم که مسیری که باید ایجاد شود همین است /api/images:

src: "http://localhost:8000/api/images", 
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون، برای آن، فقط باید نشانه گذاری HTML را که در پاسخ صادر می شود، آماده کنید. علاوه بر این، روش برای مسیر خواهد بود POST، زیرا در body از RequestInit شما باید عبور کنید page با مقدار لازم بیایید یک مسیر مشابه را تعیین کنیم:

routes/post.js

const express = require("https://dev.to/anthonymax/express"https://dev.to/anthonymax/);
const expressRouter = express.Router();

const imagePaths = [
  "https://dev.to/anthonymax/http://localhost:8000/images/img1.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img2.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img3.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img4.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img5.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img6.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img7.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img8.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img9.jpg"https://dev.to/anthonymax/,
  "https://dev.to/anthonymax/http://localhost:8000/images/img10.jpg"https://dev.to/anthonymax/,
];

const imagesController = (req, res) => {
  const { page } = req.body;

  if (!page || isNaN(page)) {
    return res.status(400).send("https://dev.to/anthonymax/Page number error"https://dev.to/anthonymax/);
  }

  const pageNumber = parseInt(page);
  const itemsPerPage = 5;
  const startIndex = (pageNumber - 1) * itemsPerPage;
  const endIndex = startIndex + itemsPerPage;

  if (startIndex >= imagePaths.length || pageNumber < 1) {
    return res.status(404).send("https://dev.to/anthonymax/Page not found"https://dev.to/anthonymax/);
  }

  const imagesForPage = imagePaths.slice(startIndex, endIndex);

  const htmlResponse = `
      ${imagesForPage
        .map((img, index) => `span><span class=${img}" alt="تصویر${index}"/>`)
        .join("https://dev.to/anthonymax/\n"https://dev.to/anthonymax/)}
  `;

  res.send(htmlResponse);
};

expressRouter.post("https://dev.to/anthonymax//images"https://dev.to/anthonymax/, imagesController);

module.exports = expressRouter;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

حالا، خیلی ساده است. هنگامی که ما یک GET درخواست برای دریافت عنوان، ما یک فایل html ساده ارسال می کنیم. در اینجا به صورت کد به نظر می رسد:

routes/get.js

const express = require("https://dev.to/anthonymax/express"https://dev.to/anthonymax/);
const expressRouter = express.Router();
const path = require("https://dev.to/anthonymax/path"https://dev.to/anthonymax/);

const titleController = (req, res) => {
  res.sendFile(path.join(__dirname, "https://dev.to/anthonymax/../components/GET/title.html"https://dev.to/anthonymax/));
};

expressRouter.use("https://dev.to/anthonymax//title"https://dev.to/anthonymax/, titleController);

module.exports = expressRouter;
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

در فایل html فقط یک خواهیم داشت span با متن برنامه گالری و بس در اصل، امکان ایجاد یک POST درخواست کنید و چندزبانگی را به برنامه اضافه کنید، اما این بار دیگر بر روی برنامه کاربردی است. می خواستم آن را کم و بیش ساده و در عین حال زیبا و کاربردی کنم.

اکنون تنها چیزی که باقی می ماند این است که همه اینها را به یک فایل متصل کرده و سرور خود را راه اندازی کنیم. برای انجام این کار، بیایید فایل های خود را وارد کنیم و یک برنامه اکسپرس ایجاد کنیم:

app.js

const express = require("https://dev.to/anthonymax/express"https://dev.to/anthonymax/);
const path = require("https://dev.to/anthonymax/path"https://dev.to/anthonymax/);
const bodyParser = require("https://dev.to/anthonymax/body-parser"https://dev.to/anthonymax/);
const cors = require("https://dev.to/anthonymax/cors"https://dev.to/anthonymax/);

const PORT = 8000;
const app = express();

const getRoutes = require("https://dev.to/anthonymax/./routes/get"https://dev.to/anthonymax/);
const postRoutes = require("https://dev.to/anthonymax/./routes/post"https://dev.to/anthonymax/);

app.use(express.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cors({ origin: true, credentials: true }));

const imagesFolder = path.join(__dirname, "https://dev.to/anthonymax/./images"https://dev.to/anthonymax/);
app.use("https://dev.to/anthonymax//images"https://dev.to/anthonymax/, express.static(imagesFolder));

app.use(express.static(path.join(__dirname, "https://dev.to/anthonymax/src"https://dev.to/anthonymax/)));

app.get("https://dev.to/anthonymax//"https://dev.to/anthonymax/, (req, res) => {
  res.sendFile(path.join(__dirname, "https://dev.to/anthonymax/src/index.html"https://dev.to/anthonymax/));
});

app.use("https://dev.to/anthonymax//api"https://dev.to/anthonymax/, getRoutes);
app.use("https://dev.to/anthonymax//api"https://dev.to/anthonymax/, postRoutes);

app.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اینجا ما راه اندازی کردیم CORS تا بتوانیم از دیگری درخواست ارسال کنیم localhost پورت، و همچنین بارگذاری تصاویر از یک پوشه. به طور خاص، ما این کار را در اینجا انجام می دهیم:

const imagesFolder = path.join(__dirname, "https://dev.to/anthonymax/./images"https://dev.to/anthonymax/);
app.use("https://dev.to/anthonymax//images"https://dev.to/anthonymax/, express.static(imagesFolder));
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همچنین، شما می توانید خود را مشخص کنید PORT برای سرور، اما من پیش فرض را مشخص کردم 8000. شما همچنین باید پیکربندی کنید bodyParser برای کار راحت با HTML و در واقع فقط مسیرها را به api متصل کنید. و اکنون، من فکر می کنم، شما می توانید با خیال راحت از برنامه استفاده کنید!

نتیجه گیری

این برنامه، حتی چنین به ظاهر کوچک، با توجه به اینکه حداقل عملکرد اجرا شده بود، بسیار پیچیده بود. اما، این نیز جالب است، زیرا زمینه ای برای تغییرات، مونتاژ با کیفیت بالا و ماژول های ساده مدرن وجود دارد. شما می توانید backend را در PHP یا چیز دیگری پیاده سازی کنید، معنی برای کلاینت تغییر چندانی نخواهد کرد، بنابراین فکر می کنم که این برنامه حتی می تواند به عنوان یک پروژه حیوان خانگی نیز به خوبی پیش برود.

از همه شما برای خواندن مقاله بسیار سپاسگزارم! خیلی بزرگ بود، حتی در موردی که سعی کردم روایت را در جایی کوتاه کنم، جایی که ظرافت ها را پوشش ندهد، اما با این وجود بسیار زیاد بود، اما، امیدوارم، برای شما جالب و مفید باشد!

مخزن پروژه

این پروژه در GitHub قرار دارد. در آنجا می توانید با جزئیات بیشتر با کد آشنا شوید. در آینده ممکن است پروژه های دیگری نیز وجود داشته باشد که مشابه و یا حتی سردتر باشند.

لیست برنامه های کاربردی در HMPL

این مخزن شامل لیستی از برنامه های آزمایشی است که با استفاده از زبان قالب HMPL نوشته شده اند. می توانید با خیال راحت آنها را بگیرید و آنها را تغییر دهید (فقط تصاویر باید جایگزین شوند).

برنامه گالری

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

عکس 1
عکس 2
عکس 3


مانند

همچنین، خوشحال خواهم شد که از آن حمایت کنید پروژه با ستاره شما. متشکرم

ستاره HMPL ☆

نوشته های مشابه

دیدگاهتان را بنویسید

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

دکمه بازگشت به بالا