یک نکته درباره Angular routeProvider
در اینجا برای بررسی مقدماتی کامپوننتها، یک پروژهی جدید React را ایجاد میکنیم.
> create-react-app sample-04 > cd sample-04 > npm start
> npm install --save bootstrap
پس از اجرای این دستور، ممکن است پیامهای اخطاری مانند «requires a peer of jquery@1.9.1 - 3 but none is installed» را نیز مشاهده کنید که مهم نیستند. چون در اینجا صرفا از امکانات CSS ای بوت استرپ استفاده خواهیم کرد و کاری با jQuery نداریم. محل نصب آن نیز پوشهی node_modules\bootstrap برنامه است.
سپس برای افزودن فایل bootstrap.css به پروژهی React خود، ابتدای فایل index.js را به نحو زیر ویرایش خواهیم کرد:
import "bootstrap/dist/css/bootstrap.css";
ایجاد اولین کامپوننت React
در پوشهی src برنامه، پوشهی جدیدی را به نام components ایجاد میکنیم و تمام کامپوننتهای خود را در آن قرار خواهیم داد. سپس داخل این پوشه، یک فایل جدید و خالی را به نام counter.jsx ایجاد میکنیم. پسوند این فایل jsx است و نام فایلهای کامپوننتها را نیز camel case وارد میکنیم؛ یعنی اولین حرف اولین واژهی وارد شده، با حروف کوچک و تمام واژههای پس از آن با حروف بزرگ شروع خواهند شد مانند coolApp. مزیت استفادهی از پسوند jsx نسبت به js، فراهم شدن امکانات مخصوص React در VSCode است.
در ابتدای فایل counter.jsx، نیاز است وابستگیهای React را import کنیم. اگر از قسمت اول بخاطر داشته باشید، «simple react snippets» را نیز در VSCode نصب کردیم. به کمک آن میتواند این نوع importها را سادهتر وارد کرد. برای این منظور imrc را تایپ کرده و سپس دکمهی tab را فشار دهید. به این ترتیب یک سطر زیر به صورت خودکار تولید میشود:
import React, { Component } from 'react';
import React, { Component } from "react"; class Counter extends Component { render() { return <h1>Hello world!</h1>; } } export default Counter;
خروجی متد render در اینجا، یک رشتهی معمولی نیست؛ بلکه یک عبارت jsx است که در قسمت اول معرفی شد. این عبارت در نهایت توسط کامپایلر Babel به معادل React.createElement ترجمه میشود. به همین جهت نیاز است تا import React را در ابتدای این ماژول درج کرد؛ هرچند به ظاهر به صورت مستقیم از آن استفاده نمیکنیم.
تا اینجا این کامپوننت در UI برنامه نمایش داده نمیشود. به همین جهت به فایل index.js مراجعه کرده و آنرا به صورت زیر تغییر میدهیم:
- ابتدا نیاز است تا شیء Counter را در اینجا import کنیم و چون خروجی پیشفرض است، نیازی به ذکر {} برای معرفی آن نیست:
import Counter from "./components/counter";
ReactDOM.render(<Counter />, document.getElementById("root"));
درج چند عنصر در عبارات JSX
میخواهیم در کامپوننت Counter، یک دکمه را نیز نمایش دهیم. برای انجام اینکار، به نحو زیر عمل میکنیم:
render() { return <h1>Hello world!</h1><button>Increment</button>; }
عبارات JSX در نهایت باید تبدیل به متد React.createElement شوند. اولین پارامتر این متد، نوع المانی است که قرار است ایجاد شود که در اینجا h1 است. اما در اینجا دو المان را داریم. در این حالت Babel نمیداند که چگونه باید یک چنین عبارتی را به React.createElement ترجمه کند. یک راه حل این است که کل این عبارت را داخل یک div قرار داد:
render() { return ( <div> <h1>Hello world!</h1> <button>Increment</button> </div> );
return ; <div></div>
return ( <div></div> );
return ( <React.Fragment> <h1>Hello world!</h1> <button>Increment</button> </React.Fragment> );
نکته 2: در VSCode برای ویرایش همزمان ابتدا و انتهای یک تگ (برای مثال ویرایش همزمان عبارت div در اینجا و تبدیل آن به React.Fragment در دو قسمت)، عبارت آن تگ را انتخاب کرده و سپس دکمههای ctrl+d را فشار دهید تا بتوانید همزمان هر دو عبارت انتخاب شده را با هم ویرایش کنید. به اینکار multi-cursor editing میگویند.
نمایش پویای اطلاعات در عبارات JSX
در ادامه بجای نمایش عبارت ثابت «Hello world»، میخواهیم آنرا به صورت پویا تنظیم کنیم. برای این منظور یک خاصیت جدید را در کلاس جاری، به نام state تعریف کرده و آنرا با یک شیء، مقدار دهی میکنیم. state، یک خاصیت ویژه در کامپوننتهای React است و بیانگر دادههایی است که آن کامپوننت نیاز دارد. این دادهها میتوانند یک key/value ساده باشند و یا حتی value تعریف شده نیز میتواند یک شیء پیچیده باشد.
import React, { Component } from "react"; class Counter extends Component { state = { count: 0 }; render() { return ( <React.Fragment> <span>{this.state.count}</span> <button>Increment</button> </React.Fragment> ); } } export default Counter;
همانطور که عنوان شد در بین {}ها میتوان هر نوع عبارت مجاز جاوا اسکریپتی را ذکر کرد و عبارت چیزی است که مقداری را بازگشت میدهد. بنابراین عبارتی مانند {2+2} را نیز میتوان در اینجا بکار برد و یا حتی در اینجا میتوان متدی را فراخوانی کرد که مقداری را بازگشت میدهد:
import React, { Component } from "react"; class Counter extends Component { state = { count: 0 }; render() { return ( <React.Fragment> <span>{this.formatCount()}</span> <button>Increment</button> </React.Fragment> ); } formatCount() { const { count } = this.state; // Object Destructuring return count === 0 ? "Zero" : count; } } export default Counter;
در متد formatCount حتی میتوان عبارات JSX را نیز بجای یک رشتهی ساده، بازگشت داد:
formatCount() { const { count } = this.state; // Object Destructuring return count === 0 ? <h1>Zero</h1> : count; }
مقدار دهی ویژگیهای عناصر در عبارات JSX
فرض کنید یک المان img را به عبارت JSX کلاس Counter اضافه کردهایم. اکنون میخواهیم ویژگی src آنرا مقدار دهی کنیم. در اینجا هر چیزی که بین "" قرار گیرد، به صورت یک رشتهی ثابت پردازش میشود. برای تنظیم آن به یک متغیر، ابتدا خاصیت state را به صورت زیر جهت درج imageUrl، ویرایش میکنیم:
state = { count: 0, imageUrl: "/logo192.png" };
render() { return ( <React.Fragment> <img src={this.state.imageUrl} alt="" /> <span>{this.formatCount()}</span> <button>Increment</button> </React.Fragment> ); }
return ( <React.Fragment> <img src={this.state.imageUrl} alt="" /> <span className="badge badge-primary m-2">{this.formatCount()}</span> <button className="btn btn-secondary btn-sm">Increment</button> </React.Fragment> );
تا اینجا اگر فایل کامپوننت Counter را ذخیره کنید، خروجی ذیل در مرورگر ظاهر خواهد شد:
روش مقدار دهی ویژگی style نیز متفاوت است. در اینجا React انتظار دارد تا شیءای را که به صورت زیر تشکیل میشود:
styles = { fontSize: 50, fontWeight: "bold" };
return ( <React.Fragment> <img src={this.state.imageUrl} alt="" /> <span style={this.styles} className="badge badge-primary m-2"> {this.formatCount()} </span> <button className="btn btn-secondary btn-sm">Increment</button> </React.Fragment> );
اعمال این styles نمونه، یک چنین خروجی را به همراه خواهد داشت:
مزیت تعریف شیء styles به صورت یک خاصیت در کلاس، امکان استفادهی مجدد از آن در سایر المانها است. اگر چنین چیزی مدنظر شما نیست، میتوان این شیء را به صورت inline هم تعریف کرد:
<button style={{ fontSize: 30 }} className="btn btn-secondary btn-sm">
مقدار دهی پویای ویژگی className عناصر در عبارات JSX
در ادامه میخواهیم اگر مقدار count مساوی صفر بود، span ای که هم اکنون با یک badge آبی (با کلاس badge-primary) نمایش داده میشود، زرد رنگ (با کلاس badge-warning) شود و در غیراینصورت آبی رنگ. بنابراین میخواهیم بر اساس مقدر count، مقدار کلاسهای انتسابی به className را به صورت پویا تغییر دهیم و این الگویی است که در برنامههای واقعی بسیار استفاده میشود:
render() { let classes = "badge m-2 badge-"; classes += this.state.count === 0 ? "warning" : "primary"; return ( <React.Fragment> <img src={this.state.imageUrl} alt="" /> <span style={this.styles} className={classes}> {this.formatCount()} </span> <button style={{ fontSize: 30 }} className="btn btn-secondary btn-sm"> Increment </button> </React.Fragment> );
البته باید دقت داشت که میتوان منطق تشکیل متغیر classes را به یک متد، جهت خلوت سازی متد render نیز منتقل کرد. برای این کار، دو سطر مرتبط با متغیر classes را در VSCode انتخاب کنید. سپس یک آیکن لامپ مانند ظاهر میشود که با کلیک بر روی آن، منوی extract to method نیز قابل انتخاب است:
render() { let classes = this.getBadgeClasses(); // ... } getBadgeClasses() { let classes = "badge m-2 badge-"; classes += this.state.count === 0 ? "warning" : "primary"; return classes; }
<span style={this.styles} className={this.getBadgeClasses()}>
ویژگیهای مورد بحث شامل موارد زیر میباشند:
• ویرایش TextBoxها در محیط Designer
• Copy و Paste کردن Styleها از یک کنترل به کنترل دیگر
• قالب بندی شرطی
• پیمایش و تغییر اندازه گزارش و آیتمهای آن
• تغییر اندازه بخشهای مختلف گزارش نظیر Page Header ، Detail و ...
• افزودن TextBox Shape و PictureBox درون Designer گزارش
• استفاده از پنجره Data Explorer
• استفاده از پنجره Report Explorer
در ادامه به بررسی موارد ذکر شده جهت طراحی گزارش میپردازیم.
1. جهت تغییر محتوای یک TextBox میتوان روی آن دوبار کلیک نمود. پس از آن TextBox به حالت ویرایش میرود و میتوان متن درون آن را به سادگی تغییر داد.این کار در محیط Designer انجام میشود و نیازی نیست برای تغییر محتوای TextBox به پنجره Properties بروید و متن آن را تغییر دهید.
2. در محیط Designer به راحتی میتوانید گزارش خود را Zoom نمایید.این کار توسط ComboBox مربوطه در پایین سمت چپ Designer انجام میشود.
3. اگر قرار باشد TextBox جدیدی به گزارش خود اضافه نمایید، کافی است آن را از بخش ToolBox به محیط گزارش بکشید و سپس به چینش آن بپردازید.
4. در محیط طراح گزارش Telerik میتوانید به راحتی یک قالب بندی و یا Style را از کنترلی به کنترل دیگر کپی نمایید و در وقت خود جهت طراحی گزارش صرفه جویی نمایید. برای انجام اینکار کافی است روی کنترلی که قرار است Style آن را کپی نمایید راست کلیک نموده و پس از آن از منوی ظاهر شده گزینه Copy Style را انتخاب نمایید. در ادامه میتوانید کنترل و یا کنترل هایی که قرار است قالب بندی را به آنها اعمال کنید انتخاب نموده ، روی آنها راست کلیک نمایید و گزینه Paste Style را انتخاب کنید.با این کار Style ی که در مرحله قبل از کنترلی دیگر کپی کرده بودید به کنترل یا کنترلهای انتخاب شده اعمال میشود.
5. یکی دیگر از امکانات Telerik Reporting امکان قالب بندی شرطی (Conditional Formating) میباشد. یعنی Style یک کنترل توسط شرطها تعیین میشود. برای مثال میتوانیم بگوییم که اگر مقدار فروش بیشتر از مبلغ خاصی بود ، عدد نمایش داده شده با رنگ سبز نمایش داده شود و یا اینکه از فونت و یا اندازه دیگری جهت نمایش آن استفاده شود (به طور کلی با توجه به شرطهای تعیین شده نمایش آن کنترل با یک Style متفاوت صورت گیرد). در قسمتهای آینده به بررسی کامل این قابلیت نیز خواهیم پرداخت.
6. یکی از امکاناتی که در هنگام طراحی گزارش در اختیار ما قرار میگیرد پنجره Data Explorer میباشد. توسط این پنجره میتوان فیلدهای یک منبع داده (DataSource) را مشاهده نمود و برای اینکه بتوان از آنها در محیط طراحی استفاده کرد بر روی محیط طراحی درگ نمود. DataSourceها انواع مختلفی دارند که در قسمت اول این آموزش به معرفی آنها پرداختیم و از نمونه Sql آن نیز جهت طراحی یک گزارش ساده استفاده کردیم. در ادامه نیز با این موارد بیشتر آشنا خواهید شد.در تصویر زیر نحوهی درگ کردن یک فیلد تصویر را از پنجره Data Explorer مشاهده مینمایید.
7.
یکی دیگر از اجزای Reporting پنجرهی Report Explorer میباشد. توسط این
پنجره میتوان دسترسی سریعی به اجزای درون گزارش داشت. برای مثال میتوان
به راحتی یک بخش درون گزارش را انتخاب نمود و در پنجرهی Properties
تغییراتی در آن اعمال نمود.
ادامه دارد ...
برپایی ساختار ابتدایی پروژهی تمرین
ابتدا یک پروژهی جدید React را ایجاد میکنیم:
> create-react-app sample-05 > cd sample-05 > npm start
> npm install --save bootstrap > npm install --save font-awesome
در ادامه نیاز است فایلهای CSS این کتابخانهها و قلمهای وب را import کنیم. به همین جهت ابتدای فایل index.js را به نحو زیر ویرایش خواهیم کرد:
import "bootstrap/dist/css/bootstrap.css"; import "font-awesome/css/font-awesome.css";
همچنین به فایل index.css هم مراجعه کرده و یک padding را به بالای صفحه اضافه میکنیم؛ تا اطلاعات نمایش داده شده، با کمی فاصله از لبهی مرورگر رندر شوند:
body { margin: 0; padding: 20px 0 0 0; font-family: sans-serif; }
پس از نصب و import این کتابخانههای ثالث، به فایل App.js مراجعه کرده و کلاس container اصلی بوت استرپ را در آن تعریف میکنیم تا در برگیرندهی محتوای برنامه شود:
return ( <main className="container"> <h1>Hello world!</h1> </main> );
معرفی سرویسهای دادهی برنامه
کدهای نهایی این قسمت را از فایل پیوست شدهی در انتهای مطلب، میتوانید دریافت کنید. در اینجا یک پوشهی src\services تعریف شدهاست که داخل آن دو فایل fakeGenreService.js و fakeMovieService.js قرار دارند. این فایلها، منبع دادهی درون حافظهای مثال تمرین ما هستند.
سرویس fakeGenre چنین ساختاری را دارد و ژانرهای سینمایی، مانند اکشن، کمدی و غیره در آن لیست شدهاند:
export const genres = [ { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" }, // ... ];
و سرویس fakeMovie که دارای ساختار کلی زیر است، لیست 9 فیلم سینمایی را به همراه دارد:
const movies = [ { _id: "5b21ca3eeb7f6fbccd471815", title: "Terminator", genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" }, numberInStock: 6, dailyRentalRate: 2.5, publishDate: "2018-01-03T19:04:28.809Z" }, //... ];
ایجاد کامپوننت Movies برای نمایش لیست فیلمها در برنامه
اکنون میخواهیم یک کامپوننت جدید را به نام Movies در فایل جدید src\components\movies.jsx ایجاد کنیم، تا لیست فیلمهای سرویس fakeMovieService را نمایش دهد. برای اینکار مراحل زیر را طی خواهیم کرد:
- نمایش سادهی لیست فیلمها توسط یک جدول. برای دریافت لیست اشیاء موجود در fakeMovieService، از متد ()getMovies آن میتوان استفاده کرد.
- اضافه کردن یک دکمهی حذف، به هر ردیف، به نحوی که با کلیک بر روی آن، آن ردیف حذف شود.
- نمایش یک پیام بالای جدول که تعداد فیلمهای موجود در سرویس درون حافظهای را نمایش میدهد. همچنین پس از حذف تمام ردیفها، باید پیام «فیلمی موجود نیست» را نمایش دهد.
پس از ایجاد فایل خالی جدید movies.jsx در پوشهی جدید components، با استفاده از «simple react snippets» نصب شدهی در VSCode، یکبار imrc را تایپ کرده (مخفف import react component است) و سپس دکمهی tab را فشار میدهیم، در آخر اینکار را برای cc نیز تکرار میکنیم (مخفف create class است) تا importها و سپس ساختار ابتدایی کامپوننت React ما تشکیل شوند. نام این کامپوننت را هم Movies که با حرف بزرگ شروع میشود، وارد میکنیم.
اکنون مجددا به App.js مراجعه میکنیم و بجای Hello world ای که نمایش دادیم، کامپوننت Movies را اضافه میکنیم. برای این منظور ابتدا import آنرا به ابتدای فایل اضافه میکنیم:
import Movies from "./components/movies";
return ( <main className="container"> <Movies /> </main> );
دریافت لیست اشیاء فیلمها از سرویس fakeMovieService
برای دریافت لیست اشیاء فیلمها، ابتدا تعریف سرویس آنرا به ابتدای کامپوننت Movies اضافه میکنیم:
import { getMovies } from "../services/fakeMovieService";
سپس خاصیت state را جهت تعریف خاصیت movies که با متد ()getMovies سرویس fakeMovieService مقدار دهی میشود، به نحو زیر تکمیل میکنیم:
state = { movies: getMovies() };
نمایش لیست فیلمها، به همراه مدیریت حذف هر ردیف
در ادامه، کدهای کامل و تکمیل شدهی این کامپوننت را ملاحظه میکنید:
import React, { Component } from "react"; import { getMovies } from "../services/fakeMovieService"; class Movies extends Component { state = { movies: getMovies() }; handleDelete = movie => { const movies = this.state.movies.filter(m => m._id !== movie._id); this.setState({ movies }); }; render() { const { length: count } = this.state.movies; if (count === 0) return <p>There are no movies in the database.</p>; return ( <React.Fragment> <p>Showing {count} movies in the database.</p> <table className="table"> <thead> <tr> <th>Title</th> <th>Genre</th> <th>Stock</th> <th>Rate</th> <th /> </tr> </thead> <tbody> {this.state.movies.map(movie => ( <tr key={movie._id}> <td>{movie.title}</td> <td>{movie.genre.name}</td> <td>{movie.numberInStock}</td> <td>{movie.dailyRentalRate}</td> <td> <button onClick={() => this.handleDelete(movie)} className="btn btn-danger btn-sm" > Delete </button> </td> </tr> ))} </tbody> </table> </React.Fragment> ); } } export default Movies;
همانطور که در ابتدای بحث نیز ذکر شد، هدف از این تمرین، مرور قسمتهای قبل است و تمام نکات زیر را در قسمتهای پیشین، با جزئیات بیشتری بررسی کردهایم:
- ابتدا خاصیت state و سپس خاصیت movies شیء منتسب به آن، با لیست فیلمهای موجود در سرویس مرتبط، مقدار دهی شدهاند.
- سپس در ابتدای متد render، کار رندر شرطی انجام شدهاست. اگر تعداد فیلمهای دریافتی صفر بود، پیام «فیلمی در بانک اطلاعاتی موجود نیست» نمایش داده میشود و در غیراینصورت، جدول اصلی بوت استرپی برنامه رندر خواهد شد.
در اینجا چون از خاصیت طول آرایهی فیلمها در چندین قسمت قرار است استفاده شود، آنرا توسط Object Destructuring به یک متغیر نسبت دادهایم. همچنین توسط یک نام مستعار هم خاصیت length را با نام جدید count استفاده میکنیم.
- در ادامه بازگشت React.Fragment را مشاهده میکنید. علت اینجا است که نمیخواهیم div اضافهتری را در UI رندر کنیم. React.Fragment سبب میشود تا بتوانیم چندین فرزند را به المان جاری تبدیل شدهی به کدهای جاوا اسکریپتی اضافه کنیم، بدون اینکه خودش به المانی ترجمه شود.
- پس از return، یک () قابل مشاهدهاست. چون خروجی return ما چند سطری است، اگر در سطری که return قرار میگیرد، اطلاعاتی درج نشود، موتور جاوا اسکریپت آنرا با یک سمیکالن خاتمه خواهد داد! و دیگر سطرهای بعدی دیده نمیشوند و پردازش نخواهند شد. به همین جهت از روش ذکر یک () پس از return در فایلهای jsx زیاد استفاده میشود.
- در ابتدای return، همان خاصیت count را نمایش میدهیم.
- سپس کار رندر جدول اصلی برنامه که با کلاسهای جداول بوت استرپ نیز مزین شده، انجام شدهاست. در React برای عدم تداخل ویژگی class با نام از پیش رزرو شدهی class، از خاصیت className برای ذکر کلاسهای CSSای استفاده میشود.
- قسمت thead این جدول مشخص است و سرستونهای جدول را مشخص میکند.
- پس از آن نیاز است ردیفهای جدول را رندر کنیم. اینکار را توسط متد Array.map، با نگاشت هر آیتم آرایهی this.state.movies، به یک tr جدول انجام دادهایم.
- React برای اینکه بتواند DOM مجازی خودش را کنترل کند، نیاز دارد عناصر موجود در آنرا به صورت منحصربفردی تشخص دهد. به همین جهت در اینجا ذکر key را بر روی المان tr که با movie._id مقدار دهی شدهاست، مشاهده میکنید.
- رندر مقادیر سلولهای ردیفها توسط درج {} و سپس ذکر مقداری از شیء movie دریافتی توسط متد Array.map انجام میشود.
- در اینجا ستون رندر دکمهی Delete را نیز مشاهده میکنید. برای مدیریت this در آن و دسترسی به شیء movie جاری (ارسال پارامتر به رویداد گردان آن) و همچنین دسترسی به شیء this کلاس جاری برای کار با آرایهی this.state.movies، از روش arrow functions برای تعریف رویدادگردان onClick استفاده کردهایم.
- در متد handleDelete، یک آرایهی جدید را که id ردیفهای آن با id شیء ردیف انتخابی یکی نیست، بازگشت میدهیم. انتساب این آرایهی جدید به آرایهی this.state.movies، تغییری را در برنامههای React ایجاد نمیکند. در اینجا باید توسط متد this.setState که از کلاس پایهی extends Component دریافت میشود، خاصیت movies را بازنویسی کرد تا React از تغییرات مطلع شده و DOM مجازی جدیدی را با مقایسهی با نمونه جدید، محاسبه کرده و به DOM اصلی، جهت به روز رسانی UI اعمال کند.
- البته در اینجا this.setState({ movies }) را بجای this.setState({ movies: movies }) مشاهده میکنید. علت اینجا است که اگر عبارات key و value یکی باشند، میتوان تنها همان عبارت key را جهت حذف تکرار واژهها، ذکر کرد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: sample-05.zip
<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، موارد را بیان کنم؛ ولی با توجه به اینکه شاید دوستان ترجیح بدهند روش آموزشی خود آن وبسایت که امکان تغییر و نوشتن کد را هم محیا کرده است، امتحان کنند لینک آن را به اشتراک میگذارم.