HTMX (وقليل من الألبـين.js) لتجربة مماثلة لـ SPA في ASP.Net (العربية (Arabic))

HTMX (وقليل من الألبـين.js) لتجربة مماثلة لـ SPA في ASP.Net

Comments

NOTE: Apart from English (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.

Sunday, 15 September 2024

//

7 minute read

أولاً

في هذا الموقع أستخدم XXXX على نطاق واسع، هذه طريقة سهلة جدا لجعل موقعك يبدو أكثر استجابة وسلاسة دون الحاجة إلى كتابة الكثير من جافاسكربت.

ملاحظة: لست سعيداً تماماً بهذا بعد، HTMX لديه بعض العناصر التي تجعل هذا صعب

HTMX وASP.

استخدام HTMX باستخدام HTMX مع ASP.net الأساسية هو قليلا من الحلم، لقد كتبت عن هذا سابقا في هذه الوظيفة/ / / / من السهل جداً جداً "HTMXIE" موقعك، وهي طريقة عظيمة لجعل موقعك يبدو أكثر استجابة.

كجزء من آخر جولة لي حول استخدام HTMX قررت لجعل أكبر عدد من الروابط على هذا الموقع استخدام HTMX قدر الإمكان. على سبيل المثال إذا قمت بالنقر على زر 'Home' فوقه الآن تستخدم HTMX لتحميل محتوى الصفحة.

انا احقق هذا ببساطة باضافة بعض الخواص للوصلة، مثل هذا:

    <a asp-action="IndexPartial" asp-controller="Home" hx-swap="show:window:top"  hx-target="#contentcontainer" hx-boost="true" class="mr-auto sm:mr-6">
     <div class="svg-container">
        <img src="/img/logo.svg" asp-append-version="true"  width="180px" height="30px"  alt="logo"  :class="{ 'img-filter-dark': isDarkMode }"/>
     </div>
    </a>

هنا يمكنك ان ترى انني اضيف hx-swap الدالة، هذا يخبر HTMX لمبادلة محتوى عنصر الهدف مع المحتوى المسترجع من الخادم.

ملاحظة: لا تستخدم hx-pushurl كما أن هذا سيجعل المتصفح يعيد تحميل الصفحة على زر الظهر مرتين.

الـ hx-target الدالة تخبر HTMX أين تضع المحتوى المسترجع من الخادم. في هذه الحالة هي #contentcontainer element (حيث يكون كل محتوى الصفحة مُحمّل).

يضاف أيضاً ما يلي: hx-swap="show:window:top الذي يجعل النافذة تمرير إلى أعلى الصفحة عند مبادلة المحتوى.

جزء C# من هذا بسيط جداً، انه فقط يكرر طريقة الفهرس العادية لكن بدلاً من ذلك يقوم بتحميل العرض الجزئي. والرمز مبين أدناه. هذه الاستخدامات المقر المقر المقر المقر فقط لـه hx-request ترويسة وإرجاع وجهة النظر الجزئية. هناك أيضا قطع لإعادة وجهة النظر العادية إذا كان الطلب ليس طلب HTMX.

    [Route("/IndexPartial")]
    [OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" })]
    [ResponseCache(Duration = 300, VaryByHeader = "hx-request",
        Location = ResponseCacheLocation.Any)]
    [HttpGet]
    public async Task<IActionResult> IndexPartial()
    {
        ViewBag.Title = "mostlylucid";
        if(!Request.IsHtmx()) return RedirectToAction("Index");
        var authenticateResult = await GetUserInfo();
        var posts = await BlogService.GetPagedPosts(1, 5);
        posts.LinkUrl = Url.Action("Index", "Home");
     
        var indexPageViewModel = new IndexPageViewModel
        {
            Posts = posts, Authenticated = authenticateResult.LoggedIn, Name = authenticateResult.Name,
            AvatarUrl = authenticateResult.AvatarUrl
        };
        return PartialView("_HomePartial", indexPageViewModel);
    }

النتيجة من هذا هو أن هذا الرابط (وآخرون يستخدمون نفس التقنية) يحمل مثل طلبات AJAX و المحتوى يتم مبادلته من دون إعادة تحميل صفحة كاملة. هذا يتجنب "ومضة الضوء" المزعجة التي تحصل عليها عندما تقوم صفحة بإعادة تحميلها بسبب كيفية عمل تيمتي التبديل.

BB وصلات (الطريقة الأبسط)

إذاً الطريقة التي تحتها يمكن أن تجعل للعمل على الرغم من أنها صعبة جداً ومحرجة قليلاً. HTMX يحب حقاً أن يعمل باستخدام النهج المستند إلى الخاصية. & بوصة htmx.ajax هو نوع من "إذا فشل كل شيء آخر" الطريقة والوسائل التي تحتاج إلى العبث مع تاريخ borwsser. لسوء الحظ تاريخ المتصفح المستخدم pushState replaceState وقد عقد مؤتمراً بشأن popstate هو في الواقع القليل من الألم في الرقبة (ولكن يمكن أن تكون قوية جداً لحالات الحافة).

بدلاً من ما أقوم به الآن هو مجرد إضافة hx-boost إلى العلامة التي تحتوي على محتوى المدونات.

   <div class="prose prose max-w-none border-b py-2 text-black dark:prose-dark sm:py-2" hx-boost="true"  hx-target="#contentcontainer">
        @Html.Raw(Model.HtmlContent)
    </div>

يبدو أن هذا يجدي نفعاً hx-boost ويمكن أن توضع على أساليب الوالدين وأن تنطبق على جميع روابط الأطفال. وهو أيضا أكثر معيارا HTMX دون العبث مع التاريخ وما إلى ذلك.

في الحالة النادرة التي لا تريد فيها استخدام HTMx لوصلات معينة يمكنك ان تضيف hx-boost="false" إلى.

(ملاحظة: تخليت عن هذا النهج ولكن أبقيته هنا للرجوع إليه)

لكن المشكلة في هذا النهج كانت روابط مدونتي مثل هذه HTMX لتجربة شبيهة بتجربة SPA التي ليست روابط "طبيعية" هذه الروابط يتم توليدها عن طريق الحد التنازلي، بينما يمكنني كتابة امتداد مارك ديغ لإضافة خاصيات HTMX إلى الروابط، قررت استخدام نهج مختلف (لأنني لدي بالفعل طن من المحتوى لا أريد إعادة الفرز).

بدلاً من ذلك قمت باضافة دالة دالة جافاScccre التي تبحث عن كل هذه الأنواع من الروابط، ومن ثم استخدامات htmx.ajax للقيام بالمقايضة. هذا اساساً ما يفعله HTMX على اي حال فقط 'الخط اليدوي'.

كما يمكنك ان ترى ان هذا عبارة عن مجرد اقتا div.prose هذا العنصر الذي يبدأ مع a / ثم يضيف لهم مستمعاً للأحداث. عندما تُنقر الوصلة على هذا النقر، يُمنع الحدث، ويُستخرج العنوان، ثم htmx.ajax الدالة هو مُتَحَدِّث مع العنوان و element إلى تحديث.

(function(window) {
   
    window.blogswitcher =() =>  {
        const blogLinks = document.querySelectorAll('div.prose  a[href^="/"]');

        // Iterate through all the selected blog links
        blogLinks.forEach(link => {
            link.addEventListener('click', function(event) {
               event.preventDefault();
                let link = event.currentTarget;
                let url = link.href;
                htmx.ajax('get', url, {
                    target: '#contentcontainer',  // The container to update
                    swap: 'innerHTML',            // Replace the content inside the target


                }).then(function() {
                    history.pushState(null, '', url);
                  
                        window.scrollTo({
                            top: 0,
                            behavior: 'smooth' // For a smooth scrolling effect
                        });
                    
                });
            });
        });
        
    };
})(window);

بالإضافة إلى ذلك، بمجرد أن يتم التبديل سوف أدفع العنوان الجديد إلى تاريخ المتصفح ثم أنتقل إلى أعلى الصفحة. أستعمل هذا النهج في بضعة أماكن (مثل البحث) لإعطاء تجربة لطيفة وسهلة.

Back زرtton (هذا هو صعب للحصول على العمل)

يمكن أن يكون الزر الخلفي في هذا النوع من التطبيق إشكالية ؛ MANY SPAS 'proper' إما أن تقوم بتعطيل الزر الخلفي أو أن تضع مع هذا السلوك غير الصحيح. على أي حال أردت التأكد من أن الزر الخلفي يعمل كما هو متوقع. ملاحظة: لجعل الزر الخلفي يعمل كما هو متوقع، نحتاج أيضاً إلى الاستماع إلى popState حدث حدث. يتم إطلاق هذا الحدث عندما يبحر المستخدم إلى الخلف أو إلى الأمام في تاريخ المتصفح. عندما يتم إطلاق هذا الحدث يمكننا إعادة تحميل المحتوى لـ الحالي URL.

window.addEventListener("popstate",   (event) => {
 // When the user navigates back, reload the content for the current URL
 event.preventDefault();
 let url = window.location.href;
 // Perform the HTMX AJAX request to load the content for the current state
 htmx.ajax('get', url, {
  target: '#contentcontainer',
  swap: 'innerHTML'
 }).then(function () {
  // Scroll to the top of the page
  window.scrollTo({
   top: 0,
   behavior: 'smooth'
  });
 });
});

في هذا الشفرة نحن نمنع سلوك المتصفح الشعبي الافتراضي مع event.preventDefault() نداء نداء. ثم نقوم بعد ذلك باستخلاص الحق الحالي من window.location.href وتنفيذ طلب HTMX AJAX لتحميل محتوى الحالة الحالية. عندما يتم تحميل المحتوى فإننا ننقل إلى أعلى الصفحة.

كما ذكر سابقاً لا يمكنك أن تستخدم أيضاً hx-pushurl كما أن هذا سيجعل المتصفح يعيد تحميل الصفحة على زر الخلف مرتين.

HTMX بصورة أعم (وAlbin.js)

كما خمنتم، أنا معجب نوعاً ما بـ HTMX، مضافاً إلى ASP.NET Corrure ومواضع الألبين.js يمكنها من إنشاء تجربة مستخدم لطيفة مع الحد الأدنى من الجهد. الشيء الرئيسي الذي أفضله على مثل أُطر الجانب العميل الأكثر "تكويناً" مثل React / agular etc... هو أنه لا يزال يعطيني خط أنابيب كامل جانب الخادم مع ASP.Net corre لكن 'الشعور' من a SPA. Albin.js يُمْكِنُ تفاعلَ جانبِ العميلِ البسيطِ، a ميزة بسيطة جداً أضفتُ مؤخراً كَانَ يَجْعلُ فئتَي 'مخفية' لكن يُوسّعُ على a نقرة.

استخدام الألبين.js لهذا يعني أنه ليس هناك حاجة إلى جافاسكربت إضافي.

        <div class="mb-8 mt-6 border-neutral-400 dark:border-neutral-600 border rounded-lg" x-data="{ showCategories: false }">
            <h4 
                class="px-5 py-1 bg-neutral-500  bg-opacity-10 rounded-lg  font-body text-primary dark:text-white w-full flex justify-between items-center cursor-pointer"
                x-on:click="showCategories = !showCategories"
            >
                Categories
                <span>
                    <i
                        class="bx text-2xl"
                        :class="showCategories ? 'bx-chevron-up' : 'bx-chevron-down'"
                    ></i>
                </span>
            </h4>
            <div 
                class="flex flex-wrap gap-2 pt-2 pl-5 pr-5 pb-2"
                x-show="showCategories" 
                x-cloak
                x-transition:enter="max-h-0 opacity-0"
                x-transition:enter-end="max-h-screen opacity-100"
                x-transition:leave="max-h-screen opacity-100"
                x-transition:leave-end="max-h-0 opacity-0"
            >
                @foreach (var category in ViewBag.Categories)
                {
                    <partial name="_Category" model="category"/>
                }
           
            </div>
        </div>

هنا يمكنك ان ترى انني استخدم x-data إلى إنشاء a جديد a كائن البيانات كائن بوصة هذه حالة showCategories/ / / / هذا هو bollean الذي يتم تجلج عندما h4 تم النقر عليها. الـ x-on:click مُستخدَمٌ لِتَحَلُّقِ زَوْجَةِ زَوْجَةِ زَوْجَةِ التَّحَذُّرِ إلى مُحَاوَلَةِ التَّحَذُّرِ.

داخل قائمة التصنيفات، ثم استخدم x-show إلى إظهار أو إخفاء قائمة الفئات على أساس قيمة showCategories/ / / / أنا أيضاً أستخدم الـ x-transition إلى إضافة a لطيف انزلاق أسفل تأثير الـ فئات هو أو مخفي. الـ x-cloak هو مُستخدَم إلى منع 'fliker' من التصنيفات قبل تنفيذ جافاسكربت. لدي فئة CSS صغيرة معرّفة لهذا:

[x-cloak] { display: none !important; }

في الإستنتاج

هذا هو عليه، مقالة قصيرة عن كيفية استخدام HTMX و بقعة من الألبين. وآمل أن تجدوا ذلك مفيداً، إذا كان لديكم أي أسئلة أو تعليقات، أرجو أن تكون لديكم الحرية في تركها أدناه.

logo

©2024 Scott Galloway