معرفی کتابخانه جاوا اسکریپتی Vue.js

سه شنبه 9 خرداد 1396

Vue.js یک کتابخانه جاوا اسکریپت رو به رشد مورداستفاده برای ساخت رابط‌های کاربری (user interface) وب می‌باشد. در این مقاله، با استفاده از ساخت یک اپلیکیشن ساده، کوچک و تک‌صفحه‌ای، کتابخانه Vue.js را به شما معرفی می‌کنیم.

معرفی کتابخانه جاوا اسکریپتی Vue.js

چکیده:

Vue.js، یک کتابخانه جاوا اسکریپت رو به رشد مورداستفاده برای ساخت رابط‌های کاربری (user interface) وب می‌باشد. در این مقاله، با استفاده از ساخت یک اپلیکیشن ساده، کوچک و تک‌صفحه‌ای، کتابخانه Vue.js را به شما معرفی می‌کنیم. ما چگونگی، چرایی و زمان مناسب برای استفاده از Vue.js را توضیح می دهیم و ویژگی‌های ابتدایی این کتابخانه را به شما معرفی می‌کنیم. همچنین ساخت قالب و چگونگی توسعه کامپوننت ها و راه‌های ساخت رابط‌های کاربری کارآمد و جذاب را به شما آموزش خواهیم داد.

در صورت تمایل یه یادگیری کامل این فریم ورک قدرتمند میتونید آموزش Vue Js را در سایت تاپ لرن مشاهده کنید .

Vue.js، یک کتابخانه جاوا اسکریپت رو به رشد جهت ساخت رابط‌های کاربری وب می‌باشد. Vue.js در اصل از Angularjs الهام گرفته است و syntax آن بسیار شبیه Angularjs است. (Angularjs که یکی از چارچوب‌های بسیار محبوب جاوا اسکریپتی است و جهت توسعه اپلیکیشن های وب جدید استفاده می شود و در سال 2013 منتشر شده است. )

شروع کار با Vue.js

تمرکز vue بر اجرای مناسب دو عمل است: سادگی استفاده و سرعت اجرا شدن

Vue این دو قابلیت را به خوبی ارائه می‌کند: یادگیری و استفاده از این کتابخانه بسیار ساده است و کارایی بالاتری نسبت به angularJS و React دارد. Vue.js از بسیاری جنبه‌ها به AngularJS شباهت دارد اما نسبت به این فریم ورک، سبک‌تر و کارآمدتر است.

با این حال،Vue.js یک کتابخانه است و ابزاری همسان با فریم ورک AngularJS را ارائه نمی‌دهد. برای مثال، درحالی‌که چارچوب Angular ابزاری مانند مسیریاب یا سرویس درخواست HTTP ارائه می‌کند، کاربران Vue.js برای دستیابی به چنین ابزاری باید از کدهای سوم شخص (third – party code) استفاده کنند.

Vue.js در حال تبدیل‌شدن به ابزاری مهم برای هر توسعه‌دهنده وب است؛ بنابراین در این مقاله جهت بررسی Vue.js و معرفی این کتابخانه به کاربران تازه‌کار با ساخت یک اپلیکیشن ساده پرداخته شده است: اپلیکیشن Surfpics.

وب‌سایت surfpics فرضی امکان نمایش عکس‌ها و ویدئوهای ساحل و کنار دریا را برای افراد فراهم می‌آورد.

در بخش اول مقاله، طرح کلی کد موردنظر برای این اپلیکیشن آزمایشی را ارائه می‌دهیم. در دو بخش بعدی، توسعه اپلیکیشن با استفاده از Vue.js را ارائه کرده و ویژگی‌های گوناگون آن را معرفی می‌کنیم.

آماده‌سازی اپلیکیشن آزمایشی

قبل از استفاده از Vue.js باید پیش‌زمینه کار برای اپلیکیشن آزمایشی را فراهم کنیم. برای شروع، یک مسیر (Directiry) به نام Src ایجاد می‌کنیم. این دایرکتوری حاوی کد اپلیکیشن Vue.js ما خواهد بود. یک پوشه (folder) به نام Vue درون این دایرکتوری ایجاد می‌کنیم.

سه فایل زیر را درون پوشه Vue ایجاد می‌کنیم:

index.html

app.js

app.css

استایل های زیر را به APP.CSS اضافه می‌کنیم:

#app {
    min-height: 460px;
}
.text-muted {
    color: lightgrey;
}
.search-box {
    margin-left: 1em;
    margin-top: -1em;
}

قوانین بالا رنگ‌ها، حاشیه‌ها و کمترین ارتفاع برای اپلیکیشن ما را تعیین می‌کنند.

ازآنجایی‌که این مقاله درگیر پیچیدگی‌های نشانه‌گذاری‌ها و استایل های CSS نیست، شما می‌توانید هنگام افزودن این قوانین به فایل CSS اپلیکیشن، آنها را نادیده بگیرید.

فایل index.html حاوی طرح اپلیکیشن ساده ما می‌باشد:

<html>
    <head>
        <title>SurfPics</title>
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
        <link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
        <link rel="stylesheet" href="app.css">
    </head>
    <body>
        <nav>
            <div class="nav-wrapper">
                <a href="#" class="brand-logo">SurfPics</a>
                <ul id="nav-mobile" class="right hide-on-med-and-down">
                    <li class="active"><a href="index.html">Home</a></li>
                    <li><a href="foo.html">Foo</a></li>
                    <li><a href="bar.html">Bar</a></li>
                </ul>
            </div>
        </nav>
        <div id="app">
            <!-- App content goes here -->
        </div>
 
        <footer class="page-footer">
            <div class="footer-copyright">
                <div class="container">
                    © 2017 Copyright SurfPics
                </div>
            </div>
        </footer>
        <a href="http://app.js">http://app.js</a>
        <a href="https://code.jquery.com/jquery-2.1.1.min.js">https://code.jquery.com/jquery-2.1.1.min.js</a>
        <a href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js">https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js</a>
    </body>
</html>

کد بالا بسیار واضح است، ما صفحه‌ای حاوی یک نوار پیمایش (navbar) و نوار پایین صفحه (footer) و شامل تکنولوژی‌های مرتبط (materialize و jquery) را ایجاد می‌کنیم. جهت کارایی بهتر، فایل‌های جاوا اسکریپت در پایین صفحه بارگذاری می‌شوند (اگر بارگزاری فایل های جاوا اسکریپت در بالای صفحه بود، باعث کند شدن سرعت بارگزاری صفحه می شد).

تکنولوژی Materialize، یک چارچوب front-end است که واکنش گرا (responsive) نیز هست و مبتنی بر طراحی Material Design است و ما برای طراحی اپلیکیشن آزمایشی خود از آن استفاده می‌کنیم. (طراحی مواد (Meterial Design) به مجموعه‌ای از دستورالعمل‌های طراحی بصری ایجاد شده توسط Google اشاره دارد). این چارچوب، طراحی جذابی را فراهم آورده و برای دوست داران طراحی مواد (Material Design) معادل Bootstrap می‌باشد.

ساخت یک صفحه با استفاده از Vue.JS

اپلیکیشن آزمایشی موردنظر ما بسیار ساده خواهد بود و حاوی یک صفحه و نمایش گر مجموعه‌ای از عکس‌های موجود است (مانند شکل زیر). هر عکس حاوی توضیحات کوتاه و عنوان خواهد بود. عکس، عنوان و توضیحات در یک کادر ارائه خواهند شد.

به علاوه، جهت نمایش مجموعه‌ای از عکس‌ها، یک نوار جستجو در بالای عکس‌ها قرار خواهیم داد که امکان جستجوی عکس‌های دارای عنوان یا توضیحات را فراهم خواهد آورد. اگرچه، عملکرد جستجو را پیاده‌سازی نخواهیم کرد اما پیام «در حال جستجو» را برای آگاه کردن کاربر از انجام فرآیند جستجو پس از وارد کردن عبارت جستجو پیاده‌سازی خواهیم کرد.

ما ساخت اپلیکیشن آزمایشی خود را با استفاده ا ز Vue.js به عنوان یکی از تکنولوژی‌های موجود آغاز می‌کنیم. Vue/index.html را باز کرده و خط زیر را در بالای تگ script در app.js وارد کنید:

<a href="https://unpkg.com/vue/dist/vue.js">https://unpkg.com/vue/dist/vue.js</a>

سپس، نمونه vue.js خود را در app.js به شکل زیر تعریف می‌کنیم:

var app = new Vue({
    el: '#app'
});

توجه کنید که چگونه با چند خط کد کوتاه نمونه سازی مورد نیاز ما انجام شد و مجبور به استفاده از مفاهیم ماژول‌ها و کنترل‌کننده‌ها نشدیم، ما برای ساخت div اپلیکیشن خود  به‌سادگی از شی vue استفاده می‌کنیم(Div با id=’app’). این div ساخته شده نشان می دهد که شی vue ما در تمامی بخش های برنامه قابل دسترسی است.

جهت تعریف کارت‌ها (یا هر داده دیگر) باید از خصوصیات داده‌ای (Data property) استفاده کنیم. در این کار، داده کارت ها را به صورت hard–coding قرار می‌دهیم زیرا درخواست HTTP جهت واکشی داده فراتر از قابلیت‌های Vue هستند و بنابراین فراتر از حوزه این مقاله هم هستند.

یادداشت: پلاگین vue-resource را برای اجرای درخواست‌های وب و مدیریت پاسخ‌ها با استفاده از XmllttlpRequest یا JSON بررسی کنید.

خواهیم دید که چگونه می‌توان به داده‌های حاصل شده از شی Vue دسترسی پیدا کرد؛ اما حال فقط بر روی تعریف داده‌ها با افزودن خصوصیات موردنظر خود به خصوصیت داده شی Vue خود تمرکز می‌کنیم.

ما کادر message را با رشته خالی (empty) و search term را با null مقداردهی اولیه خواهیم کرد. این دو خصوصیت هنگام پیاده‌سازی عملکرد جستجو در مراحل بعد مورداستفاده قرار خواهند گرفت.

هنگام تعریف داده‌های مورداستفاده اپلیکیشن ها، appjs باید به شکل زیر باشد:

var app = new Vue({
    el: '#app',
    data: {
        message: '',
        search_term: null,
        cards: [
            {
                title: 'Sunrise with palm trees',
                description: 'Lorem ipsum dolor sit amet, consectetur', 
                img_src: "img/1.jpg"
            },
            { 
                title: 'Sunrise',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/2.jpg"
            },
            { 
                title: 'Copacabana sunrise',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/3.jpg"
            },
            { 
                title: 'Surfer',
                description: 'Lorem ipsum dolor sit amet, consectetur',
                img_src: "img/4.png"
            }
        ]
    }
});

برای نمایش کارت‌های تعریف‌شده از قبل باید قالب خود را بروز رسانی کنیم (index.html). کدهای زیر را به div این اپلیکیشن اضافه کنید:

<div class="row">
    <div class="col s12 m3">
        <div class="card">
            <div class="card-image">
                <img>
                <span class="card-title">{{card.title}}</span>
                <a>
                <i>add</i>
                </a>
           </div>
           <div class="card-content">
               <p>{{card.description}}</p>
           </div>
       </div>
    </div>
</div>

اغلب بخش‌های این کد واضح هستند. سطری که شامل 4 ستون باشد ایجاد می‌کنیم. کلاس‌های گوناگون مورداستفاده در کد ساده بالا با materialize تعریف‌شده و برای نمایش زیباتر صفحه به کار گرفته می‌شوند.

 با این حال، سه بخش از کد ممکن است ناآشنا به نظر برسند. اول، ویژگی V-for:”card in cards”. این ویژگی، راه حل Vue برای فراهم آوردن تکرار کارت‌های موجود در شی Vue برای کاربران است. هم چنین، این ویژگی بدین معنی است که هر ستون شامل یک کارت است.

ما محتوای هر کارت را به {{card.property}} الحاق می‌کنیم که property، خصوصیت کارتی است که قصد دسترسی به آن را داریم. الحاق (interpolation) بدین معنی است که یک توصیف نگه‌دارنده (در این مورد {{card.property}}) با یک مقدار واقعی از خصوصیت داده‌شده جایگزین می‌شود. پس عنوان و توضیحات هر کارت موجود در شی Vue ما، اجرا خواهد شد.

همانند V-for، V-bind امکان الحاق یک مقدار به یک ویژگی معین را فراهم می‌کند – در این مورد، ما ویژگی Src تصویر را با img.src کارت تنظیم می‌کنیم: V-bind:Src=”card.img-src”

سپس نوار جستجو را تعریف خواهیم کرد. کد نشانه‌گذاری زیر را در بالای سطر حاوی عکس‌ها اضافه کنید.

<div class="row">
    
       <div class="row">
            <div class="input-field col s6">
                 <i class="material-icons prefix text-muted">search</i>
                  
                 Search term
           </div>
      </div>
      <div class="row text-muted">
        <i class="material-icons search">hourglass_empty</i> {{message}}
      </div>
   </form>
</div>

دوباره، کد واضح و روشن است: ما ضرورتاً سطری حاوی یک کادر ورودی اضافه می‌کنیم با استفاده از V-on:change مطمئن می‌شویم که تابعی به نام Search (تعریف‌شده در بالا) در هر جا که ورودی تغییر کند، فراخوانده خواهد شد. با استفاده از v-if، در صورتی که عبارت جستجو وجود داشته باشد آنگاه یک آیکون ساعت شنی همراه با یک پیام نمایش داده می‌شود (همانند شکل زیر). ورودی جستجو با استفاده از V-model به خصوصیت search-term در کنترلر فرستاده می شود.

در آخر، تابع جستجو (search) را با استفاده از خصوصیت methods تعریف می‌کنیم:

methods: {
        search: function () {
            this.message = 'Searching for ' + this.search_term + '...';
        }
}

حال ما یک اپلیکیشن Vue.js داریم که:

_ با استفاده از یک حلقه و الحاق داده‌های مرتبط، سطرها را ایجاد می‌کند.

_ داده‌های ورودی را الحاق می‌کند.

_ در صورت نیاز پیام جستجو را نمایش می‌دهد.

کار خود را ذخیره کرده و برای مشاهده نتیجه، index.html را در مرورگر باز کنید. سپس برای درک بهتری کاری که انجام شده به بخش بعدی بروید.

Directive ها و مؤلفه‌ها در Vue

Vue.js، مسیرها و مؤلفه‌ها را ارائه می‌دهد. دایرکتیوها (Directives) و مؤلفه‌ها (component) توابعی هستند که می‌توانند در Dom به عنوان ویژگی‌های یک عنصر اجرا شده بر روی مبانی پیش عنصری مورد ارجاع واقع شوند. تفاوت بین دایرکتیوها و مؤلفه‌ها این است که «مسیرها»، اصلاحات DOM را کپسوله می‌کنند درحالی‌که «مؤلفه‌ها» واحدهای مستقلی هستند که دیدگاه و منطق داده‌ای خود را دارند.

این موجودیت‌ها امکان استفاده از دو قابلیت قدرتمند را فراهم می‌کنند: مؤلفه سازی (componentization) و بسط زبانی (language extension)

بسط زمانی بدین معنی است که توسعه‌دهنده قادر به توسعه زبان نشانه‌گذاری با ویژگی‌های مرسوم است. برای مثال، فرض کنید که می‌خواهیم یک دایرکتیو جهت نمایش متن توضیحات تصویر با رنگ خاکستری تعریف کنیم. در Vue.js ابتدا باید دایرکتیو را تعریف کنیم.

Vue.directive(‘sp-grey', {
});

به طوری که SP-grey نام دایرکتیو ما است. سپس، هنگامی‌که عنصر در Dom درج شد. نام آن را تغییر می‌دهیم.

Vue.directive('sp-grey', {
    inserted: function (el) {
        el.style.color = 'lightgrey';
    }
});

سپس، دایرکتیو می‌تواند در V-perfix مورداستفاده قرار گیرد:

{{card.description}}

به یاد بیاورید که چگونه در بخش قبل با ویژگی‌های V-perfix رفتار می‌کردیم: v-if، V-for، V-model و غیره. ما تنها به طور مبهم به عنوان روشی برای فراهم کردن یک قابلیت خاص اشاره کردیم. حال که در مورد دایرکتیوها آموزش می‌بینیم باید به طور شفاف‌تر مشخص شود که این ویژگی‌ها به چه چیزی اشاره دارند: این ویژگی‌ها، دایرکتیوهای Vue درونی جهت فراهم آوردن مجموعه‌ای پایه‌ای از عملکردها است. برای مشاهده خلاصه کاملی از مهمترین دایرکتیوهای Vue، جدول زیر را ببینید.

مفهوم مؤلفه‌ها امکان مؤلفه سازی کدهای نشانه‌گذاری را فراهم می‌کند.

به جای داشتن یک قالب بسیار بزرگ که حاوی تمام کدهای نشانه‌گذاری باشد، می‌توان مجموعه‌ی کوچکی از مؤلفه‌های قابل‌استفاده مجدد داشت، بنابراین (1) از تکرار جلوگیری می‌شود و (2) با کاهش مقدار کل کدهای نشانه‌گذاری در یک قالب، قابلیت خوانایی افزایش می‌یابد.

برای تعریف یک مؤلفه در Vue به‌سادگی یک نام و مجموعه‌ای از خصیصه‌ها را تنظیم می‌کنیم:

Vue.component('my-name', {
  template: ‘’,
  // Other options
})

که قالب (tempelate) باید حاوی نشانه‌گذاری مؤلفه باشد. یک مورد کاربردی برای مؤلفه‌ها در اپلیکیشن آزمایشی ما می‌تواند کارت ما برای نمایش یک عکس همراه با عنوان و توضیحات آن باشد. هم چنین قالب مؤلفه شامل نشانه‌گذاری div کارت خواهد بود:

Vue.component('sp-card', {
  template: `
    <div class="card">
        <div class="card-image">
            <img>
            <span class="card-title">{{card.title}}</span>
            <a class="btn-floating halfway-fab waves-effect waves-light red"><i class="material-icons">add</i></a>
        </div>
        <div class="card-content">
            <p>{{card.description}}</p>
        </div>
    </div>`,
});

برای عملکرد دلخواه این مؤلفه نیاز به قابلیت ارسال نمونه به عنوان یک پارامتر به تابع وجود دارد. از طریق خصوصیت props می‌توان به این هدف دست یافت.

Vue.component('sp-card', {
  template: ‘…’,
  props: [‘card’]
});

سپس، برای استفاده از این مؤلفه در نشانه‌گذاری، به‌سادگی Div کارت را با کد زیر جایگزین می‌کنیم:

<sp-card v-bind:card="card"></sp-card>

ویژگی‌های HTML به کوچک و بزرگ بودن حروف حساس نیستند (case - intensive) بنابراین هنگام استفاده از قالب‌های غیر رشته‌ای، نام‌های camel cased باید از معادل‌های kebab-vase خود استفاده کنند. این جمله بدین معنی است که اگر می‌خواهید از نام‌های پارامتر چندکلمه‌ای استفاده کنید. آنگاه کلمات باید با "-" از هم جدا شوند (مثل my –card) درحالی‌که در خصوصیات با استفاده از camel case نشان داده می‌شوند (مثل props:[“myCard”].

قابل‌ذکر است که:"تمام خصوصیات، انقیادی یک‌طرفه بین خصوصیت فرزند و خصوصیت پدر تشکیل می‌دهند: هنگامی‌که خصوصیت پدر بروز رسانی می‌شود آنگاه خصوصیت فرزند نیز بروز رسانی می‌شود اما عکس این جریان انجام نمی‌شود. این امر از تغییر تصادفی وضعیت پدر توسط فرزند که می‌تواند جریان منطقی داده اپلیکیشن شما را دچار اشکال کند، جلوگیری می‌کند."

همانطور که قبلاً ذکر شد، مؤلفه‌ها برخلاف دایرکتیوها می‌توانند شامل داده‌های خاص خود باشند، با این حال، این داده‌ها باید توسط یک تابع برگردانده شوند ( این تابع نمی‌تواند یک شی داده‌ای باشد چراکه این مورد شبیه نمونه Vue  است که قبلاً ساخته‌ایم).

Vue.component('sp-card', {
  template: ‘…’,
  props: [‘card’],
  data: function () { 
    // Return some data object
    return {  }; 
  };
});

مقایسه Vue.js با دیگر  چارچوب‌های جاوا اسکریپت

استفاده از Vue.js نسبت به کتابخانه‌ها یا چارچوب‌های قدیمی‌تر مانند Angular JS مزیت‌های بسیاری دارد. این مزیت‌ها شامل کارایی، سادگی استفاده، انعطاف‌پذیری طراحی ، اندازه  و عملکرد است . در این بخش، هرکدام از این مزیت‌ها را پوشش می‌دهیم.

کارایی (performance)

Vue.js از نظر کارایی اجرا کردن از بسیاری از چارچوب‌های موجود مانند AngularJS یا React بهتر است. در واقع، Vue.js یکی از سریع‌ترین چارچوب‌های موجود است.

برای مثال، زمان اجرا شدن اپلیکیشن آزمایشی ما که حاوی یک سطر داده است با استفاده از AngularJS1 به 1407 میلی‌ثانیه زمان بیشتری نیاز دارد. هنگامی‌که مجموعه داده را از 1 سطر به 100 سطر افزایش دهیم آنگاه تفاوت کارایی قابل‌توجه‌تر می‌شود: Vue.js صفحه را در زمان 48807 میلی‌ثانیه می سازد . درحالی‌که AngularJS به 53403 میلی‌ثانیه زمان برای ساختن صفحه نیاز دارد. زیر توضیحات خلاصه‌شده عمیق‌تری درباره فریم ورک های گوناگون و تفاوت‌های کارایی آنها را نمایش می‌دهد.

انعطاف‌پذیری طراحی (Design flexibility)

Vue.js ، چارچوب کاملاً "خود رأی (opinionated)" نیست. بدین معنی که این کتابخانه تعیین نمی‌کند که چگونه باید مورداستفاده قرار گیرد و اپلیکیشن هایی که از آن استفاده می‌کنند. چگونه باید طراحی شوند. معنی این جملات این است که درحالی‌که دیگر فریم ورک ها ممکن است توسعه‌دهنده‌ها را وادار به پیروی از الگوی خاصی کنند، Vue.js اینطور نیست.

برای مثال، برخلاف Ember یا Angular ، Vue.js شما را وادار با استفاده از ماژول‌ها یا تعریف یک کنترلر نمی‌کند: در عوض، ساخت یک شی Vue.js با داده و روش‌های موردنیاز در قالب پیکربندی می‌شود.

استفاده از یک چارچوب خود رأی (opinionated) می‌تواند مفید یا مضر باشد: این قابلیت با دارا بودن مؤلفه‌هایی، انتخاب نوع طراحی را ساده‌تر می کند و در زمان توسعه‌دهنده‌ها صرفه‌جویی کند، یا می‌تواند مانعی بر سر راه توسعه‌دهنده‌ها جهت انجام کارها به شیوه‌ای خاص باشد.

عملکرد (functionality)

همانطور که قبلاً  ذکر شد، Vue.js یک کتابخانه برای توسعه رابط‌های کاربری وب است. بنابراین، این کتابخانه فقط برای همین کار است. Vue.js با ابزار و ویژگی‌های اضافی همراه نیست. هر چیزی خارج از هدف Vue باید با نوشتن جداگانه کد یا استفاده از کدهای سوم شخص (third-party) به دست آید.

اندازه (siza)

کد پایه‌ای vue.js نسبت به رقبای خود مانند angularJS بسیار کوچک‌تر و ساده‌تر است. Vue.js 21.10 حاوی 8569 خط کد می‌باشد. این موضوع باعث تفاوت بسیاری در اندازه واقعی فایل می‌شود: اندازه فایل Vue.js2.1.10  معادل KB74 است و اندازه1.6.1  Angularjs معادل KB168 است.

نتیجه‌گیری

در این آموزش، Vue.js را با استفاده از ساخت یک اپلیکیشن آزمایش به تازه‌کاران معرفی کردیم. هم چنین، مهمترین ویژگی‌های این کتابخانه نشان‌دهنده چگونگی استفاده از Vue جهت ساخت سریع یک رابط کاربری وب قدرتمند و انعطاف‌پذیر پوشش دادیم.

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید