در این آموزش به شما استفاده از Vuejs به جای jQuery را نشان خواهیم داد. ضمنا همه کدها در github.com/Erilan/replace-jQuery-by-vuejs قابل دسترسی است.
ابتدا با یک مقایسه بین یک مثال ساده jQuery و یک ترکیب ساده از VueJs شروع می کنیم. یک ترکیب کد VueJs شامل کتابخانه VueJs (به عنوان مثال با استفاده از CDN)، یک DIV و یک اسکریپت کوچک است. این ترکیب و یا ساختار ساده VueJS را در زیر مشاهده می کنید.
ابتدا فایل Simple.HTML را که شامل DIV است، مشاهده می کنید:
<div id="Vue"> Message from vue : {{ message }} </div>
و حالا ساختار فایل simple.vue را مشاهده خواهید کرد:
new Vue({ el: '#Vue', data() { return { message: 'I am in Vue' } } })
نتیجه را در تصویر زیر ببینید:
کد بالا در این لینک قابل دسترس و ویرایش است. می بینید که هیچ چیز پیچیده ای نسبت به ساختار کد jQuery ندارد!
حالا ساختار یک کد jQuery را مشاهده خواهیم کرد. یک DropDown ساده را در زیر می بینید (که با کلیک شدن یک دکمه، لیستی از تعدادی آیتم را نمایش می دهد)
ساختار فایل DropDown.HTML:
<h3>Dropdown - jQuery</h3> <div> <div class="Dropdown-Title js-dropdown">Dropdown me !</div> <div class="Dropdown-ItemList Dropdown-ItemList--closed"> <a class="Dropdown-Item">First link</a> <a class="Dropdown-Item">Second link</a> <a class="Dropdown-Item">Third link</a> </div> </div> <h3>Dropdown - Vuejs</h3> <div id="Vue"> <div class="Dropdown-Title" @click="toggleDropdown">Dropdown me !</div> <div v-if="display" class="Dropdown-ItemList"> <a class="Dropdown-Item">First link</a> <a class="Dropdown-Item">Second link</a> <a class="Dropdown-Item">Third link</a> </div> </div>
و سپس ساختار فایل DropDown.js:
// Dropdown with jQuery $('.js-dropdown').on('click', function(element) { var next = $(this).next() if (next.hasClass('Dropdown-ItemList--closed')) { next.removeClass('Dropdown-ItemList--closed') } else { next.addClass('Dropdown-ItemList--closed') } }) // Dropdown with VueJs new Vue({ el: '#Vue', data() { return { display: false } }, methods: { toggleDropdown() { this.display = !this.display } } })
نتیجه کد jQuery و فایل HTML را در تصویر زیر ببینید:
کد بالا در این لینک قابل دسترس و ویرایش است.
در کد بالا که نتیجه آن را می توانید در تصویر بالا ببینید، این موضوع کاملا واضح است که استفاده از کد jQuery به جای کد Vue.js برای رسیدن به نتیجه ای مثل نتیجه تصویر بالا، کوتاه تر است.
کد بالا یک وظیفه بسیار ساده ای را بر عهده دارد. رویداد کلیک شدن و در ادامه تغییر وضعیت یک کلاس (jQuery) یا تغییر وضعیت یک مقدار boolean (در Vue.js) تنها کاری است که کد بالا انجام می دهد. در حقیقت کد ارائه شده ی بالا در نسخه Vue واقعا بهتر نیست اما نسبت به نسخه jQuery مقداری منطقی تر است. دلیلش هم این است که واقعا شما با یک کلاس رو به رو نیستید. ما یک متغیری داریم که وضعیت dropdown را به ما نشان می دهد، نه اینکه واقعا مثل یک کلاس برنامه نویسی عمل کند!
در زیر مثال دیگری را در jQuery و Vue می بینیم که شامل پنلی با تعدادی لینک است. کلیک کردن روی دکمه ها یا لینک ها موجب تغییر محتوایی می شود که کاربر مشاهده می کند.
در فایل panels.HTML خواهیم داشت:
<h3>Panels - jQuery</h3> <div> <div class="Panel-TitleList"> <button class="Panel-Title js-panel" data-targetPanel="#panel1">First Panel</button> <button class="Panel-Title js-panel" data-targetPanel="#panel2">Second Panel</button> <button class="Panel-Title js-panel" data-targetPanel="#panel3">Third Panel</button> </div> <div class="Panel-ContentList"> <div id="panel1" class="Panel-Content js-contentPanel">Content of the first panel</div> <div id="panel2" class="Panel-Content js-contentPanel Panel-Content--hidden">I am the second panel's content</div> <div id="panel3" class="Panel-Content js-contentPanel Panel-Content--hidden">The third panel is the best</div> </div> </div> <h3>Panels - Vuejs</h3> <div id="Vue"> <div class="Panel-TitleList"> <button class="Panel-Title" @click="activatePanel(1)">First Panel</button> <button class="Panel-Title" @click="activatePanel(2)">Second Panel</button> <button class="Panel-Title" @click="activatePanel(3)">Third Panel</button> </div> <div class="Panel-ContentList"> <div v-if="activePanel === 1" class="Panel-Content">Content of the first panel</div> <div v-if="activePanel === 2" class="Panel-Content">I am the second panel's content</div> <div v-if="activePanel === 3" class="Panel-Content">The third panel is the best</div> </div> </div>
و در ادامه کدهای زیر را در فایل panels.js داریم:
// Panels with jQuery $('.js-panel').on('click', function(element) { var targetId = element.currentTarget.dataset.targetpanel $('.js-contentPanel').addClass('Panel-Content--hidden') $(targetId).removeClass('Panel-Content--hidden') }) // Panels with vuejs new Vue({ el: '#Vue', data() { return { activePanel: 1 } }, methods: { activatePanel(panelIndex) { this.activePanel = panelIndex } } })
و حالا نتیجه کدهای بالا را در تصویر زیر ببینید:
کد بالا در این لینک قابل دسترس و ویرایش است.
در این جا هم کد در نسخه jQuery نسبت به نسخه Vue کوتاه تر است و همچنان موضوع، رویدادِ کلیک کردن است. می بینیم که کد jQuery نسبت به کد Vue کوتاه تر است اما در این جا نکته ی برتری کد برنامه نویسی Vue نسبت به کد jQuery، منطقی تر بودن آن است. برای مثال در کد بالا (نسخه Vue) به جای کلاس های adding/removing، یک متغیری وجود دارد که با تغییر مقدار آن، حالت جدید نشان داده می شود و محتوایی که باید کاربر مشاهده کند، تغییر می کند.
حالا مثالی را که کمی پیچیده تر است، بررسی می کنیم. مثال زیر کدهای یک محاسبه گر را در دو نسخه Vue و jQuery نشان می دهد.
ابتدا کدهای فایل recipe_calculator.HTML را مشاهده می کنید:
<h3>Recipe - jQuery</h3> <div> <label for="serving">Portions :</label> <input type="number" id="servingInput" value="1"> <button class="js-decreaseService">-</button> <button class="js-increaseService">+</button> <div class="Recipe-IngredientList"> <div class="Recipe-Ingredient js-recipeIngredient" data-baseValue="100">Farine : <span></span>g</div> <div class="Recipe-Ingredient js-recipeIngredient" data-baseValue="2">Oeuf : <span></span></div> <div class="Recipe-Ingredient js-recipeIngredient" data-baseValue="150">Lait : <span></span>mL</div> <div class="Recipe-Ingredient js-recipeIngredient" data-baseValue="50">Lardon : <span></span>g</div> </div> </div> <h3>Recipe - Vuejs</h3> <div id="Vue"> <label for="serving">Portions :</label> <input type="number" v-model="serving"> <button @click="decreaseServing">-</button> <button @click="increaseServing">+</button> <div class="Recipe-IngredientList"> <div class="Recipe-Ingredient">Farine : <span>{{ serving * 100 }}</span>g</div> <div class="Recipe-Ingredient">Oeuf : <span>{{ serving * 2 }}</span></div> <div class="Recipe-Ingredient">Lait : <span>{{ serving * 150 }}</span>mL</div> <div class="Recipe-Ingredient">Lardon : <span>{{ serving * 50 }}</span>g</div> </div> </div>
و سپس کدهای فایل recipe_calculator.js را خواهیم داشت:
// Recipe calculator with jQuery var computeServing = function(serving) { $('.js-recipeIngredient').each(function(index, item) { $(item).children('span').HTML($(item)[0].dataset.basevalue * serving) }) } $('#servingInput').on('change', function() { computeServing($(this).val()) }) $('.js-decreaseService').on('click', function() { var currentServing = $('#servingInput').val() $('#servingInput').val(currentServing - 1) computeServing(currentServing - 1) }) $('.js-increaseService').on('click', function() { var currentServing = $('#servingInput').val() $('#servingInput').val(parseInt(currentServing) + 1) computeServing(parseInt(currentServing) + 1) }) computeServing(1) // Recipe calculator with vuejs new Vue({ el: '#Vue', data() { return { serving: 1 } }, methods: { decreaseServing() { this.serving = this.serving - 1 }, increaseServing() { this.serving = this.serving + 1 } } })
مانند مثال های قبل تر، کدهای فایل جاوا اسکریپت بالا در دو نسخه jQuery و Vue ارائه شده است، نتیجه برنامه را در تصویر زیر مشاهده می کنید:
کد بالا در این لینک قابل دسترس و ویرایش است.
کد این مثال در نسخه Vue کوتاه تر از نسخه jQuery کد است و نکته دیگری که باید به آن توجه کرد بهینه تر بودن کد Vue نسبت به کد jQuery است. در کد jQuery واکنش ها روی چند نوع رویداد است: ابتدا خواندن داده از DOM، سپس وارد کردن در innerHTML و در نهایت رفتن دستورالعمل برنامه به بخش محاسبه گر جهت شروع روال اصلی برنامه.
کد Vue را در برنامه بالا را بررسی می کنیم: کد کوتاه تر است و روال منطقی تری دارد. مقدار «حالت یا state» را داریم که کد (شماره) کاری را که باید در برنامه اجرا شود، نشان می دهد و هر خط موارد مربوط به خود را محاسبه می کند. مشاهده نمودید که نه چیزی از DOM خوانده شد و نه چیزی به DOM اضافه شد. ما تنها یک مقدار خاص را محاسبه کردیم. در نهایت هم می توانید واکنش پذیری Vue.js را ببینید.
همان طور که در مقایسه بین نسخه های مختلف کدهای بالا دیده شد، مواردی وجود دارد که کد jQuery از کد Vue کوتاه تر است اما در نهایت افزودن یک منطق صحیح با کد Vue راحت تر است.
در این لینک می توانید کد بالا را (در نسخه Vue) با استفاده بهینه از قدرت کامپوننت ها در Vue ببینید. (نتیجه همان تصویر بالاست)
در لینک قبلی کامپوننت ها شامل تگ های HTML در رشته های جاوا اسکریپتی هستند که همه در داخل یک فایل js. قرار گرفته اند و این ایده خوبی نیست. این کامپوننت ها به دلیل پیچیدگی کدنویسی، قابلیت استفاده مجدد ندارند.
حالا که در تکه کد بالا به جای jQuery، فرمت Vue جایگزین شده آن را دیدید، جهت استفاده بهینه از کامپوننت ها دقیق تر عمل می کنیم. به سراغ webpack می رویم. به دلیل سختی پیکربندی و استفاده از webpack من از نسخه ی standalone که توسط Symfony آماده شده است، استفاده می کنم. جهت نصب آن و برخی پکیج های مرتبط با Vue دستورات زیر را در ترمینال اجرا کنید:
composer require symfony/webpack-encore-pack npm install — save node-sass sass-loader vue vue-loader vue-template-compiler
در فایل تولید شده ی webpack.config.js باید Vue loader را با استفاده از کد زیر فعال کنیم:
Encore // enables VueJs support .enableVueLoader()
حالا می توانیم فایل های vue. را ایجاد کنیم (تا همه چیز در یک فایل جاوا اسکریپت نباشد) و از یک vue-template-loader قوی بهره ببریم.
در رابطه با آخرین برنامه ای که در پیش تر کدهای آن در Vue و jQuery نوشته شد، ابتدا فایل Recipe.vue را ایجاد می کنیم و کدهای زیر را در آن قرار می دهیم:
<template> <div> <label>Portions :</label> <input type="number" v-model="serving"> <button @click="decreaseServing">-</button> <button @click="increaseServing">+</button> <div class="Recipe-IngredientList"> <RecipeIngredient name="Farine" :serving="serving" base-value="100" metric="g"></RecipeIngredient> <RecipeIngredient name="Oeuf" :serving="serving" base-value="2" metric=""/> <RecipeIngredient name="Lait" :serving="serving" base-value="150" metric="mL"/> <RecipeIngredient name="Lardon" :serving="serving" base-value="50" metric="g"/> </div> </div> </template> <script> import RecipeIngredient from './components/RecipeIngredient' export default { name: 'Recipe', components: { RecipeIngredient }, data() { return { serving: 1 } }, methods: { decreaseServing() { this.serving = this.serving - 1 }, increaseServing() { this.serving = this.serving + 1 } } } </script>
همچنین فایل RecipeIngredient.vue را ایجاد می کنیم و کدهای زیر را در آن قرار می دهیم:
<template> <div class="Recipe-Ingredient">{{ name }} : <span>{{ serving * baseValue }}</span>{{ metric }}</div> </template> <script> export default { name: 'RecipeIngredient', props: ['name', 'serving', 'baseValue', 'metric'] } </script>
جهت مقداردهی اولیه در Vue باید یک تگ DIV با کلاس خاصی را در در فایل template.HTML.Twig اضافه کنیم:
<div class="recipe-components-webpack"></div>
سپس فایل app.js را ایجاد و کد زیر را در آن وارد می کنیم. این فایل نقطه شروع جاوا اسکریپت است که در آن با استفاده از «کلاس خاصی» که در کد بالا داده شد، محتوای تگ DIV را مدیریت و یا اصطلاحا رندر می کنیم:
import RecipeComponentsWebpack from './RecipeComponentsWebpack/Recipe' new Vue({ el: '.recipe-components-webpack', // 'h' is for hyperscript => Hyperscript itself stands for "script that generates HTML structure". It's a shortcut for DOM element creation render: h => h(RecipeComponentsWebpack) })
حالا باید دقیق تر به این ساختار Vue که جایگزین jQuery در کدهای بالا شده است، بپردازیم.
در تصویر زیر نقشه ای شماتیک آورده شده است که من به آن نقشه یا چارت برنامه می گویم و در یک نگاه، بخش های مختلفی را که در یک برنامه فریم ورک سیمفونی (برای مثال) با یکدیگر ترکیب شده اند، نشان می دهد. در این مثال من جهت نشان دادن نقشه شماتیک برنامه به سراغ یک برنامه نمونه از فریم ورک سیمفونی رفتم اما این شیوه نقشه شماتیک در سایر فریم ورک ها و ابزارها نیز کاربرد دارد و مرسوم است.
تصویر زیر را مشاهده کنید:
ایده بکار رفته در تصویر بالا جهت ایجاد کردن صفحات (به طور معمول) است که به صورت یک سری static HTML از سمت سرور رندر و با استفاده از بخش های مختلف Vue بهینه و کارا می شوند. به این بخش های Vue در این جا، Vue Widget می گوییم. یک Vue Widget می تواند برای عملکردی خاص یک یا چند بار استفاده شود. همچنین یک Vue Widget می تواند کاملا مستقل به ایفای نقش بپردازد یا همان طور که در چارت بالا قابل مشاهده است، توسط Vuex Store EventBus با سایر Widget ها یا بخش های Vue لینک شود.
با تصویری که از روند کار Vue در بالا ارائه شد، با نگاهی دقیق تر به بررسی ساختار فایل های پروژه می پردازیم. در تصویر زیر ساختار (معماری) فایل های پروژه که Widget ها و کلیه فایل های مرتبط با Vue را مدیریت می کنند، مشاهده می کنید:
در تصویر بالا و در فایل js فقط یک فولدر جهت ابزارهای مرتبط با Vue مانند mixins، پلاگین ها و directive ها و... داریم. همچنین یک فولدر با عنوان widgets موجود است که شامل همه widget های پروژه می شوند. هر widget دایرکتوری مربوط به خود را دارد که محتوی فایل Vue و کامپوننت های مرتبط با widget است. در نظر داشته باشید که می توانیم یک دایرکتوری برای فایل های Vue مشترک داشته باشیم. در ادامه مشاهده می کنید که دایرکتوری store شامل فولدرها و ابزارهای مرتبط با store یا یک دایرکتوری جهت مدیریت service ها، مدیریت api، مدیریت eventBus و ... را داریم.
در نهایت طبق تصویر بالا در شروع به کار فایل های Vue، فایل vueWidgetsHandler را خواهیم داشت که کد آن را در زیر مشاهده می کنید:
import Vue from 'vue' import Vuex from 'vuex' import functionnalStore from './store' import MyFirstWidget from './MyFirstWidget/MyFirstWidget' import MySecondWidget from './MySecondWidget/MySecondWidget' Vue.use(Vuex) export default (function () { let self = {} self.init = function () { document.querySelectorAll('[data-vue-widget="MyFirstWidget"]').forEach(function (element) { let props = {} for (let key in element.dataset) { try { props[key] = JSON.parse(element.dataset[key]) } catch(error) { props[key] = element.dataset[key] } } new Vue({ store: functionnalStore, render: h => h(MyFirstWidget, {props}), }).$mount(element) }) document.querySelectorAll('[data-vue-widget="MySecondWidget"]').forEach(function (element) { new Vue({ render: h => h(MySecondWidget), }).$mount(element) }) } return self }
این فایل وظیفه ایجاد Widget های پروژه را برعهده دارد. این کار می تواند هم صورت کاملا عمومی انجام گیرد تا در پروژه های مختلف یکسان باشد و بارها مورد استفاده قرار گیرد، هم جهت نیازهای یک پروژه به صورت کاملا خاص و سفارشی سازی شده باشد.
حالا می خواهیم برای هر Widget با استفاده از Vue یک نمونه بسازیم که براساس نیازهای widget می تواند شامل موارد مختلفی همچون store ،router و props باشد. در مثالی که در حال بررسی آن هستیم از صفتی به نام dataset جهت مقداردهی props استفاده می کنیم. این روش کاملا با HTML سازگار و به راحتی قابل استفاده می باشد.
در زیر کد فایل props.HTML.twig را می بینید:
<div data-vue-widget="MyFirstWidget" data-widget-name="The Widget of The Dead"></div> <div data-vue-widget="MyFirstWidget" data-widget-name="Beer is Good"></div> <div data-vue-widget="MyFirstWidget" data-widget-name="Vive MontpellierJs ❤"></div>
با ترکیب مناسبی از widget ها می توانید وبسایت های بسیار قوی بسازید. بعنوان مثال این مورد را مشاهده کنید. (در حالت موبایل دید بهتری خواهید داشت)
موارد مختلف بسیاری هستند که می توانید حهت بالا بردن کیفیت پروژه خود در Vue، افزایش کارایی آن و بهینه کردن پروژه از آن ها استفاده کنید، مانند: Vuex store یا eventBus.
در نهایت باید به این نکته اشاره کنم که jQuery، بسیار محبوب و کارامد است و شامل مجموعه کاملی از کتابخانه ها و پلاگین ها می شود که با بکارگیری آن ها می توانید پروژه خود را سرعت بخشید اما استفاده از Vue بسیار هیجان انگیز و جالب است و راه دیگری را برای افزایش کارایی و بهبود پروژه در اختیارتان قرار می دهد. استفاده از Vue از لحاظ کدنویسی تمیزتر و از لحاظ نگهداری کد آسان تر است. همین طور ویژگی های جدیدی هم چون native data binding به شما ارائه می کند.
همه کدها و موارد و مثال های بیشتری در این لینک در دسترس است.
منبع: سایت Medium
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.