تصمیم گرفتم در طی چندین پست در حد توانم به آموزش jQuery بپردازم. (مطالب نوشته شده برداشت ازادی از کتاب jQuery in action است)
جی کوئری (jQuery) چیست؟
نکته: برای استفاده از جی کوئری باید HTML و CSS و جاوا اسکریپت آشنایی داشته باشید.
چگونه از جی کوئری استفاده کنیم؟
برای استفاده از جی کوئری باید ابتدا فایل آن را از سایت آن دانلود کرده و در پروژه خود استفاده نمایید. البته روشهای دیگری برای استفاده از این فایل وجود دارد که در آینده بیشتر با آن آشنا خواهیم شد. برای استفاده از این فایل در پروژه باید به شکل زیر آن را به صفحه HTML خود معرفی کنیم.
<html> <head> <script type="text/javascript" src="jquery-1.9.1.min.js"></script> </head> <body> </body> </html>
کوتاه کردن کد: هر زمان شما خواسته باشید کارکرد یک صفحه وب را پویاتر کنید، در اکثر مواقع به ناچار این کار از طریق عناصری بروی صفحه انجام داده اید که با توجه به انتخاب شدن آنها، صفحه کارکردی خاص خواهد داشت. مثلا در جاوا اسکریپت اگر بخواهیم عنصری را که در یک radioGroup انتخاب شده است را برگردانیم باید کدهای زیر را بنویسیم:
var checkedValue; var elements = document.getElementByTagName ('input'); for (var n = 0; n < elements.length; n++) { if (elements[n].type == 'radio' && elements[n].name == 'myRadioGroup' && elements[n].checked) { checkedValue = elements[n].value; } }
var checkedValue = $ ('[name="myRadioGroup"]:checked').val();
قدرت اصلی جی کوئری برگفته از انتخابکنندهها (Selector) هاست، انتخابکننده ، یک عبارت است که دسترسی به عنصری خاص بر روی صفحه را موجب میشود؛ انتخابکننده این امکان را فراهم میسازد تا به سادگی عنصر مورد نظر را مشخص و به آن دسترسی پیدا کنیم که در مثال فوق، عنصر مورد نظر ما گزینه انتخاب شده از myRadioGroup بود.
Unobtrusive JavaScript: اگر پیش از پیدایش CSS در کار ایجاد صفحههای اینترنتی بودهاید حتما مشکلات و مشقات آن دوران را به خاطر میآورید. در آن زمان برای فرمتدهی به اجزای مختلف صفحه ، به ناچار علائم فرمتدهی را به همراه دستورات خود اجزا، در صفحههای HTML استفاده میکردیم. اکنون بسیار بعید به نظر میرسد کسی ترجیح دهد فرمتدهی اجزا را به همراه دستورهای HTML آن انجام دهد. اگر چه هنوز دستوری مانند زیر بسیار عادی به نظر میآید:
<button type="button" onclick="document.getElementById('xyz').style.color='red';"> Click Me </button>
مجموعه عناصر در جی کوئری:
زمانی که CSS به عنوان یک تکنولوژی به منظور جداسازی طراحی از ساختار به دنیای صفحههای اینترنتی معرفی شد، میبایست راهی برای اشاره به اجزای صفحات از طرف فایل CSS نیز معرفی میشد. این امر از طریق انتخابکنندهها (Selector) صورت پذیرفت.
برای مثال انتخابکننده زیر، به تمام عناصر <a> اشاره دارد که در یک عنصر <p> قرار گرفتهاند:
p a
برای انتخاب مجموعهای از عناصر از یکی از دو Syntax زیر استفاده میکنیم.
$(Selector) یا jQuery(Selector)
مثال زیر نمونهای دیگر است که در آن مجموعهای از تمام لینکهایی که درون تگ <p> قرار دارند را انتخاب میکند:
$("p a")
در اصطلاح برنامه نویسی به چنین توابعی که گروهی از عناصر را جمع میکنند، Wrapper میگویند زیرا تمام عناصر مطلوب را تحت یک شی بستهبندی میکند. در جیکوئری به آنها Wrapped Set یا jQuery Wrapper میگویند و به متدهایی که قابل اعمال بروی اینها به نام jQuery Wrapper Methodes شناخته میشوند.
در مثال زیر میخواهیم تمام عناصر <div> در صورتی که دارای کلاس notLongForThisWorldباشند را مخفی (با فید شدن) کنیم.
$("div.notLongForThisWorld").fadeOut();
فرض کنید در مثال بالا بخواهیم پس از مخفی کردن هر <div> بخواهیم یک کلاس به نام removedبه آن بیافزاییم. به این منظور میتوان کدی مانند زیر نوشت:
$("div.notLongForThisWorld").fadeOut().addClass("removed");
چند نمونه انتخاب کننده:
نتیجه | انتخاب کننده | |
تمام <p>های زوج را انتخاب میکند | $('p:even') | |
سطر اول هر جدول را انتخاب میکند | $("tr:nth-child(1)"); | |
<div>هایی که مستقیما در <body> تعریف شده باشند را انتخاب میکند. | $("body > div"); | |
لینک هایی که به یک فایل pdf اشاره دارند را انتخاب میکند. | $("a[href$=pdf]"); | |
تمام <div> هایی که مستقیما در <body> معرفی شده اند و دارای لینک میباشند را انتخاب میکند. | $("body > div:has(a)") | |
ادامه مطالب در پستهای بعدی تشریح خواهد شد.
جهت مطالعه بیشتر میتوانید از این منابع ^ و ^ و ^ و ^ و ^ استفاده کنید.
موفق و موید باشید
Web-based applications run smoother if instead of using the traditional form method, they use JavaScript to post data to the server and to update the user interface after posting data: It also makes it easier to keep POST and GET actions separated. SignalR makes it even slicker; it can even update multiple pages at the same time. Is it time to use JavaScript to post data rather than posting via the browser the traditional way?
C# 8 و پس از آن
OpenSSL SSL_connect: Connection was reset in connection to github.com:443
git config --global http.sslBackend schannel
[http] sslBackend = schannel
کوکیها به اندازهی خود اینترنت قدیمی هستند و تا سالها، تنها گزینهی شخصی سازی تجربهی کاربری در وب و انتقال آن از یک صفحه به صفحهی دیگری بهشمار میآمدند؛ به این نوع کوکیها، First-party cookies هم میگویند و توسط خود سایت ارائه دهندهی محتوا و برنامهها، تنظیم میشوند. در مقابل آن، third-party cookies یا کوکیهای ثالث هم وجود دارند که از طریق دومین دیگری بجز دومین اصلی برنامه، ارائه و تنظیم میشوند؛ به همین جهت به آنها Cross-site cookies هم میگویند. یکی از اهداف کوکیهای ثالث، ردیابی فعالیت کاربران در بین سایتهای مختلف است و این روزها به علت سوء استفادههای زیادی که از آنها میشوند، یکی از وسایل به اشتراکگذاری و جمع آوری اطلاعات خصوصی کاربران شدهاند.
البته کوکیهای ثالث، کاربردهای مفیدی هم دارند؛ مانند امکان پیاده سازی لاگین و اعتبارسنجی یکپارچهی بین چندین برنامه که به آن SSO یا Single Sign On هم گفته میشود؛ نمونهی آن، استفاده از Identity server و یا OpenId dict در دنیای داتنت است.
اما ... در کل به علت مشکلات یاد شده، اکثر مرورگرها تصمیم به عدم پذیرش و پردازش آنها گرفتهاند. برای مثال مرورگر Safari سالها است که اینگونه کوکیها را بلاک میکند و یا مرورگر فایرفاکس، کوکیهای ثالث ردیابها را بلاک میکند و ... مرورگر کروم نیز تصمیم گرفتهاست، تا پایان سال 2024، به این جمع محلق شود. هرچند اخیرا اعلام کردهاند، بجای اینکه مرورگر کروم، راسا این کار را انجام دهد، قرار است امکان انتخاب این گزینه به خود کاربر واگذار شود (چون ... خود گوگل از این نوع کوکیها منتفع است!). البته این تصمیم، بهنظر W3C خوش نیامده و اعلام کردهاند که این نوع کوکیها باید بروند!
روش آزمایش برنامهها برای بررسی تاثیر ممنوعیت کوکیهای ثالث
برای اینکه پیش از موعد، امکان آزمایش برنامهی خود را داشته باشید و بتوانید تاثیر ممنوعیت بکارگیری کوکیهای ثالث را بررسی کنید، در مرورگر کروم به آدرس زیر مراجعه کرده:
chrome://flags/#test-third-party-cookie-phaseout
و سپس این گزینه را فعال کنید و یا روش دوم فعالسازی آن، اجرای مرورگر کروم با سوئیچ test-third-party-cookie-phaseout-- از طریق خط فرمان است.
کدام برنامهها با ممنوعیت کوکیهای ثالث مشکل پیدا میکنند؟
اگر برنامهی SSO شما، مبتنی بر اعتبارسنجی یکپارچهی از نوع implicit flow است، حتما مشکل پیدا میکنید. در این حالت بهتر است به نوع امنتر authorization flow + PKCE مهاجرت کنید.
علت مسدود شدن نوع اعتبارسنجی و احراز هویت implicit flow که در برنامههای تک صفحهای وب (SPA/single-page apps) مرسوم است، شباهت بسیار زیاد آن به کاری است که ردیابهای اینترنتی انجام میدهند. در اینحالت، سایتهای ثالث، یک iframe مخفی را در پشت صحنه، درون سایت جاری باز کرده و توسط آن شروع به استفادهی از امکانات مرتبط با کوکیها میکنند. این الگو دقیقا همان کاری است که توسط implicit flow هم انجام میشود. بنابراین مرورگری که کوکیهای ثالث از این دست را مسدود میکند، قابلیت اعتبارسنجی یکپارچهی برنامههای SPA را هم غیرفعال خواهد کرد.
پیشنیازهای کار با ASP.NET Core 3.0
خلاصه شدن ساختار فایلهای csproj
- ارتقاء به ASP.NET Core 3.0 و سرنوشت metapackageهای Microsoft.AspNetCore
- در NET Core 3x. دیگر بستههای نیوگت Shared framework به صورت جداگانه تولید و توزیع نمیشوند
ارائهی یک Generic Host در نگارش سوم
- ارتقاء به ASP.NET Core 3.0 و تغییرات نقطهی آغازین برنامه
- قالبی برای ایجاد سرویسهای پسزمینه به NET Core 3.0. اضافه شدهاست که بر اساس Generic Host کار میکند.
- محدود شدن امکان تزریق وابستگیها در سازندهی کلاس آغازین برنامه در ASP.NET Core 3.0
تغییرات مسیریابی با معرفی endpoint routing
- نام متدهای تعاریف مسیریابی تغییر کردهاند.
- تغییرات مورد نیاز در فایل آغازین برنامه جهت ارتقاء به Endpoint routing
- نحوهی تعریف بررسی سلامت برنامه بر اساس endpoint routing تغییر کردهاست.
- همچنین روش فعالسازی ASP.NET MVC نیز تغییر کردهاست.
بالا رفتن کارآیی پردازش JSON
نکتهی مهمی در مورد توزیع برنامههای وب در IIS
- نام بستهی npm سمت کلاینت مخصوص SignalR Core مجددا تغییر کردهاست.
- UseSignalR منسوخ شده اعلام میشود و با UseEndpoints جانشین خواهد شد.
تغییرات امنیتی نگارش سوم
- میانافزار جدید Authorization در ASP.NET Core 3.0
- امضای سازندهی تعدادی از سرویسهای توکار ASP.NET Core Identity 3.0 تغییر کردهاند.
- امضای اینترفیس ILookupNormalizer، توکار ASP.NET Core Identity 3.0 تغییر کردهاست.
- اگر NET Core 3 SDK. را نصب کنید، امکان ایجاد یک برنامهی Angular مبتنی بر Microsoft.AspNetCore.ApiAuthorization.IdentityServer به قالبهای پیشفرض آن اضافه شدهاست.
- تنظیمات کوکیهای سشن تغییر کردهاند.
- تمام Response.Body.Writeها در Action Resultها ممنوع شدهاند.
- هرجائی در برنامهی خود IHostingEnvironment دارید، باید به IWebHostEnvironment تبدیل شود.
بهتر است وارد عمل شویم و ببینیم این سیستم چگونه عمل میکند. برای شروع ما خود Asp .net را به عنوان میزبان در نظر میگیریم.
- یک پروژه خالی Asp .net ایجاد کنید. (Asp .net Empty Web Application)
- وارد خط فرمان Package Manager شوید و عبارت زیر را وارد کنید:
یک کلاس به پروژه اضافه کنید و نام آن را TestModule بگذارید.
در متن کلاس عبارات زیر را تایپ کنید:
public class TestModule : NancyModule { public TestModue() { Get["/"] = x => "Welcome to my site!"; Get["/Hello/"] = x=> "Hello Nancy!"; Get["/Bye/{name}"] = x=> "Good bye " + x.name; } }
حال کلید F5 را زده و برنامه را اجرا کنید.
حالا در مرورگر خودتان عبارت http://localhost:12345/Hello را تایپ کنید. توجه کنید که به جای 12345 باید شماره پورتی که وب سرور دات نت اجراست تایپ کنید.
همانطور که متوجه شدید ما در خطوط بالا تعیین کرده ایم که برای درخواستهای از نوع Get که مسیر ریشه سایت را درخواست میکنند عبارت Welcome to my site! ارسال شود. همچنین برای درخواست هایی که مسیر /Hello را درخواست میکنند عبارت Hello Nancy نمایان میشود.
نکته جالب برای درخواستهای /Bye است. در اینجا ما یک پارامتر به نام name تعریف کرده ایم و گفته ایم که درخواستهای Bye که در ادامه آنها عبارتی وجود دارد به صورت Good bye به همراه عبارت بازگردانده شوند.
همین عملیات برای درخواستهای Put و Head و سایر انواع درخواست وجود دارد.
برای اینکه درخواستها از مسیر خاصی فراخوانی شوند کافی است در هنگام اعلان سازنده کلاس ماژول، مسیر را تعیین کنید.
public class TestModule : NancyModule { public TestModule() : base("/test") { Get["/user"] = x=> "It is test for user"; } }
این درخواستها از مسیری شبیه این مسیر فراخوانی خواهند شد:
Get["/hello/{username}"] = x=> { // some code // ... // ... return "Hello, " + username; };
همچنین امکان بازگرداندن کدهای وضعیت به طور مستقیم وجود دارد.
Get["/user"] = x=> return 200;
و یا
Get["/user] = x=> return HttpStatusCode.OK;
همانطور که گفته شد امکان میزبانی پروژههای Nancy از داخل برنامههای دات نتی هم وجود دارد. در مقاله بعدی به این موضوع خواهیم پرداخت.
<script> let src = 'https://svelte.dev/tutorial/image.gif'; let name = 'Rick Astley'; </script> <img src={src} alt="{name} dancing">
- نکته اول : اگر در تگ img مقدار alt را وارد نکنیم و یا alt در این تگ وجود نداشته باشد، یک هشدار توسط کامپایلر svelte برای ما با عنوان <img> element should have an alt attribute> ایجاد میشود. زمان ساخت یک برنامه بسیار مهم است تا قوانین نوشتن یک کد html خوب را رعایت کنیم تا برای تمامی کاربران احتمالی برنامه قابل استفاده باشد. در همین مثال با ایجاد یک هشدار Svelte تلاش میکند که ما را از اشتباه در نوشتن کد html مطلع سازد.
- نکته دوم : اگر نام یک آبجکت تعریف شده و یک attribute، برابر باشد میتوانیم از نسخه کوتاه شده یا Shorthand attributes در svelte استفاده کنیم. به طور مثال در مثال بالا میتوانیم از کد زیر در خط 6 استفاده کنیم.
<img {src} alt="{name} dancing">
<script> export let siteName = "dotnettips"; </script> <p>this is a nested component for third tutorial on {siteName}</p>
<script> import Nested from "./Nested.svelte"; export let name; </script> <h1>Hello {name}!</h1> <Nested siteName="dotnettips.info" />
Hello world! this is a nested component for third tutorial on dotnettips.info
در مثال بالا ما یک کامپوننت جدید را ایجاد کرده و از طریق دستور import به App.svelte اضافه کردیم. نکتهای که در اینجا وجود دارد، نحوه مقدار دهی props در کامپوننتها است. اگر به خط 9 دقت کنیم، کامپوننت ما از طریق تگ جدیدی با نام (Nested) به بدنه html برنامه اضافه شده است که یک attribute به نام siteName دارد. siteName متغیر export شده در کامپوننت Nested.svelte است که در کامپوننتها به این صورت مقدار دهی میشود. قبلا نحوه مقدار دهی این خصیصهها را در فایلهای جاوا اسکریپت مشاهده کرده بودیم. نکته دیگری که باید به آن دقت داشت این است که خصیصه siteName مقدار پیش فرض dotnettips را در Nested.svelte به خود اختصاص داده بود. به همین جهت اگر ما siteName را هنگام استفاده از کامپوننت مقدار دهی نکنیم، از مقدار پیش فرض خود استفاده خواهد کرد. ولی اینجا ما با مقدار دهی آن، siteName را به dotnettips.info تغییر دادهایم.
نکته مهم : دقت داشته باشید کامپوننتهای شما همیشه باید با حروف بزرگ شروع شوند؛ به طور مثال در صورت نوشتن <nested/> محتوای کامپوننت نمایش داده نخواهد شد. svelte، از طریق زیر نظر گرفتن حروف کوچک و بزرگ در ابتدای تگها، بین تگهای html و کامپوننتها تمایز قائل میشود.
Spread props :
تا اینجا به صورت خلاصه با props یا خصیصهها آشنا شدهاید و دیدیم که با export کردن یک متغیر در یک کامپوننت، میتوانیم آن را هنگام استفاده مقدار دهی نماییم. برای اینکه تمرینی هم باشد با توجه به مطالبی که تاکنون گفته شده، پروژهی جدیدی را ایجاد کنید و محتوای App.svelte را مانند کد زیر تغییر دهید.
<script> import Info from './Info.svelte'; const pkg = { name: 'svelte', version: 3, speed: 'blazing', website: 'https://svelte.dev' }; </script> <Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
همانطور که در خط دوم کد میبینید، کامپوننتی به نام Info.svelte به این بخش اضافه شدهاست. این کامپوننت را با محتوای زیر ایجاد نمایید:
<script> export let name; export let version; export let speed; export let website; </script> <p> The <code>{name}</code> package is {speed} fast. Download version {version} from <a href="https://www.npmjs.com/package/{name}">npm</a> and <a href={website}>learn more here</a> </p>
اگر برنامه را اجرا کنید یک چنین خروجی را مشاهده خواهید کرد:
The svelte package is blazing fast. Download version 3 from npm and learn more here
<Info {...pkg}/>
<script> let count = 0; function handleClick() { count += 1; } </script> <p>Count : {count}</p> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button>
<script> let count = 0; let doubled = count * 2; function handleClick() { count += 1; } </script> <button on:click={handleClick}> Clicked {count} {count === 1 ? 'time' : 'times'} </button> <p>{count} doubled is {doubled}</p>
$: doubled = count * 2;
$: console.log(`the count is ${count}`);
$: { console.log(`the count is ${count}`); alert(`I SAID THE COUNT IS ${count}`); }
$: if (count >= 10) { alert(`count is dangerously high!`); count = 9; }
<script> let numbers = [1, 2, 3, 4]; function addNumber() { let newNumber = numbers.length + 1; numbers.push(newNumber); } $: sum = numbers.reduce((t, n) => t + n, 0); </script> <p>{numbers.join(' + ')} = {sum}</p> <button on:click={addNumber}>Add a number</button>
function addNumber() { let newNumber = numbers.length + 1; numbers.push(newNumber); numbers = numbers; }
function addNumber() { let newNumber = numbers.length + 1; numbers = [...numbers, newNumber]; }
مروری بر Two way bindings :
<script> let name = ""; function updateName(event) { name = event.target.value; } </script> <h4>My Name Is {name}</h4> <input value={name} on:input={updateName} />
<script> let name = ""; </script> <h4>My Name Is {name}</h4> <input bind:value={name} />
{#if condition} <!-- you html codes ... --> {/if}
<script> let user = { loggedIn: false }; function toggle() { user.loggedIn = !user.loggedIn; } </script> {#if user.loggedIn} <button on:click={toggle}> Log out </button> {/if} {#if !user.loggedIn} <button on:click={toggle}> Log in </button> {/if}
{#if condition} <!-- you html code when condition is true --> {:else} <!-- you html code when condition is false --> {/if}
{#if user.loggedIn} <button on:click={toggle}> Log out </button> {:else} <button on:click={toggle}> Log in </button> {/if}
{#if condition} <!-- you html code when condition is true --> {:else if condition2} <!-- you html code when condition2 is true --> {:else} <!-- you html code when condition and condition2 are false --> {/if}
{#each list as item} <!-- you html code per each item in list --> {/each}
<script> let cats = [ { id: 'J---aiyznGQ', name: 'Keyboard Cat' }, { id: 'z_AbfPXTKms', name: 'Maru' }, { id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' } ]; </script> <h1>The Famous Cats of YouTube</h1> <ul> {#each cats as cat} <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}"> {cat.name} </a></li> {/each} </ul>
<ul> {#each cats as {id,name}} <li><a target="_blank" href="https://www.youtube.com/watch?v={id}"> {name} </a></li> {/each} </ul>
<ul> {#each cats as { id, name }, i} <li><a target="_blank" href="https://www.youtube.com/watch?v={id}"> {i + 1}: {name} </a></li> {/each} </ul>
نکته : در این بخش من سعی کردم تا حدودی به ترتیب بخش آموزشی خود وبسایت Svelte، موارد را بیان کنم؛ ولی با توجه به اینکه شاید دوستان ترجیح بدهند روش آموزشی خود آن وبسایت که امکان تغییر و نوشتن کد را هم محیا کرده است، امتحان کنند لینک آن را به اشتراک میگذارم.