- این پروژه به Angular Material 9x ارتقاء داده شده؛ جزئیات بیشتر
- کتابخانهی jalali-moment متاسفانه باگ زیاد دارد. اگرتنظیم jalaliMoment.locale("fa") در آن وجود نداشته باشد، مدام خطای null reference میدهد. همچنین روش معرفی تاریخ میلادی به آن اینبار باید به اینصورت باشد (عدم سازگاری با نگارشهای قبلی آن).
در این قسمت روش جایگزین کردن متد css جیکوئری را با کدهای خالص جاوا اسکریپتی بررسی میکنیم.
کار با Inline Styles
در این مثال میخواهیم با استفاده از جاوا اسکریپت، المانهای h2 و h3 را یافته و سپس h2ها را آبی و h3ها را سبز کنیم:
برای تغییر inline style المانها، از خاصیت style آنها استفاده میشود که در نهایت این شیوهنامههای جدید توسط ویژگی style به همان المان اضافه میشوند:
خاصیت style جزو استاندارد DOM Level 2 است که در سال 2000 تصویب شدهاست (از زمان IE 8.0 به بعد در دسترس است). باید دقت داشت که از این روش بیشتر در کتابخانههای جاوا اسکریپتی برای شرایطی خاص، جهت تغییر پویای رابط کاربری استفاده میشود و هر تغییری که در اینجا اعمال شود، مقادیر قبلی موجود را بازنویسی میکند.
همچنین اگر بخواهیم به یک المان چندین شیوهنامه را انتساب دهیم، روش کار به صورت زیر است:
پس از یافتن المانهای مدنظر، تنها کافی است نام شیوهنامهی مدنظر را به خاصیت style اضافه و مقدار دهی کنیم. در اینجا نام شیوهنامهای که «کبابی» باشد، مانند font-weight، به صورت camel case مانند fontWeight درج خواهد شد؛ هرچند از همان نام اصلی نیز میتوان به صورت زیر استفاده کرد:
روش دیگری نیز برای انجام این تغییرات چندتایی وجود دارد:
خاصیت style یک المان، از نوع اینترفیس CSSStyleDeclaration است که دارای خاصیت استاندارد cssText نیز میباشد. توسط این خاصیت میتوان چندین شیوهنامه را به صورت یکجا به عنصری انتساب داد و یا تمام آنها را خواند.
کار با Style Sheets
Inline styles تنها روش کار با شیوهنامهها نیست. روش صحیح و قابل مدیریت کار با شیوهنامهها استفاده از فایلهای style sheets است. برای مثال تغییرات قبل را میتوان در فایلی به نام styles.css و با محتوای زیر ایجاد کرد:
و سپس آنرا به صفحه متصل نمود:
و یا حتی میتوان این شیوه نامه را به صورت inline نیز به ابتدای صفحه اضافه نمود:
اما ممکن است در برنامه بخواهیم امکان تغییر پویای قالب را به کاربران بدهیم. در یک چنین حالتی اعمال این نوع شیوهنامهها توسط جاوا اسکریپت مفهوم پیدا میکند:
اولین سطر، اولین تگ style اضافه شده به صفحه را یافته (این style میتواند inline و یا لینک شدهی توسط یک فایل باشد) و سپس شیوه نامهی جدیدی را توسط متد insertRule، در انتهای آن به صورت پویا درج میکند.
مخفی کردن و نمایش دادن المانها در صفحه
جیکوئری به همراه متدهای hide و show است که کار مخفی کردن و یا نمایش دادن مجدد یک المانرا انجام میدهند:
در کل روشهای زیادی برای مخفی کردن یک المان وجود دارند. برای مثال میتوان opacity آنرا به صفر تنظیم کرد و یا position آنرا به absolute و سپس آنرا در مختصاتی خارج از صفحه قرار داد. اما عموما خاصیت display را به none تنظیم میکنند. همچنین در استاندارد W3C HTML5، خاصیت جدید hidden از نوع boolean نیز به المانها اضافه شدهاند که دقیقا برای همینمنظور بکار میرود. مزیت مهم این خاصیت نه فقط استاندارد بودن آن، بلکه بالابردن دسترسی پذیری المانهای صفحه توسط برنامههای «screen reader» مخصوص معلولین است. بنابراین با استفاده از جاوا اسکریپت خالص برای مخفی کردن یک المان میتوان نوشت:
این روش 25 بار سریعتر از متد hide جیکوئری است! از این جهت که jQuery در پشت صحنه مدام متد window.getComputedStyle را برای موارد خاص و بحرانی کار با شیوهنامهها فراخوانی میکند (در تمام متدهایی که با CSS کار میکنند) و این متد تاثیر منفی بر روی کارآیی برنامه دارد.
و چون خاصیت hidden از نوع Boolean است، ذکر آن در یک المان یعنی تنظیم آن به true و حذف آن، یعنی تنظیم آن به false یا نمایش مجدد المان در اینجا:
اندازهگیری تاثیر شیوهنامهها بر روی طول و عرض المانها
CSS Box Model یک چنین تعریفی را دارد:
زمانیکه از متدهای ()width و ()height جیکوئری بر روی المانی استفاده میشود، صرفا طول و عرض قسمت «content» را دریافت خواهید کرد.
برای این منظور در جاوا اسکریپت خالص این خواص در اختیار ما است:
روش اندازه گیری Content + Padding توسط جاوا اسکریپت خالص:
این خواص هرچند اخیرا به استانداردهای CSS به صورت رسمی اضافه شدهاند، اما از زمان IE 6.0 پشتیبانی میشدهاند و با متدهای ()innerWidth و ()innerHeight جیکوئری قابل مقایسه هستند.
روش اندازه گیری Content + Padding + Border توسط جاوا اسکریپت خالص:
این خواص از زمان IE 8.0 پشتیبانی میشدهاند.
کار با Inline Styles
<h1>News</h1> <div>Welcome to our site!</div> <h2>World</h2> <h3>Title 1</h3> <div>description 1.</div> <h2>Science</h2> <h3>Title 2</h3> <div>description 2.</div>
var headings = document.querySelectorAll('h2, h3'); for (var i = 0; i < headings.length; i++) { if (headings[i].tagName === 'H2') { headings[i].style.color = 'blue'; } else { headings[i].style.color = 'green'; } }
<h2 style="color: blue">….</h2> <h3 style="color: green">….</h3>
همچنین اگر بخواهیم به یک المان چندین شیوهنامه را انتساب دهیم، روش کار به صورت زیر است:
<h2>World</h2> ... <h2>Science</h2> <script> var headings = document.querySelectorAll('h2'); for (var i = 0; i < headings.length; i++) { headings[i].style.color = 'blue'; headings[i].style.fontWeight = 'bold'; } </script>
headings[i].style['font-weight'] = 'bold';
var headings = document.querySelectorAll('h2'); for (var i = 0; i < headings.length; i++) { headings[i].style.cssText = 'color: blue; font-weight: bold'; }
کار با Style Sheets
Inline styles تنها روش کار با شیوهنامهها نیست. روش صحیح و قابل مدیریت کار با شیوهنامهها استفاده از فایلهای style sheets است. برای مثال تغییرات قبل را میتوان در فایلی به نام styles.css و با محتوای زیر ایجاد کرد:
h2 { color: blue; } h3 { color: green; }
<link href="styles.css" rel="style sheet">
<style> h2 { color: blue; } h3 { color: green; } </style>
var sheet = document.styleSheets[0]; sheet.insertRule('h2 { font-style: italic; }', sheet.cssRules.length - 1);
مخفی کردن و نمایش دادن المانها در صفحه
جیکوئری به همراه متدهای hide و show است که کار مخفی کردن و یا نمایش دادن مجدد یک المانرا انجام میدهند:
// hide an element $element.hide(); // show it again $element.show();
element.setAttribute('hidden', '');
و چون خاصیت hidden از نوع Boolean است، ذکر آن در یک المان یعنی تنظیم آن به true و حذف آن، یعنی تنظیم آن به false یا نمایش مجدد المان در اینجا:
element.removeAttribute('hidden');
اندازهگیری تاثیر شیوهنامهها بر روی طول و عرض المانها
CSS Box Model یک چنین تعریفی را دارد:
زمانیکه از متدهای ()width و ()height جیکوئری بر روی المانی استفاده میشود، صرفا طول و عرض قسمت «content» را دریافت خواهید کرد.
برای این منظور در جاوا اسکریپت خالص این خواص در اختیار ما است:
<style> .box { padding: 10px; margin: 5px; border: 3px solid; display: inline-block; } </style> <span class="box">a box</span>
// returns 38 var clientHeight = document.querySelector('.box').clientHeight; // returns 55 var clientWidth = document.querySelector('.box').clientWidth;
روش اندازه گیری Content + Padding + Border توسط جاوا اسکریپت خالص:
// returns 44 var offsetHeight = document.querySelector('.box').offsetHeight; // returns 61 var offsetWidth = document.querySelector('.box').offsetWidth;
اشتراکها
پروژه Marka
مطالب
OpenCVSharp #17
تشخیص اشخاص به کمک OpenCV
فرض کنید قصد دارید یک سیستم حضور غیاب مبتنی بر تشخیص چهره را طراحی کنید. قسمت استخراج چهره، از تصویر کلی رسیده را بررسی کردیم. اما در ادامه چگونه تشخیص دهیم که این چهره متعلق به چه شخصی است؟ با توجه به اینکه تصویر چهرهی یک شخص میتواند از زوایای مختلفی تهیه شود و یا حتی حالات روحی منعکس شدهی در صورت نیز در تغییر بیت و بایتهای تصویر چهره مؤثر هستند.
بانک اطلاعاتی تصاویر چهرههای اشخاص
در اینجا از تصاویر «The Database of Faces» استفاده خواهیم کرد. این مجموعه شامل تصاویر 40 شخص، در 10 حالت مختلف است.
برای بارگذاری این تصاویر و استفادهی از آنها در الگوریتم FisherFaceRecognizer نیاز به ساختار ذیل است:
در اینجا Image، محتوای تصویر انتخابی است. مقدار ImageGroupId مساوی مقدار عددی نام پوشهی تصاویر منهای یک، تنظیم میشود. برای مثال پوشهی s1 به گروه صفر تنظیم میشود. ImageId نیز به یک مقدار خود افزایش یابنده معادل شمارهی جاری تصویر، تنظیم میگردد؛ به این صورت:
ابتدا پوشههای دیتابیس تصاویر یافت شده و سپس از نام هر پوشه یک شمارهی گروه (یا شمارهی شخص) استخراج میشود. سپس تصاویر این پوشه به لیست تصاویر اصلی اضافه خواهند شد.
تشخیص یک چهرهی اتفاقی
پس از تشکیل لیست تصاویر، اکنون کار با الگوریتم FisherFaceRecognizer به نحو ذیل خواهد بود:
پارامتر اول متد Train، لیست تصاویر است و پارامتر دوم، لیست شماره گروههای متناظر با هر تصویر است که در اینجا به عنوان برچسب نیز نامگذاری شدهاست.
سپس با استفاده از کلاس Random، یک تصویر اتفاقی انتخاب میشود.
اکنون این تصویر اتفاقی به متد Predict ارسال شده و نتیجهی آن، شماره گروه چهرهی تشخیص داده شدهاست. به این ترتیب میتوان تشخیص داد که یک تصویر مفروض ورودی، متعلق به چه شخصی (یا در اینجا گروه یا برچسب) است.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.
فرض کنید قصد دارید یک سیستم حضور غیاب مبتنی بر تشخیص چهره را طراحی کنید. قسمت استخراج چهره، از تصویر کلی رسیده را بررسی کردیم. اما در ادامه چگونه تشخیص دهیم که این چهره متعلق به چه شخصی است؟ با توجه به اینکه تصویر چهرهی یک شخص میتواند از زوایای مختلفی تهیه شود و یا حتی حالات روحی منعکس شدهی در صورت نیز در تغییر بیت و بایتهای تصویر چهره مؤثر هستند.
بانک اطلاعاتی تصاویر چهرههای اشخاص
در اینجا از تصاویر «The Database of Faces» استفاده خواهیم کرد. این مجموعه شامل تصاویر 40 شخص، در 10 حالت مختلف است.
برای بارگذاری این تصاویر و استفادهی از آنها در الگوریتم FisherFaceRecognizer نیاز به ساختار ذیل است:
public class ImageInfo { public Mat Image { set; get; } public int ImageGroupId { set; get; } public int ImageId { set; get; } }
var images = new List<ImageInfo>(); var imageId = 0; foreach (var dir in new DirectoryInfo(@"..\..\Images").GetDirectories()) { var groupId = int.Parse(dir.Name.Replace("s", string.Empty)) - 1; foreach (var imageFile in dir.GetFiles("*.pgm")) { images.Add(new ImageInfo { Image = new Mat(imageFile.FullName, LoadMode.GrayScale), ImageId = imageId++, ImageGroupId = groupId }); } }
تشخیص یک چهرهی اتفاقی
پس از تشکیل لیست تصاویر، اکنون کار با الگوریتم FisherFaceRecognizer به نحو ذیل خواهد بود:
var model = FaceRecognizer.CreateFisherFaceRecognizer(); model.Train(images.Select(x => x.Image), images.Select(x => x.ImageGroupId)); var rnd = new Random(); var randomImageId = rnd.Next(0, images.Count - 1); var testSample = images[randomImageId]; Console.WriteLine("Actual group: {0}", testSample.ImageGroupId); Cv2.ImShow("actual", testSample.Image); var predictedGroupId = model.Predict(testSample.Image); Console.WriteLine("Predicted group: {0}", predictedGroupId);
سپس با استفاده از کلاس Random، یک تصویر اتفاقی انتخاب میشود.
اکنون این تصویر اتفاقی به متد Predict ارسال شده و نتیجهی آن، شماره گروه چهرهی تشخیص داده شدهاست. به این ترتیب میتوان تشخیص داد که یک تصویر مفروض ورودی، متعلق به چه شخصی (یا در اینجا گروه یا برچسب) است.
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.
در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 12 - معرفی Tag Helpers» با مفهوم جدید Tag Helpers و همچنین نحوهی استفادهی از نمونههای پیش فرض و توکار آن در ASP.NET Core آشنا شدیم. در ادامه قصد داریم با نحوهی پیاده سازی نمونههای سفارشی آنها نیز آشنا شویم.
نوشتن یک Tag Helper سفارشی، برای رندر کردن لیستهای بوت استرپی
فرض کنید میخواهیم یک tag helper جدید را جهت رندر کردن لیست بوت استرپی ذیل تهیه کنیم:
برای اینکار یک کتابخانهی جدید را به پروژهی جاری اضافه کرده و سپس وابستگیهای ذیل را نیز به آن اضافه میکنیم. اینها حداقلهایی هستند که جهت دسترسی به امکانات MVC و Tag Helpers، در یک پروژهی مجزای Class library نیاز داریم:
بررسی آناتومی یک کلاس TagHelper
یک کلاس Tag Helper سفارشی، در حالت کلی میتواند شکل زیر را داشته باشد:
در اینجا نام کلاس، به TagHelper ختم میشود و همچنین این کلاس از کلاس پایهی TagHelper ارث بری میکند. ذکر HtmlTargetElement الزامی بوده و در صورت عدم تعریف آن، TagHelper تعریف شده توسط ASP.NET Core شناسایی و بارگذاری نخواهد شد.
توسط HtmlTargetElement نام نهایی تگ مرتبط با TagHelper سفارشی را تعریف و سفارشی سازی کردهایم. در این حالت این TagHelper جدید در Viewهای برنامه، توسط تگ ذیل شنایی میشود (بجای نام پیش فرض کلاس):
همچنین در اینجا، یک خاصیت عمومی نیز تعریف شدهاست. تمام خواص عمومی تعریف شدهی در اینجا به صورت ویژگیهایی در تگ نهایی TagHelper قابل دسترسی و مقدار دهی خواهند بود:
برای لغو این حالت میتوان از ویژگی HtmlAttributeNotBound استفاده کرد.
برای اینکه نام این ویژگی را نیز بتوانیم سفارشی سازی کنیم، میتوان از ویژگی HtmlAttributeName استفاده کرد. در صورت عدم ذکر آن، از نام پیش فرض این خاصیت عمومی جهت تعریف ویژگیهای تگ نهایی استفاده میگردد.
عملیات نهایی افزودن تگهای HTML، به View برنامه، در متد Process انجام میشود. در اینجا توسط متدهایی مانند output.Content.AppendHtml میتوان خروجی دلخواهی را به صفحه اضافه کرد.
تکمیل کدهای Tag Helper سفارشی رندر کردن لیستهای بوت استرپی
پس از آشنایی با ساختار کلی یک کلاس TagHelper، اکنون میتوان کدهای آن را به نحو ذیل تکمیل کرد:
توضیحات:
- چون میخواهیم تگ نهایی آن، list-group نام داشته باشد، آنرا توسط ویژگی HtmlTargetElement به صورت صریحی مشخص کردهایم.
- همچنین علاقمندیم تا ویژگی دریافت لیست آیتمها، نامی معادل asp-items داشته باشد. بنابراین آنرا نیز توسط ویژگی HtmlAttributeName، دقیقا مشخص کردهایم.
- در این کلاس، یک خاصیت اضافهی ViewContext را نیز مشاهده میکنید. ویژگی ViewContext اعمالی به آن، سبب خواهد شد تا اطلاعات درخواست جاری، به این خاصیت عمومی، به صورت خودکار تزریق شود. بنابراین اگر نیاز به اطلاعاتی مانند Request جاری دارید، شیء ViewContext.HttpContext.Request، این مقادیر را در اختیار شما قرار میدهد. به علاوه اگر دقت کرده باشید، این خاصیت با ویژگی HtmlAttributeNotBound مزین شدهاست. از این جهت که نمیخواهیم این خاصیت عمومی، در لیست ویژگیهای تگ نهایی TagHelper در حال تهیه، ظاهر شود.
- پس از آن کاری که انجام شده، تکمیل متد Process است. در اینجا توسط output.TagName مشخص میکنیم که TagHelper جاری، در بین تگهای ul قرار گیرد (مفهوم TagMode.StartTagAndEndTag ذکر شده) و همچنین این تگ محصور کننده دارای کلاس list-group بوت استرپ نیز خواهد بود.
- سپس بر روی لیست آیتمهای دریافت شده، یک حلقه را تشکیل داده و به کمک TagBuilder، تگهای li داخل ul برونی را تکمیل میکنیم. این TagBuilder در نهایت توسط متد output.Content.AppendHtml به View برنامه اضافه خواهد شد. در اینجا، متد Append هم وجود دارد. اگر از آن استفاده شود، خروجی نهایی HTML Encoded خواهد بود.
ثبت و استفادهی از TagHelper سفارشی تهیه شده
پس از تعریف TagHelper سفارشی فوق، ابتدا ارجاعی از اسمبلی آنرا به پروژهی جاری اضافه میکنیم و سپس به فایل ViewImports.cshtml_ برنامه مراجعه و یک سطر ذیل را به آن اضافه میکنیم:
در اینجا عبارت Core1RtmEmptyTest.TagHelpers همان نام فضای نام اصلی پروژهی Class library دربرگیرندهی TagHelper سفارشی است.
اکنون که این TagHelper در Viewهای برنامه قابل شناسایی است، روش افزودن آن، بر اساس همان سفارشی سازیهایی است که انجام دادیم:
نوشتن یک Tag Helper سفارشی، برای رندر کردن لیستهای بوت استرپی
فرض کنید میخواهیم یک tag helper جدید را جهت رندر کردن لیست بوت استرپی ذیل تهیه کنیم:
<ul class="list-group"> <li class="list-group-item">Item 1</li> <li class="list-group-item">Item 2</li> <li class="list-group-item">Item 3</li> </ul>
{ "version": "1.0.0-*", "dependencies": { "NETStandard.Library": "1.6.0", "Microsoft.AspNetCore.Http.Extensions": "1.0.0", "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.1", "Microsoft.AspNetCore.Mvc.Core": "1.0.1", "Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.1", "Microsoft.AspNetCore.Razor.Runtime": "1.0.0" }, "frameworks": { "netstandard1.6": { "imports": "dnxcore50" } } }
بررسی آناتومی یک کلاس TagHelper
یک کلاس Tag Helper سفارشی، در حالت کلی میتواند شکل زیر را داشته باشد:
namespace Core1RtmEmptyTest.TagHelpers { [HtmlTargetElement("list-group")] public class ListGroupTagHelper : TagHelper { [HtmlAttributeName("asp-items")] public List<string> Items { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { } } }
توسط HtmlTargetElement نام نهایی تگ مرتبط با TagHelper سفارشی را تعریف و سفارشی سازی کردهایم. در این حالت این TagHelper جدید در Viewهای برنامه، توسط تگ ذیل شنایی میشود (بجای نام پیش فرض کلاس):
<list-group></list-group>
<list-group asp-items="Model.Items"></list-group>
برای اینکه نام این ویژگی را نیز بتوانیم سفارشی سازی کنیم، میتوان از ویژگی HtmlAttributeName استفاده کرد. در صورت عدم ذکر آن، از نام پیش فرض این خاصیت عمومی جهت تعریف ویژگیهای تگ نهایی استفاده میگردد.
عملیات نهایی افزودن تگهای HTML، به View برنامه، در متد Process انجام میشود. در اینجا توسط متدهایی مانند output.Content.AppendHtml میتوان خروجی دلخواهی را به صفحه اضافه کرد.
تکمیل کدهای Tag Helper سفارشی رندر کردن لیستهای بوت استرپی
پس از آشنایی با ساختار کلی یک کلاس TagHelper، اکنون میتوان کدهای آن را به نحو ذیل تکمیل کرد:
using System; using System.Collections.Generic; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; namespace Core1RtmEmptyTest.TagHelpers { [HtmlTargetElement("list-group")] public class ListGroupTagHelper : TagHelper { [HtmlAttributeName("asp-items")] public List<string> Items { get; set; } protected HttpRequest Request => ViewContext.HttpContext.Request; [ViewContext, HtmlAttributeNotBound] public ViewContext ViewContext { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (output == null) { throw new ArgumentNullException(nameof(output)); } if (Items == null) { throw new InvalidOperationException($"{nameof(Items)} must be provided"); } output.TagName = "ul"; output.TagMode = TagMode.StartTagAndEndTag; output.Attributes.Add("class", "list-group"); foreach (var item in Items) { TagBuilder itemBuilder = new TagBuilder("li"); itemBuilder.AddCssClass("list-group-item"); itemBuilder.InnerHtml.Append(item); output.Content.AppendHtml(itemBuilder); } } } }
- چون میخواهیم تگ نهایی آن، list-group نام داشته باشد، آنرا توسط ویژگی HtmlTargetElement به صورت صریحی مشخص کردهایم.
- همچنین علاقمندیم تا ویژگی دریافت لیست آیتمها، نامی معادل asp-items داشته باشد. بنابراین آنرا نیز توسط ویژگی HtmlAttributeName، دقیقا مشخص کردهایم.
- در این کلاس، یک خاصیت اضافهی ViewContext را نیز مشاهده میکنید. ویژگی ViewContext اعمالی به آن، سبب خواهد شد تا اطلاعات درخواست جاری، به این خاصیت عمومی، به صورت خودکار تزریق شود. بنابراین اگر نیاز به اطلاعاتی مانند Request جاری دارید، شیء ViewContext.HttpContext.Request، این مقادیر را در اختیار شما قرار میدهد. به علاوه اگر دقت کرده باشید، این خاصیت با ویژگی HtmlAttributeNotBound مزین شدهاست. از این جهت که نمیخواهیم این خاصیت عمومی، در لیست ویژگیهای تگ نهایی TagHelper در حال تهیه، ظاهر شود.
- پس از آن کاری که انجام شده، تکمیل متد Process است. در اینجا توسط output.TagName مشخص میکنیم که TagHelper جاری، در بین تگهای ul قرار گیرد (مفهوم TagMode.StartTagAndEndTag ذکر شده) و همچنین این تگ محصور کننده دارای کلاس list-group بوت استرپ نیز خواهد بود.
- سپس بر روی لیست آیتمهای دریافت شده، یک حلقه را تشکیل داده و به کمک TagBuilder، تگهای li داخل ul برونی را تکمیل میکنیم. این TagBuilder در نهایت توسط متد output.Content.AppendHtml به View برنامه اضافه خواهد شد. در اینجا، متد Append هم وجود دارد. اگر از آن استفاده شود، خروجی نهایی HTML Encoded خواهد بود.
ثبت و استفادهی از TagHelper سفارشی تهیه شده
پس از تعریف TagHelper سفارشی فوق، ابتدا ارجاعی از اسمبلی آنرا به پروژهی جاری اضافه میکنیم و سپس به فایل ViewImports.cshtml_ برنامه مراجعه و یک سطر ذیل را به آن اضافه میکنیم:
@addTagHelper *,Core1RtmEmptyTest.TagHelpers
اکنون که این TagHelper در Viewهای برنامه قابل شناسایی است، روش افزودن آن، بر اساس همان سفارشی سازیهایی است که انجام دادیم:
یکی از امکانات Angular 7، ویژگی Virtual Scrolling میباشد. در صورتیکه شما قصد داشته باشید یک لیست بزرگ از المنتها را بارگذاری کنید، اینکار میتواند بر روی کارآیی برنامهی شما تاثیر بگذارد . تگ زیر
بعد از نصب با استفاده از ng version نسخهی Angular CLI را بررسی میکنیم که باید بزرگتر از 7 باشد:
بعد از نصب، دستور ng serve را اجرا میکنیم تا بررسی کنیم که برنامه به درستی اجرا میشود یا نه. سپس فایل app.module.ts را باز میکنیم و ScrollingModule را در بخش imports اضافه میکنیم. اکنون نیاز است تا یک آرایه را برای نمایش آیتمهای لیست، تولید کنیم. قطعه کد زیر در فایل app.component.ts قرار دارد که یک آرایه عددی را ایجاد میکند و تعدادی آیتم را به آن اضافه میکند:
<cdk-virtual-scroll-viewport></cdk-virtual-scroll-viewport>
می تواند برای بارگذاری تنها بخشهای قابل مشاهدهی از یک لیست، بر روی صفحه نمایش استفاده شود و همچنین تنها آیتمهایی Render خواهند شد که میتواند آنها را در صفحه نمایش جا دهد. اگر لیست بارگذاری شده را اسکرول کنیم، در این حالت المنتها در DOM به صورت پویا load و unload میشوند.
قبل از پیاده سازی ، لازم است Angular CLI را به آخرین نسخه بروز رسانی کنیم. برای بروز رسانی Angular CLI دستور زیر را اجرا میکنیم:
npm install -g @angular/cli
حالا نوبت به ایجاد یک پروژهی جدید میباشد. با استفاده از دستور زیر یک پروژه جدید ایجاد میشود:
ng new angular7-virtualScrolling
بعد از تایید دستور بالا، دو سؤال از شما پرسیده میشود؟
1- آیا قصد دارید Angular routing اضافه شود یا نه؟ ( در نسخههای قبلی با استفاده از routing-- این کار را انجام میدادیم)
2-انتخاب فرمت stylesheet که قصد استفادهی از آنرا دارید ( با کلیدهای جهتی بالا و پایین روی صحفه کلید میتوانید یکی از گزینهها را انتخاب کنید )
برای استفاده از Virtual Scrolling نیاز است پکیج زیر را نصب کنیم :
npm install @angular/cdk@latest
title = 'Angular 7 – Virtual Scrolling feature'; scrollItems: number[] = []; constructor() { for (let index = 0; index < 10000; index++) { this.scrollItems.push(index); } }
در فایل app.component.html قطعه کد زیر را قرار میدهیم:
<div> <h4> {{this.title}} </h4> <cdk-virtual-scroll-viewport itemSize="100"> <div *cdkVirtualFor="let n of scrollItems">Item {{n}}</div> </cdk-virtual-scroll-viewport> </div>
داخل تگ cdk-virtual-scroll-viewport، یک div را ایجاد و سپس یک دایرکتیو را به نام cdkVirtualFor* به آن اضافه میکنیم. این دایرکتیو، ngFor* را درون cdk-virtual-scroll-viewport، جایگزین میکند که شما با استفاده از آن میتوانید یک حلقه بر روی آرایه scrollItems جهت پیمایش ایجاد کنید.
تمام ! اکنون پروژه را اجرا کنید.
در اولین بار اجرا :
تمام ! اکنون پروژه را اجرا کنید.
در اولین بار اجرا :
بعد از اسکرول کردن لیست :
همانطور که مشاهده میکنیم المنتهای قبلی unload شدند و المنتهای جدید load شدند