NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Friday, 02 May 2025
//15 minute read
HTMX هي مكتبة جافاسكربت قوية تسمح لك بإنشاء تطبيقات ديناميكية على الشبكة مع الحد الأدنى من جافاسكربت. تمكنك من جعل طلبات AJAX، مبادلة محتوى HTML، والتعامل مع الأحداث مباشرة في الخاصيات HTML الخاص بك. لقد كنت استخدم HTMX لحوالي عامين في هذه النقطة ومع كل مشروع اتعلم اكثر واكثر عن قدراته واكثر اهمية انه حدود
ومع ذلك ما زلت لا أدعي أن لدي معرفة خبيرة بها. أردت فقط أن أشارك بعض الأشياء التي تعلمتها على طول الطريق.
كما ترون HTMX يوفر عدد من الأحداث التي يمكنك ربطها لتعديل الطلب أو الرد. باستخدام كل واحد من هذه يمكنك تعديل كيفية تفاعل HTMX مع الخادم / العميل بطرق شاملة جداً.
أحد أقوى جوانب HTMX هو القدرة على & مُرسِل :: توسيع نطاق قدراتها. في حالتي، أنا عادةً أرتبط في htmx:configRequest
إضافة بارامترات إضافية إلى الطلب. هذا هو مفيد عندما تريد تمرير بيانات إضافية إلى الخادم بدون الحاجة إلى تعديل HTML أو جافاScript code.
تمديدات أخرى أخرى قد تكون خطاطا htmx:beforeRequest
(أ) تعديل الطلب قبل إرساله؛ ما بعد مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن مـن configRequest
لـك في beforeRequest
(أ) مثل: HX-Vals
وقد عقد مؤتمراً بشأن HX-Include
s مُرفقة مسبقاً بإعادة النشوء (إما في الحمولة / الإستشارة).
يمكنك حتى أن تُخطِط htmx:afterSwap
● القيام بإجراءات بعد مبادلة المحتوى. تُجمع مع العميل الجانبي الذي يقوم بتأجير مكتبات مثل: الألابين أو ليت لتر يمكنك إنشاء تطبيقات ديناميكية قوية مع الحد الأدنى من الشفرة.
HTMX يوفر بعض الامتدادات المثبتة مثل hx-boost
وقد عقد مؤتمراً بشأن hx-swap-oob
التي تسمح لك بتعزيز وظيفة HTMX دون كتابة أي رمز مخصص. ومع ذلك، هناك أوقات تحتاج فيها إلى إنشاء تمديدات خاصة بك لتلبية متطلبات محددة.
على سبيل المثال، قد ترغب في إضافة ترويسات مخصصة إلى طلباتك، أو تعديل حمولة الطلب، أو التعامل مع أحداث محددة بطريقة فريدة.
لتحقيق هذا HTMX يوفر لكم بعض نقاط التكامل المفيدة:
{
/**
* init(api)
* Called once when the extension is initialized.
* Use it to set up internal state, store references, or access HTMX utility functions via the api parameter.
*/
init: function(api) {
return null;
},
/**
* getSelectors()
* Returns additional CSS selectors that HTMX should monitor.
* Useful if your extension needs to handle custom elements or dynamic behavior.
*/
getSelectors: function() {
return null;
},
/**
* onEvent(name, evt)
* Called on every HTMX event (e.g., htmx:beforeRequest, htmx:afterSwap).
* Return false to cancel the event or stop propagation.
*/
onEvent: function(name, evt) {
return true;
},
/**
* transformResponse(text, xhr, elt)
* Modify the raw response text before it is parsed and swapped into the DOM.
* Use this to sanitize or preprocess HTML.
*/
transformResponse: function(text, xhr, elt) {
return text;
},
/**
* isInlineSwap(swapStyle)
* Return true if your extension will handle this swap style manually.
* This tells HTMX to skip default behavior.
*/
isInlineSwap: function(swapStyle) {
return false;
},
/**
* handleSwap(swapStyle, target, fragment, settleInfo)
* Perform custom DOM manipulation if you implement a custom swap style.
* Return true to prevent HTMX's default swap.
*/
handleSwap: function(swapStyle, target, fragment, settleInfo) {
return false;
},
/**
* encodeParameters(xhr, parameters, elt)
* Modify or serialize request parameters before sending.
* Return null to use default URL/form encoding.
* Return a string to override with a custom payload (e.g., JSON).
*/
encodeParameters: function(xhr, parameters, elt) {
return null;
}
}
HTMX يوفر عدداً من الملحقات المسبقة الصنع التي يمكنك قراءة هنا.
على سبيل المثال، على سبيل المثال، مُدّمّاً مُدّمّاً json-encode
يسمح لك بإرسال بيانات Jeson في جسم الطلب بدلاً من بيانات شكل URL- encoverd. هذا مفيد عندما تريد إرسال تركيبات البيانات المركبة أو الصفات إلى الخادم.
يمكنك أن ترى أن هذا يصل إلى 3 أحداث
init
- إنشاء امتداد وتخزين إشارة إلى مؤشر HTMX APIonEvent
- أن تُضَع Content-Type
مقدم إلى application/json
« إذا ال المطلوب » أي ال أمر أمر أمر أمر الأمر في أمر أمر أمر أمر أمر أمر أمره و أمر أمر أمر أمره و أمر أمر أمره : أي : أي : إذا هذا ال أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر أمر عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو خلق عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو هو خلق عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو هو خلق عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو هو عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو عظيم هو هو هو هو هو خلق عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم هو هو هو هو هو هو هو هو هو هو هو هو عظيم هو هو هو هو هو هو خلق عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيم عظيمencodeParameters
- إلى تجاوز افتراضي URL encoded شكل ترميز و تسلسلي البارامترات كJSON. إنها أيضاً ترجع سلسلة نصية إلى منع HTMX من استخدام افتراضي URL- encodd from secondd.(function() {
let api
htmx.defineExtension('json-enc', {
init: function(apiRef) {
api = apiRef
},
onEvent: function(name, evt) {
if (name === 'htmx:configRequest') {
evt.detail.headers['Content-Type'] = 'application/json'
}
},
encodeParameters: function(xhr, parameters, elt) {
xhr.overrideMimeType('text/json')
const object = {}
parameters.forEach(function(value, key) {
if (Object.hasOwn(object, key)) {
if (!Array.isArray(object[key])) {
object[key] = [object[key]]
}
object[key].push(value)
} else {
object[key] = value
}
})
const vals = api.getExpressionVars(elt)
Object.keys(object).forEach(function(key) {
// FormData encodes values as strings, restore hx-vals/hx-vars with their initial types
object[key] = Object.hasOwn(vals, key) ? vals[key] : object[key]
})
return (JSON.stringify(object))
}
})
})()
او حتى الابسط ولكن اكثر hx-debug
مضافاً إليها مضافاً HX-Debug
رأساً على الطلب. وهذا مفيد لأغراض التصحيح وقطع الأشجار، حيث أنه يتيح لكم رؤية بيانات الطلب والاستجابة الخام في وحدة التحكم Devv.
(function() {
htmx.defineExtension('debug', {
onEvent: function(name, evt) {
if (console.debug) {
console.debug(name, evt)
} else if (console) {
console.log('DEBUG:', name, evt)
} else {
throw new Error('NO CONSOLE SUPPORTED')
}
}
})
})()
هناك الكثير أكثر من ذلك بكثير، بما في ذلك قوة قوية جداً جانب العميل الجانبي والذي يسمح لك باستخدام المكتبات المؤقتة من جانب العملاء لتحويل بيانات JSON المعادة إلى HTML. وهذا مفيد في إنشاء الـ UIs الديناميكية دون الحاجة إلى الاعتماد على تحويل جانب الخوادم.
على سبيل المثال في مشروع حديث استخدمت مبادلات HTMX OOB لتحديث عدد من الصفوف في الجدول. لفعل هذا اردت ان اعرف اي الصفات التي يتم عرضها حالياً في الجدول، لذا قمت فقط بتحديث الصفوف التي كانت مرئية.
export default {
encodeParameters: function (xhr, parameters, elt) {
const ext = elt.getAttribute('hx-ext') || '';
if (!ext.split(',').map(e => e.trim()).includes('dynamic-rowids')) {
return null; // Use default behavior
}
const id = elt.dataset.id;
const approve = elt.dataset.approve === 'true';
const minimal = elt.dataset.minimal === 'true';
const single = elt.dataset.single === 'true';
const target = elt.dataset.target;
const payload = { id, approve, minimal, single };
if (approve && target) {
const table = document.querySelector(target);
if (table) {
const rowIds = Array.from(table.querySelectorAll('tr[id^="row-"]'))
.map(row => row.id.replace('row-', ''));
payload.rowIds = rowIds;
}
}
// Merge payload into the parameters object
Object.assign(parameters, payload);
return null; // Return null to continue with default URL-encoded form encoding
}
}
إلى استخدام الإيطالية نحن بحاجة إلى إضافة امتداد إلى HTMX تشكيلات. اذاً في ملف نقطة الدخول js (افترض انك تستخدم الوحدات؛ yoy يجب ان يكون) يمكنك ان تفعل شيئاً كهذا:
import dynamicRowIds from "./dynamicRowIds"; // Load the file
htmx.defineExtension("dynamic-rowids", dynamicRowIds); // Register the extension
ثم على أي عنصر من العناصر التي تريد استخدامها على يمكنك إضافة hx-ext
dynamic-rowids
.
<button
hx-ext="dynamic-rowids"
data-target="#my-table"
data-id="@Model.Id"
data-param1="true"
data-param2="false"
data-param3="@Model.Whatever"
hx-post
hx-controller="Contoller"
hx-action="Action"
>
<i class='bx bx-check text-xl text-white'></i>
</button>
هذا هو ايضاً بسيطاً آخر HTMX امتداد، هذا الوقت مرتبط في htmx:configRequest
كما نقوم بتعديل الURL قبل إرسال الطلب. هذا اضف هو IF أنت استخدام الإسنادات أساس المرشّح. وتريد بعض الطلبات للحفاظ على المرشّحات الموجودة بينما لا تريد غير ذلك (مثل 'الاسم' و'البداية' ولكن ليس 'الصفحة' أو 'الرصيف').
هذا مشابه لـ لكن ليس تماماً تماماً نفس مثل الحالي HTMx امتداد دفع المكافئات
يمكنك أن ترى أن لدينا خط onEvent
من أجل الإصغاء لـ htmx:configRequest
حدث حدث.
ثم نحن:
preserve-params-exclude
من العنصر (إن كان موجوداً) و تقسيمه إلى مجموعة من المفاتيح لاستبعادها (إذاً نحن لا نضيفها إلى الطلب)export default {
onEvent: function (name, evt) {
if (name !== 'htmx:configRequest') return;
const el = evt.detail.elt;
const excludeStr = el.getAttribute('preserve-params-exclude') || '';
const exclude = excludeStr.split(',').map(s => s.trim());
const currentParams = new URLSearchParams(window.location.search);
const newParams = new URLSearchParams(evt.detail.path.split('?')[1] || '');
currentParams.forEach((value, key) => {
if (!exclude.includes(key) && !newParams.has(key)) {
newParams.set(key, value);
}
});
evt.detail.path = evt.detail.path.split('?')[0] + '?' + newParams.toString();
return true;
}
};
هنا أستعمل المادة الأساسية HTMX.Net من أجل مساعِداتها. مثل مثل hx-controller
وقد عقد مؤتمراً بشأن hx-action
هي مساعِدات العلامة التي تولّد خصائص HTMX الصحيحة لك. بالإضافة إلى hx-route-<x>
لقيم أن تمر في الطريق. هذا مفيد حقاً لأنه يسمح لك باستخدام رمز C# إلى توليد القيم الصحيحة للخصائص بدلاً من الحاجة إلى تشفيرها في HTML الخاص بك.
أن تكون امتداداً من السهل حقاً إستخدامه:
أولاً نحن بحاجة إلى إضافة امتداد إلى تشكيل HTMX لدينا.
import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);
ملاحظة: ستلاحظ أن تمديدات HTMX الافتراضية تستخدم طريقة 'التحميل التلقائي' لتحميل التمديد.
// Autoloading the extension and registering it
(function() {
htmx.defineExtension('debug', {
}
هذه طريقة جيدة للقيام بذلك إذا كنت تستخدم HTMX في بيئة غير متمددة. مع ذلك، إذا كنت تستخدم الوحدات (التي يجب أن تكون) فمن الأفضل استخدام import
لتحمّل التمديد ثمّ سجله بشكل صريح ضدّك htmx
(ه) حالة من حالات الطوارئ. هذا يتيح لك الاستفادة من مصافحة الأشجار و فقط تحميل الامتدادات التي تحتاجها.
ثم على عنصرك يمكنك إضافة hx-ext
preserve-params
وقد عقد مؤتمراً preserve-params-exclude
مع a فاصلة قائمة من إلى استبعاد من طلب.
<a class="btn-outline-icon"
hx-controller="MyController"
hx-action="MyAction"
hx-route-myparam="@MyParam"
hx-push-url="true"
hx-ext="preserve-params"
preserve-params-exclude="page,sort"
hx-target="#page-content"
hx-swap="innerHTML show:top"
hx-indicator>
<i class="bx bx-search"></i>
</a>
في هذه القضية بسبب: event.detail.path
لَهُ الجديدُ myparam
قيمة وضعها في أنها سوف تستبدل هذا مع قيمة جديدة لدينا مع قيمة جديدة ولكن الحفاظ على جميع الآخرين (باستثناء page
وقد عقد مؤتمراً بشأن sort
)ع( حتى نتمكن من الاستمرار في تمرير أي مرشحات وضعناها في URL إلى الخادم من دون أن نقلق بشأن فقدانها عندما نقوم بعمل طلب جديد.
واحد من الأشياء الأنيقة حول HTMX هو أن الكثير من تفاعله مع الخادم يحدث من خلال مواجهات HTTP. هذه الترويسات تزود الخادم بسياق غني حول ما تسبب في الطلب، مما يسمح لك بالرد بشكل مناسب من نقاط النهاية الأساسية الخاصة بك. نت أو وجهات نظر المستخلصات.
والعنصر الأساسي في هذا هو: HTMX.Net/ / / / ومن بين كثير من البنود التي توفرها هذه الوثيقة تكون متقنة. Request
(ب) أن تكشف عن الطلبات الواردة من الشركة HTMX. وهذا مفيد لتحديد ما إذا كان طلب مقدم من HTMX أم لا، ولمعالجته وفقاً لذلك.
كما أن لديها آليتها الخاصة لإرسال المنازعات
Response.Htmx(h => {
h.WithTrigger("yes")
.WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
.WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});
............................................................................................................................................................................................................... قام خالد بعمل عظيم في إنشاء مجموعة من التمديدات لجعل من السهل العمل مع HTMX في ASP.NET الأساسي.
إنها أداة رئيسية في صندوق أدواتي عندما أعمل مع HTMX و ASP.NET افحصه في الخارج!
هنا توزيع للترويسات الأكثر فائدة التي يرسلها HTMX مع كل طلب:
/ ترويسة / وصف / |----------------------------|------------------------------------------------------------------------------------------------------------------|
أنا أستخدم هذه بشكل واسع في تطبيقاتي الأساسية مع HTMX.Net مثل Request.IsHtmx()
, Request.IsHtmxBoosted()
وقد عقد مؤتمراً بشأن Request.IsHtmxNonBoosted()
يمكنك بسهولة الكشف عن طلبات HTMX والاستجابة وفقاً لذلك.
على سبيل المثال، لديّ تمديد بسيط جداً للطلب الذي يسمح لي بالكشف إذا كان الطلب يستهدف رئيسي #page-content
)٤( إذا كان كذلك، فأنا أعلم أنه يجب أن أُعيد جزء منه.
ملاحظة: العديد لا يُدرك أنه يمكنك تحديد 'صفحة كاملة' على أنها جزئية، ثم تقوم فقط بالتخطّي عن المخطط.
if (Request.PageContentTarget())
{
Response.PushUrl(Request);
return PartialView("List", vm);
}
return View("List", vm);
public static class RequestExtensions
{
public static bool PageContentTarget(this HttpRequest request)
{
bool isPageContentTarget = request.Headers.TryGetValue("hx-target", out var pageContentHeader)
&& pageContentHeader == "page-content";
return isPageContentTarget;
}
}
بالإضافة إلى الطلبات الإضافية، يمكنك أيضاً أن تُنشئ تمديدات للإجابة لإرجاع الأحداث إلى العميل. وهذا مفيد لإثارة الأحداث الجانبية للزبائن.
على سبيل المثال في تكاملي مع حليّتي الثانية أنا تمكين إغلاق حوار استخدام a زناد هو set من خادم.
document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);
هذا هو من خادم ك a HTMX مُطلَق.
public static void CloseSweetAlert(this HttpResponse response)
{
response.Headers.Append("HX-Trigger" , JsonSerializer.Serialize(new
{
sweetalert = "close"
}));
}
هذا سَيُدّرر sweetalert:close
حدث على جانب العميل، يسمح لك بإغلاق الحوار. يمكنك أيضاً تمرير البيانات مرة أخرى إلى العميل باستخدام HX-Trigger
رأساً على رأساً على رأساً. هذا مفيد لنقل البيانات من الخادم إلى العميل دون الحاجة إلى تعديل رمز HTML أو جافاسكربت.
كما ترون، من السهل جداً الإستماع لهذه الأحداث بإضافة مستمع حدث للجثة. أنا أستخدم (جيسون) بشكل رئيسي كما أنه دائماً يرمز بشكل صحيح
لقد كتبت عن طريقتي المحمصة سابقاً هنا هناولكن من الجدير بالذكر هنا أيضاً إلى تمكين الخادم من إطلاق رسالة تحذير على جانب العميل. أنا وضعت الزناد في هذا التمديد الإستجابي.
public static void ShowToast(this HttpResponse response, string message, bool success = true)
{
response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
{
showToast = new
{
toast = message,
issuccess =success
}
}));
}
ثم أعلق في جانب عميل الحدث وأتصل بـ showToast
الدالة الدالة.
import { showToast, showHTMXToast } from './toast';
window.showHTMXToast = showHTMXToast;
document.body.addEventListener("showToast", showHTMXToast);
ثمّ هذا يُدّعي إلى showToast
و حسناً، تظهر نخباً، مرة أخرى ترى المزيد عنه في هذه المادة .
export function showHTMXToast(event) {
const xhr = event?.detail?.xhr;
let type = 'success';
let message = xhr?.responseText || 'Done!';
try {
const data = xhr ? JSON.parse(xhr.responseText) : event.detail;
if (data.toast) message = data.toast;
if ('issuccess' in data) {
type = data.issuccess === false ? 'error' : 'success';
} else if (xhr?.status >= 400) {
type = 'error';
} else if (xhr?.status >= 300) {
type = 'warning';
}
} catch {
if (xhr?.status >= 400) type = 'error';
else if (xhr?.status >= 300) type = 'warning';
}
showToast(message, 3000, type);
}
حسنا هذا هو عليه، جولة وزوبعة من HTMX وASP.NET الأساسية. وآمل أن تجدوه مفيدا ومفيدا. إذا كان لديكم أية أسئلة أو تعليقات، يرجى إعطاء الكلمة للتعليق أدناه.