- 1. რა არის Vue.js ?
-
Vue.js (იგივე Vue) არის, ჯავასკრიპტის ფრეიმვორკი (და არა ბიბლიოთეკა) ღია წყაროთი,
რომელიც გამოიყენება სამომხმარებლო ინტერფეისებისა (UI - User Interface) და ერთგვერდიანი აპლიკაციების
(SPA - single page application) შესაქმნელად.
სამომხმარებლო ინტერფეისი (UI - User Interface) არის სივრცე, გარემო, რომლის მეშვეობითაც მომხმარებელი მართავს პროგრამულ მოწყობილობებსა და აპლიკაციებს. ვებ-სივრცის გადმოსახედიდან თუ ვიტყვით, სამომხმარებლო ინტერფეისი არის ყველაფერი რასაც ბრაუზერში ვხედავთ.ერთგვერდიანი აპლიკაციის (SPA) უკან მოიაზრება ვებ-აპლიკაცია ან ვებ-გვერდი, რომელიც ბრაუზერის განახლების (refresh) გარეშე ახდენს ინფორმაციის ერთ კონკრეტულ გვერდზე დინამიურად გამოტანას, მომხმარებლის ქმედებიდან გამომდინარე.
რა განსხვავებაა ფრეიმვორკსა და ბიბლიოთეკას შორის ?
ბიბლიოთეკა არის კონკრეტული მიზნებისათვის შექმნილი კონკრეტული ფუნქციების ორგანიზებული ნაკრები (მაგ: სტრიქონებთან სამუშო ფუნქციების, ფაილებთან სამუშაო ფუნქციების და ა.შ).ფრეიმვორკი არის პროექტის აბსტრაქტული, განზოგადებული ფორმა, შაბლონი, ჩონჩხი, კოდირების დიზაინი, რომელშიც სისტემის მართვის მექანიზმი უკვე შექმნილია თუმცა არის სივრცეები სადაც შეგვიძლია ჩვენი კოდი შევიტანოთ, შემდეგ ხდება ზემოთ ნახსენები, უკვე არსებული ფუნდამენტისა და ჩვენი კოდის 'შეზავება' და ასე ყალიბდება პროექტის სრული იერსახე.
Vue გავრცელებულია javascript ფაილის სახით და ვებ-გვერდზე მისი დამატება შესაძლებელია script ტეგის მეშვეობით :
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
ჩვენი პირველი გვერდი
ბიჯი 1: HTML გვერდი
შევქმნათ მარტივი HTML გვერდი :<!DOCTYPE html> <html lang="en"> <head> <title>My first Vue page</title> </head> <body> </body> </html>
ბიჯი 2: დავამატოთ <div> ელემენტი
საჭიროა შევქმნათ რაიმე HTML ელემენტი, რომელსაც დაუკავშირდება Vue. დავამატოთ <div> ელემენტი და მივცეთ მას id :<!DOCTYPE html> <html lang="en"> <head> <title>My first Vue page</title> </head> <body> <div id="app"></div> </body> </html>
ბიჯი 3: დავკავშირდეთ Vue-სთან
<!DOCTYPE html> <html lang="en"> <head> <title>My first Vue page</title> </head> <body> <div id="app"></div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> </body> </html>
ბიჯი 4: შევქმნათ Vue-ს ინსტანცია
ავკრიფოთ ჩვენი პირველი Vue კოდი.
კოდის ეს ფრაგმენტი შეიძლება შეიცავდეს სხვადასხვა ინფორმაციებს, მეთოდებს და ა.შ. ამ ეტეპზე უბრალოდ რაიმე შეტყობინება გამოვიტანოთ .
ბოლოს კი ახლადშექმნილი Vue-ს ინსტანცია დავაკავშიროთ მე-2-ე ბიჯში შექმნილ <div> ელემენტთან.
<!DOCTYPE html> <html lang="en"> <head> <title>My first Vue page</title> </head> <body> <div id="app"></div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { message: "Hello World!" } } }) app.mount('#app') </script> </body> </html>
ინგ: mount - დაყენება, დამონტაჟება, დადგმაბიჯი 5: გამოვიტანოთ შეტყობინება ინტერპოლაციის გზით
ახლა შევეცადოთ შეტყობინება გამოვიტანოთ ინტეპოლაციის გზით, Vue-ში ამისათვის გამოიყენება ორმაგი ფიგურული ფრჩხილები: {{ }}<div id="app"> {{ message }} </div>
<!DOCTYPE html> <html lang="en"> <head> <title>My first Vue page</title> </head> <body> <div id="app"> {{ message }} </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { message: "Hello World!" } } }) app.mount('#app') </script> </body> </html>
უცხო სიტყვ. ლექს: ინტეპოლაცია - რაიმე ნაწარმოების ტექსტში გვიანდელი ჩანართი, რომელიც ავტორს არ ეკუთვნისჯავასკრიპტი ინტერპოლაციაში
ინტერპოლაციაში აგრეთვე შესაძლებელია ჯავასკრიპტ კოდის გამოყენებაც :<div id="app"> {{ message }} <br> {{'Random number: ' + Math.ceil(Math.random()*6) }} </div>
- 2. Vue დირექტივები
-
Vue-ში დირექტივა ეწოდება სპეციალურ HTML ატრიბუტს, რომელსაც ერთვის პრეფიქსი v- და რომლის მეშვეობითაც HTML ელემენტი ხდება უფრო ფუნქციონალური.
დირექტივები უკავშირდებიან Vue-ს ინსტანციას. სწორედ ეს კავშირი უზრუნველყოფს სამომხმარებლო ინტერფეისის რეაქტიულობასა და დინამიურობას.
დირექტივა აღწერა v-bind HTML ელემენტის ატრიბუტს აკავშირებს Vue-ს ინსტანციაში აღწერილ ცვლადთან. v-if პირობითი ოპერატორის შედეგიდან გამონდინარე ქმნის HTML ელემენტს. ამ დირექტივასთან ერთად შესაძლებელია v-else-if და v-else დირექტივების გამოყენებაც. თუ პირობითი ოპერატორის შედეგი არის false მაშინ ელემენტი საერთოდ არ შეიქმნება DOM-ში (DOM-ის შესახებ ინფორმაცია შეგიძლიათ იხილოთ ჯავასკრიპტის ცნობარის მე-20-ე თავში). v-show პირობითი ოპერატორის შედეგიდან გამონდინარე განსაზღვრავს უნდა იყოს თუ არა ხილვადი კონკრეტული HTML ელემენტი. თუ პირობითი ოპერატორის შედეგი არის false, ელემენტი მაინც შეიქმნება DOM-ში, თუმცა მიენიჭება CSS თვისება display: none v-for ქმნის HTML ელემენტების სიას Vue-ს ინსტანციაში აღწერილი მასივისა და for ციკლის მეშვეობით. v-on როგორც ვიცით HTML ელემენტთან მუშაობისას შეიძლება შესრულდეს სხვადასხვა მოვლენები (მოვლენების შესახებ ინფორმაცია შეგიძლიათ იხილოთ ჯავასკრიპტის ცნობარის 25-ე თავში). ეს დირექტივა კი ამ მოვლენებს აკავშირებს Vue-ს ინსტანციაში აღწერილ მეთოდებთან. v-model გამოიყენება HTML ფორმებში არსებულ <form>, <input>, <button> და სხვა ტიპის ელემენტებთან სამუშაოდ. უზრველყოფს ინფორმაციის მიმაგრების ორმხრივ გზას ელემენტებსა და Vue-ს ინსტანციაში აღწერილ თვისებებს შორის. - 3. Vue v-bind დირექტივა
-
v-bind დირექტივის მეშვეობით შესაძლებელია HTML ატრიბუტებს, მათი გადინამიურების მიზნით მივამაგროთ Vue-ს ინსტანციაში
აღწერილი მნიშვნელობები (ინგ: bind - მიბმა; დამაგრება). გამოყენების სინტაქსი ასეთია :
<div v-bind:[attribute]="[Vue data]"></div>
<!DOCTYPE html> <html> <head> <title>'v-bind' Image Source Example</title> </head> <body> <div id="app"> <img v-bind:src="url"> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { url: "img_beach3.jpg" } } }) app.mount('#app') </script> </body> </html>
სტილების მიმაგრება
v-bind დირექტივის მეშვეობით შესაძლებელია ხაზსშიდა სტილების განსაზღვრაც. ამისათვის შეგვიძლია გამოვიყენოთ ჯავასკრიპტის ობიექტები. მოვიყვანოთ მაგალითი, რომელშიც ფონტის ზომა დამოკიდებული იქნება Vue-ში არწერილ 'size' თვისებაზე :<!DOCTYPE html> <html> <head> <title>v-bind font-size</title> </head> <body> <div id="app"> <div v-bind:style="{ fontSize: size }">Text example</div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { size: "28px" } } }) app.mount('#app') </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>v-bind background-color</title> </head> <body> <div id="app"> <div v-bind:style="{ backgroundColor: isImportant ? 'lightcoral' : 'lightgray' }"> Importance based on background color </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { isImportant: true } } }) app.mount('#app') </script> </body> </html>
კლასების მიმაგრება
<!DOCTYPE html> <html> <head> <title>v-bind background-color</title> <style> .impClass { background-color: lightcoral; } </style> </head> <body> <div id="app"> <div v-bind:class="className"> Importance visualized by background color </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { className: 'impClass' } } }) app.mount('#app') </script> </body> </html>
<div id="app"> <div :class="className"> Importance visualized by background color </div> </div>
- 4. Vue v-if დირექტივა
-
როგორც ადრე აღვნიშნეთ, v-if დირექტივა პირობითი ოპერატორის შედეგიდან გამონდინარე ქმნის HTML ელემენტს. ამ დირექტივასთან ერთად შესაძლებელია
v-else-if და v-else დირექტივების გამოყენებაც. თუ პირობითი ოპერატორის შედეგი არის false მაშინ ელემენტი საერთოდ არ შეიქმნება DOM-ში.
<!DOCTYPE html> <html> <head> <title>Typewriters</title> </head> <body> <div id="app"> <p v-if="typewritersInStock"> in stock </p> <p v-else> not in stock </p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { typewritersInStock: false } } }) app.mount('#app') </script> </body> </html>
პირობითი ოპერატორები Vue-ში
დირექტივა აღწერა v-if შეიძლება გამოვიყენოთ, როგორც ცალკე, ასევე v-else-if და/ან v-else დირექტივებთან ერთად. თუ v-if დირექტივაში მოქცეული პირობა ჭეშმარიტია, ანუ არის 'true', v-else-if და v-else დირექტივები აღარ განიხილება. v-else-if გამოყენებულ უნდა იქნას v-if ან სხვა v-else-if დირექტივასთან ერთად. თუ მიმდინარე v-else-if დირექტივაში არსებული პირობა არის ჭეშმარიტი, ანუ 'true', მაშინ ამ დირექტივის შემდეგ არსებული v-else-if და v-else დირექტივები აღარ განიხილება. v-else ყოველთვის ჭეშმარიტია, ანუ 'true', მაგრამ განიხილება მხოლოდ იმ შემთხვევაში თუ მანამდე არსებული ყველა პირობითი ოპერატორი მცდარია. დირექტივა იწერება პირობითი ოპერატორის ბოლოში. <!DOCTYPE html> <html> <head> <title>My first Vue page</title> </head> <body> <div id="app"> <p v-if="typewriterCount>3"> პროდუქტი არის მარაგში </p> <p v-else-if="typewriterCount>0"> მარაგი იწურება </p> <p v-else> პროდუქტი არ არის მარაგში </p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { typewriterCount: 3 } } }) app.mount('#app') </script> </body> </html>
- 5. Vue v-show დირექტივა
-
v-show დირექტივა პირობითი ოპერატორის შედეგიდან გამონდინარე განსაზღვრავს უნდა იყოს თუ არა ხილვადი კონკრეტული HTML ელემენტი.
თუ პირობითი ოპერატორის შედეგი არის false, ელემენტი მაინც შეიქმნება DOM-ში, თუმცა მიენიჭება CSS თვისება display: none;
<!DOCTYPE html> <html> <head> <title>v-show</title> </head> <body> <div id="app"> <div v-show="showDiv">This div tag can be hidden</div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { showDiv: true } } }) app.mount('#app') </script> </body> </html>
განსხვავება v-show და v-if დირექტივებს შორის
განსხვავება v-show და v-if დირექტივებს შორის არის ის, რომ v-if დირექტივა ელემენტს ქმნის პირობიდან გამომდინარე. v-show დირექტივა კი უკვე შექმნილი ელემენტის ხილვადობას ცვლის, ამიტომ, როდესაც ელემენტის ხილვადობის დინამიურად გადართვა გვჭირდება უმჯობესია გამოვიყენოთ v-show დირექტივა, რადგან ამ შემთხვევაში ბრაუზერი შედარებით უფრო სწრაფად დაამუშავებს მოთხოვნას.თავის მხრივ v-if დირექტივას ის უპირატესობა აქვს, რომ მისი გამოყენება v-else-if და v-else დირექტივებთან ერთადაა შესაძლებელი.
<!DOCTYPE html> <html> <head> <title>v-show vs. v-if</title> </head> <body> <div id="app"> <div v-show="showDiv">Div tag with v-show</div> <div v-if="showDiv">Div tag with v-if</div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { showDiv: true } } }) app.mount('#app') </script> </body> </html>
- 6. Vue v-for დირექტივა
-
სტანდარტულ ჯავასკრიპტში მასივის მიხედვით HTML ელემენტების დასაგენერირებლად უნდა გამოვიყენოთ for ციკლი, რომლის თითოეულ იტერაციაზეც შევქმნით
ახალ ელემენტს, ამასთანავე თუ მასივის მნიშვნელობა შეიცვლება, ეს ცვლილება რეაქტიულად არ აისახება სამომხმარებლო ინტერფეისში.
Vue-ში კი HTML ელემენტს უბრალოდ ვუწერთ v-for დირექტივას, რომელიც დაკავშირებულია Vue-ს ინსტანციაში აღწერილ მასივთან და დანარჩენს Vue აკეთებს. ამგვარად დაგენერირებული ელემენტების ცვლილებაც ავტომატურად ხდება მასივის ცვლილებისას.
სიის გენერირება მასივების მეშვეობით
<!DOCTYPE html> <html> <head> <title>My first Vue page</title> </head> <body> <div id="app"> <ol> <!-- შევქმნათ li ელემენტი manyFoods მასივში მოქცეული, x ცვლადით აღნიშნული თითოეული საკვებისათვის --> <li v-for="x in manyFoods">{{ x }}</li> </ol> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { manyFoods: [ 'ბანანი', 'პიცა', 'ნამცხვარი', 'თევზი', 'ბრინჯი' ] } } }) app.mount('#app') </script> </body> </html>
სიის გენერირება ობიექტთა მასივების მეშვეობით
<!DOCTYPE html> <html> <head> <title>My first Vue page</title> </head> <body> <div id="app"> <figure v-for="x in manyFoods"> <img v-bind:src="x.url"> <figcaption>{{ x.name }}</figcaption> </figure> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { manyFoods: [ {name: 'ბანანი', url: 'img_banana.svg'}, {name: 'პიცა', url: 'img_pizza.svg'}, {name: 'ნამცხვარი', url: 'img_cake.svg'}, {name: 'თევზი', url: 'img_fish.svg'}, {name: 'ბრინჯი', url: 'img_rice.svg'} ] } } }) app.mount('#app') </script> </body> </html>
ინდექსის დადგენა
იმის დასადგენად რა არის მიმდინარე ინდექსი, ანუ მასივის რომელ ელემენტთან ვმუშაობთ კონკრეტულ იტერაციაზე, გამოიყენება შემდეგი სინტაქსი :<!DOCTYPE html> <html> <head> <title>My first Vue page</title> </head> <body> <div id="app"> <p v-for="(x, index) in manyFoods"> {{ index }}: "{{ x }}" </p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { manyFoods: [ 'ბანანი', 'პიცა', 'ნამცხვარი', 'თევზი', 'ბრინჯი' ] } } }) app.mount('#app') </script> </body> </html>
- 7. Vue მოვლენები
-
Vue-ში მოვლენათა დამუშავება ხდება v-on დირექტივის მეშვეობით, მაგალითად ჩვენ შეგვიძლია შევასრულოთ რაიმე ინსტრუქცია, როდესაც მომხმარებელი დააწვება ღილაკს.
<!DOCTYPE html> <html> <head> <title>მთვლელი</title> </head> <body> <div id="app"> <p>{{ "მთვლელი: " + count }}</p> <button v-on:click="count++">მთვლელის გაზრდა</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { count: 0 } } }) app.mount('#app') </script> </body> </html>
ყველაზე გავრცელებული მოვლენებია: 'click', 'mouseover', 'mouseout', 'keydown' and 'input'.
თუ გვსურს, რომ რომელიმე მოვლენისას უფრო რთული ოპერაცია შევასრულოთ ვიდრე უბრალოდ მთვლელის გაზრდაა, მაშინ შეგვიძლია ეს ოპერაცია Vue მეთოდში აღვწეროთ :<p v-on:click="changeColor">ფერის შეცვლა</p>
- 8. Vue v-on დირექტივა
-
v-on დირექტივის მეშვეობით Vue-ში შეგვიძლია ბრაუზერს გადავცეთ თუ რომელ მოვლენას ('click', 'keydown', 'mouseover' და ა.შ) ვამუშავებთ და რა ოპერაციის
შესრულება გვინდა ამ მოვლენის მოხდენისას.
onclick მოვლენა
v-on:click მოვლენა ფიქსირდება რომელიმე ელემენტზე მაუსის დაჭერისას.<!DOCTYPE html> <html> <head> <title>Light Switch</title> </head> <body> <div id="app"> <div id="lightDiv"> <div v-show="lightOn">გამოჩნდეს/დაიმალოს ღილაკზე დაჭერისას</div> </div> <button v-on:click=" lightOn =! lightOn ">გამოჩენა/დამალვა</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { lightOn: false } } }) app.mount('#app') </script> </body> </html>
oninput მოვლენა
v-on:input მოვლენა ფიქსირდება ტექსტურ ველში რომელიმე კლავიშზე დაჭერისას.<!DOCTYPE html> <html> <head> <title>Count Input Events</title> </head> <body> <div id="app"> <input type="text" v-on:input="inpCount++" placeholder="აკრიფეთ ტექსტი"> <p>{{ 'მოვლენა დაფიქსირდა: ' + inpCount + '-ჯერ' }}</p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { inpCount: 0 } } }) app.mount('#app') </script> </body> </html>
mousemove მოვლენა
v-on:mousemove მოვლენა ფიქსირდება როდესაც მაუსს გადავატარებთ ელემენტზე.<!DOCTYPE html> <html> <head> <title>Change Color</title> <style> #app > div { width: 200px; height: 80px; } </style> </head> <body> <div id="app"> <div v-on:mousemove=" colorVal = Math.floor(Math.random()*360) " v-bind:style=" {backgroundColor: 'hsl('+colorVal+',60%,60%)'} "></div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { colorVal: 50 } } }) app.mount('#app') </script> </body> </html>
<button v-on:click=" lightOn =! lightOn ">გამოჩენა/დამალვა</button> იგივეა რაც : <button @:click=" lightOn =! lightOn ">გამოჩენა/დამალვა</button>
- 9. Vue მეთოდები
-
როგორც ადრე აღვნიშნეთ, კონკრეტულ მოვლენებთან კომპლექსური ინსტრუქციების დასაკავშირებლად Vue-ში გამოიყენება ფუნქციები, რომელთა აღწერაც უნდა მოხდეს
Vue-ს ინსტანციაში განსაზღვრულ methods თვისებაში.
აქამდე ჩვენ ვიცნობდით მხოლოდ data თვისებას, სადაც კონკრეტული მნიშვნელობების აღწერას ვაკეთებდით. იმისათვის რათა methods თვისებაში აღწერილ ფუნქციაში გამოვიყენოთ data თვისებაში აღწერილი ცვლადი, ამ ცვლადს უნდა დავურთოთ this. პრეფიქსი.
<!DOCTYPE html> <html> <head> <title>Click To Run Method</title> </head> <body> <div id="app"> <p>{{ text }}</p> <button v-on:click="changeText">ტექსი</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { text: '' } }, methods: { changeText() { this.text = 'Hello World!' } } }) app.mount('#app') </script> </body> </html>
მეთოდის გამოძახება მოვლენის ობიექტის მეშვეობით
როდესაც კონკრეტული მოვლენა ფიქსირდება და შესაბამისად ხდება რომელიმე მეთოდის გამოძახება, ამ მეთოდში შეგვიძლია მივწვდეთ მოვლენის ობიექტს, რაც საკმაოდ მოსახერხებელია, რადგან ეს ობიექტი საკმაოდ ბევრ სასარგებლო ინფორმაციას ინახავს, მაგალითად ინფორმაციას სამიზნე ობიექტის შესახებ (ანუ იმ ობიექტის, რომელზეც მოვლენა გვაქვს მიმაგრებული), ინფორმაციას მოვლენის ტიპის შესახებ და ა.შ.მოვიყვანოთ მაგალითი სადაც <div> ელემენტზე მივამაგრებთ 'mousemove' მოვლენას, როდესაც ეს მოვლენა დაფიქსირდება მოვახდინოთ 'mousePos' მეთოდის გამოძახება, ამ მეთოდში კი მოვლენის ობიექტის მეშვეობით მივწვდეთ მაუსის კოორდინატებს :
<!DOCTYPE html> <html> <head> <title>Mouse Pointer Position</title> <style> #app { border: black dashed 1px; width: 200px; padding: 0 20px 20px 20px; } #app > div { width: 160px; height: 80px; background-color: lightcoral; padding: 20px; } #app span { font-weight: bold; font-family: 'Courier New', Courier, monospace; } </style> </head> <body> <div id="app"> <div v-on:mousemove="mousePos"> <span>xPos: {{ xPos }}</span><br><span>yPos: {{ yPos }}</span> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { xPos: 0, yPos: 0 } }, methods: { mousePos(event) { this.xPos = event.offsetX this.yPos = event.offsetY } } }) app.mount('#app') </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>სამიზნე ობიექტი</title> </head> <body> <div id="app"> <textarea v-on:input="writeText" rows="5"></textarea> <div> <span>{{ text }}</span> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { text: '' } }, methods: { writeText(event) { this.text = event.target.value } } }) app.mount('#app') </script> </body> </html>
არგუმენტის გადაცემა მეთოდში
რა თქმა უნდა შესაძლებელია, რომ კონკრეტულ მოვლენაზე მიმაგრებულ მეთოდს გადაეცეს არგუმენტიც. მოვიყვანოთ მაგალითი, რომელშიც გვექნება სამი სხვადასხვა ღილაკი, რომლებიც სხვადასხვა მნიშვნელობით გაზრდიან მთვლელს :<!DOCTYPE html> <html> <head> <title>addCounter</title> </head> <body> <div id="app"> <p>{{ count }}</p> <button v-on:click="addCounter(1)">+1</button> <button v-on:click="addCounter(5)">+5</button> <button v-on:click="addCounter(10)">+10</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { count: 0 } }, methods: { addCounter(number) { this.count+=number // იგივეა რაც this.count=this.count+number } } }) app.mount('#app') </script> </body> </html>
არგუმენტისა და მოვლენის ობიექტის ერთდროულად გადაცემა მეთოდში
მოვიყვანოთ მაგალითი, რომელშიც მეთოდს ერთდროულად გადავცემთ მოვლენის ობიექტსა და რიგით არგუმენტს:<!DOCTYPE html> <html> <head> <title>არგუმენტი + მოვლენის ობიექტი</title> </head> <body> <div id="app"> <button id="vaso" v-on:click="myMethod($event,'გამარჯობა')">დააჭირეთ ღილაკს</button> <p id="green">{{ msgAndId }}</p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { msgAndId: '' } }, methods: { myMethod(e,msg) { this.msgAndId = msg + ' ' // გადაცემული პარამეტრი: 'გამარჯობა' this.msgAndId += e.target.id // სამიზნე ელემენტის ანუ ღილაკის id : vaso // შედეგი: გამარჯობა vaso } } }) app.mount('#app') </script> </body> </html>
- 10. Vue მოვლენათა მოდიფიკატორები
-
Vue-ში მოვლენათა მოდიფიკატორები გამოიყენება მოვლენათა შემდგომი პროცესების დამუშავებისათვის, მოდიფიცირებისათვის. მოდიფიკატორები გამოიყენება
v-on დირექტივასთან ერთად. მაგალითად შეგვიძლია :
- თავიდან ავიცილოთ HTML ფორმის გაგზაცნა ღილაკზე დაჭერისას (v-on:submit.prevent)
- დავრწმუნდეთ, რომ მოვლენა მხოლოდ ერთხელ დაფიქსირდება მას შემდეგ რაც გვერდი ჩაიტვირთება (v-on:click.once)
- განვსზაღვროთ თუ რომელ კლავიშზე დაჭერისას უნდა გავუშვათ კონკრეტული მეთოდი (v-on:keyup.enter)
ახლა კი მოვიყვანოთ კონკრეტული მაგალითი, ღილაკს მივამაგროთ ფუნქცია, რომელიც გვაჩვენებს შეტყობინებას, ღილაკზე მაუსის მხოლოდ პირველი დაჭერისას :<!DOCTYPE html> <html> <head> <title>შეტყობინება</title> </head> <body> <div id="app"> <button v-on:click.once="createAlert">Create Alert</button> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert() { alert("შეტყობინება") } } }) app.mount('#app') </script> </body> </html>
კლავიატურის მოვლენათა მოდიფიკატორები
კლავიატურის მოვლენებია : keydown, keypress და keyup. თითოეულ მათგანთან მიმართებაში შესაძებელია განვსაზღვროთ კონკრეტულად რომელ კლავიშზე დაჭერის დამუშავება გვსურს. მაგალითად : .space, .enter, .w, .up და ა.შ.მიმდინარე კლავიშის დასადგენად უნდა მივმართოთ მოვლენის ობიექტის key თვისებას :
<!DOCTYPE html> <html> <head> <title>Key</title> </head> <body> <div id="app"> <input type="text" v-on:keydown="getKey"> <p>{{ keyValue }}</p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { keyValue: '' } }, methods: { getKey(e) { this.keyValue = e.key console.log(e.key) } } }) app.mount('#app') </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>S</title> </head> <body> <div id="app"> <textarea v-on:keydown.s="createAlert"></textarea> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert() { alert("თქვენ დააჭირეთ S ღილაკს"); } } }) app.mount('#app') </script> </body> </html>
კლავიატურის მოვლენათა კომბინირებული მოდიფიკატორები
შესაძლებელია კლავიშთა კომბინაციების დაფიქსირებაც, მაგალითისათვის გამოვიძახოთ 'createAlert' ფუნქცია, როდესაც მომხმარებელი დააწვება Ctrl და S კლავიშებს :<!DOCTYPE html> <html> <head> <title>Ctrl + S</title> </head> <body> <div id="app"> <textarea v-on:keydown.ctrl.s="createAlert"></textarea> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert(evt) { alert("თქვენ აკრიფეთ 'Ctrl + S' კომბინაცია") } } }) app.mount('#app') </script> </body> </html>
მაუსის მოვლენათა მოდიფიკატორები
როგორც ვიცით მაუსის მოვლენებთან სამუშაოდ გამოიყენება v-on:click დირექტივა, მოდიფიკატორები : .left, .center და .right კი გამოიყენება იმის მიხედევით თუ მაუსის რომელ ღილაკს დააწვება მომხმარებელი.მოვიყვანოთ მაგალითი : თუ მომხმარებელი კონკრეტულ ელემენტზე დააწვება მარჯვენა მაუსს, გამოვიტანოთ შეტყობინება :
<!DOCTYPE html> <html> <head> <title>მარჯვენა მაუსი</title> <style> #app > div { width: 160px; padding: 20px; cursor: default; font-weight: bold; border: black dashed 1px; } </style> </head> <body> <div id="app"> <div v-on:click.right="createAlert"> <p>დააჭირეთ მარჯვენა მაუსს აქ</p> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert() { alert('შეტყობინება') } } }) app.mount('#app') </script> </body> </html>
როგორც ვიცით, მარჯვენა მაუსსე დაჭერისას ოპერაციულ სისტემას, ნაგულისმეობის პრინციპით გამოაქვს ჩამოსაშლელი მენიუ, თუ ამ მენიუს დამალვა გვსურს, უნდა გამოვიყენოთ .prevent მოდიფიკატორი:
<!DOCTYPE html> <html> <head> <title>მარჯვენა მაუსი</title> <style> #app > div { width: 160px; padding: 20px; cursor: default; font-weight: bold; border: black dashed 1px; } </style> </head> <body> <div id="app"> <div v-on:click.right.prevent="createAlert"> <p>დააჭირეთ მარჯვენა მაუსს აქ</p> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert() { alert('შეტყობინება') } } }) app.mount('#app') </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>Ctrl და მარჯვენა მაუსი</title> <style> #app > div { width: 160px; padding: 20px; cursor: default; font-weight: bold; border: black dashed 1px; } </style> </head> <body> <div id="app"> <div v-on:click.right.ctrl="createAlert"> <p>დააჭირეთ Ctrl ღილაკსა და მარჯვენა მაუსს აქ</p> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ methods: { createAlert() { alert('შეტყობინება'); } } }) app.mount('#app') </script> </body> </html>
- 11. Vue ფორმები
-
შევეცადოთ შევქმნათ საყიდლების სიაში პროდუქტის დასამატებელი მარტივი ფორმა. დავიწყოთ სტანდარტული HTML ფორმით :
<form> <p>პროდუქტი: <input type="text" required></p> <p>რაოდენობა: <input type="number"></p> <button type="submit">დამატება</button> </form>
<div id="app"> <form> <p>პროდუქტი: <input type="text" required v-model="itemName"></p> <p>რაოდენობა: <input type="number" v-model="itemNumber"></p> <button type="submit">დამატება</button> </form> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { itemName: null, itemNumber: null, shoppingList: [ { name: 'პური', number: 5 } ] } } }) app.mount('#app') </script>
<form v-on:submit.prevent="addItem">
methods: { addItem() { let item = { name: this.itemName, number: this.itemNumber } this.shoppingList.push(item); this.itemName = null this.itemNumber = null } }
<ul> <li v-for="item in shoppingList">{{item.name}}, {{item.number}}</li> </ul>
<!DOCTYPE html> <html> <head> <title>საყიდლების სია</title> </head> <body> <div id="app"> <form v-on:submit.prevent="addItem"> <p>პროდუქტი: <input type="text" required v-model="itemName"></p> <p>რაოდენობა: <input type="number" v-model="itemNumber"></p> <button type="submit">დამატება</button> </form> <ul> <li v-for="item in shoppingList">{{item.name}}, {{item.number}}</li> </ul> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { itemName: null, itemNumber: null, shoppingList: [ { name: 'პური', number: 5 } ] } }, methods: { addItem() { let item = { name: this.itemName, number: this.itemNumber } this.shoppingList.push(item); this.itemName = null this.itemNumber = null } } }) app.mount('#app') </script> </body> </html>
- 12. Vue v-model დირექტივა
-
v-model ამყარებს კავშირს HTML ფორმის ველების value ატრიბუტების მნიშვნელობებსა (ანუ რაც არის აკრეფილი ველებში) და Vue-ს ინსტანციაში აღწერილ ინფორმაციას შორის.
როდესაც ველებში აკრეფილი შიგთავსი იცვლება, იცვლება ინსტამციაში აღწერილი მნიშვნელობებიც და პირიქით.
<!DOCTYPE html> <html> <head> <title>Two-way Binding</title> </head> <body> <div id="app"> <input type="text" v-model="inpText"> <p id="text">inpText value: "{{ inpText }}" </p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { inpText: 'საწყისი ტექსტი' } } }) app.mount('#app') </script> </body> </html>
დინამიური checkbox ველი
საყიდლების სიის ფორმას დავამატოთ დინამიური checkbox ველი, რომელიც განსაზღვრავს პრიორიტეტულია თუ არა კონკრეტული პროდუქტის ყიდვა ჩვენი სიიდან.<!DOCTYPE html> <html> <head> <title>საყიდლების სია</title> <style> #app { border: dashed black 1px; display: inline-block; padding: 0 20px; } ul { list-style-type: none; } li { border-radius: 5px; padding: 5px; margin: 2px; background-color: rgb(211, 254, 211); } .impClass { background-color: rgb(255, 202, 202); font-weight: bold; } </style> </head> <body> <div id="app"> <form v-on:submit.prevent="addItem"> <p>პროდუქტი: <input type="text" required v-model="itemName"></p> <p>რაოდენობა: <input type="number" v-model="itemNumber"></p> <p> პრიორიტეტულია ? <label> <input type="checkbox" v-model="itemImportant"> {{ itemImportant }} </label> </p> <button type="submit">დამატება</button> </form> <ul> <li v-for="item in shoppingList" v-bind:class="{ impClass: item.important }"> {{item.name}}, {{item.number}} </li> </ul> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { itemName: null, itemNumber: null, itemImportant: false, shoppingList: [ { name: 'პური', number: 5, important: false } ] } }, methods: { addItem() { let item = { name: this.itemName, number: this.itemNumber, important: this.itemImportant } this.shoppingList.push(item) this.itemName = null this.itemNumber = null this.itemImportant = false } } }) app.mount('#app') </script> </body> </html>
ასევე აღვწერეთ დინამიური checkbox ველი, რომელიც დაკავშირებულია Vue-ს ინსტანციაში აღწერილ itemImportant თვისებასთან.
საყიდლების სიას დავამატოთ შემდეგი ფუნქციონალი : თუ მომხმარებელი შეიძენს რომელიმე პროდუქტს, შეეძლოს მისი შეძენილად მონიშვნა და შეძენილების სიაში გადატანა ამ პროდუქტზე მაუსის დაჭერით. შეძენილი პროდუქტები ჩაიყაროს შეძენილების სიაში, ხოლო ის პროდუქტი, რომელიც ჯერ არ შეუძენია დარჩეს საყიდლების სიაში.ორივე სიაში პროდუქტი გამოჩნდება ისევ v-show დირექტივის მიხედვით, რომელიც დამოკიდებული იქნება პროდუქტის ახალი თვისების - found-ის მნიშვნელობაზე:
<!DOCTYPE html> <html> <head> <title>საყიდლების სია</title> <style> #app { border: dashed black 1px; display: inline-block; padding: 0 20px; } ul { list-style-type: none; } li { margin: 2px; background-color: rgb(211, 254, 211); } .impClass { background-color: rgb(255, 202, 202); } #ulFound li { text-decoration: line-through; background-color: rgb(230,230,230); } </style> </head> <body> <div id="app"> <form v-on:submit.prevent="addItem"> <p>პროდუქტი: <input type="text" required v-model="itemName"></p> <p>რაოდენობა: <input type="number" v-model="itemNumber"></p> <p> პრიორიტეტულია ? <label> <input type="checkbox" v-model="itemImportant"> {{ itemImportant }} </label> </p> <button type="submit">დამატება</button> </form> <ul id="ulToFind"> <li v-for="item in shoppingList" v-bind:class="{ impClass: item.important }" v-on:click="item.found=!item.found" v-show="!item.found" > {{ item.name }}, {{ item.number}} </li> </ul> <ul id="ulFound"> <li v-for="item in shoppingList" v-bind:class="{ impClass: item.important }" v-on:click="item.found=!item.found" v-show="item.found" > {{ item.name }}, {{ item.number}} </li> </ul> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { itemName: null, itemNumber: null, itemImportant: false, shoppingList: [ { name: 'პური', number: 5, important: false, found: true }, { name: 'ყველი', number: 5, important: true, found: false }, { name: 'ქარაქი', number: 5, important: false , found: false } ] } }, methods: { addItem() { let item = { name: this.itemName, number: this.itemNumber, important: this.itemImportant, found: false } this.shoppingList.push(item) this.itemName = null this.itemNumber = null this.itemImportant = false } } }) app.mount('#app') </script> </body> </html>
<!DOCTYPE html> <html> <head> <title>შეკვეთა მენიუდან</title> </head> <body> <div id="app"> <!-- ღილაკზე დაჭერისას არ ვახდენთ გვერდის ხელახლა ჩატვირთვას, ვიძახებთ Vue-ს ინსტანციაში აღწერილ addItem მეთოდს --> <form v-on:submit.prevent="addItem"> <!-- პროდუქტის ტიპები, რომლებიც უკავშირდებიან Vue-ს ინსტანციაში აღწერილ itemType თვისებას, რომელიც თავდაპირველად არის ცარიელი, შესაბამისად, გვერდის ჩატვირთვისას select ჩამოსაშლელი მენიუც არ ჩანს --> <p> <h4>შეუკვეთეთ:</h4> <label> <input type="radio" required value="Dinner" v-model="itemType">სადილი </label><br> <label> <input type="radio" required value="Drink" v-model="itemType">სასმელი </label><br> <label> <input type="radio" required value="Dessert" v-model="itemType">დესერტი </label> </p> <!-- გამოჩნდება მას შემდეგ რაც მომხმარებელი აირჩევს პროდუქტის ტიპს --> <p v-show="itemType"> <label> <!-- პროდუქტის დასახელება, უკავშირდება Vue-ს ინსტანციაში აღწერილ itemName თვისებას --> <select required v-model="itemName"> <option value="" selected disabled>აირჩიეთ პროდუქტი</option> <!-- გენერირდება Vue-ს ინსტანციაში აღწერილი, წინასწარგანსაზღვრული preDefItems მასივის მიხედვით. მიმდინარე option ჩნდება იმ შემთხვევაში თუ პროდუქტის ტიპი უდრის მომხმარებლის მიერ არჩეულ პროდუქტის ტიპს --> <option v-for="item in preDefItems" v-bind:value="item.name" v-show="item.type===itemType"> {{ item.name }} </option> </select> </label> </p> <!-- ჩნდება იმ შემთხვევაში თუ მომხმარებელი ირჩევს პროდუქტს, უკავშირდება Vue-ს ინსტანციაში აღწერილ itemNumber თვისებას --> <p v-show="itemName"> <input type="number" placeholder="რაოდენობა" v-model="itemNumber" required> </p> <button type="submit">შეკვეთა</button> </form> <br> <hr> <div> <h4>თქვენი შეკვეთა:</h4> <!-- შეკვეთილი პროდუქტის სია, გენერირდება იმ შემთხვევაში თუ მომხმარებელი ერთ პროდუქტს მაინც შეუკვეთავს. გენერირდება Vue-ს ინსტანციაში აღწერილი order მასივის მიხედვით, რომელიც დავდაპირველად ცარიელია, შესაბამისად - გვერდის ჩატვირთვისას ეს სია არ ჩანს --> <ul> <li v-for="item in order"> {{ item.name }}, {{ item.number}} </li> </ul> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { itemType: '', // პროდუქტის ტიპი itemName: '', // პროდუქტის დასახელება itemNumber: null, // პროდუქტის პროდუქტის რაოდენობა // პროდუქტის სრული სია preDefItems: [ { name: 'ხაჭაპური', type: 'Dinner' }, { name: 'წვნიანი', type: 'Dinner' }, { name: 'თევზი', type: 'Dinner' }, { name: 'ნამცხვარი', type: 'Dessert' }, { name: 'კოკა-კოლა', type: 'Drink' }, { name: 'ვისკი', type: 'Drink' }, { name: 'ნაყინი', type: 'Dessert' }, { name: 'ლიმონათი', type: 'Drink' }, { name: 'წყალი', type: 'Drink' } ], order: [] // შეკვეთილი პროდუქტი } }, methods: { // კონკრეტული პროდუქტის შეკვეთა addItem(){ let item = { name: this.itemName, number: this.itemNumber, } this.order.push(item) this.itemType = '' this.itemName = '' this.itemNumber = null } } }) app.mount('#app') </script> </body> </html>
- 13. Vue CSS მიმაგრება
-
Vue-ში ელემენტებისათვის სტილების მინიჭებისა და შესაბამისად იერსახის ცვლილების რამოდენიმე გზა არსებობს.
ხაზსშიდა სტილები (inline styles)
ხაზსშიდა სტილების განსასაზღვრავად გამოიყენება v-bind:style დირექტივა :<!DOCTYPE html> <html> <head> <title>Opacity v-bind</title> <style> #app > div { position: relative; border: dashed black 1px; width: 200px; height: 100px; } #onTop { position: absolute; top: 0; left: 0; width: 100%; height: 100%; padding: 20px; box-sizing: border-box; z-index: 2; color: white; } </style> </head> <body> <div id="app"> <p> <input type="range" min="0" max="1" step="0.1" v-model="opacityVal"> {{ opacityVal }} (opacity) </p> <div> <!-- შევნიშნოთ რომ background-color თვისება ჩაწერილია ე.წ camelCase სტილში და არა სტანდარტულად --> <div id="onTop" v-bind:style="{ backgroundColor: 'rgba(99,0,89,' + opacityVal + ')' }"> </div> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { opacityVal: 0.8 } } }) app.mount('#app') </script> </body> </html>
კლასების მინიჭება
ელემენტებზე კლასების მისანიჭებლად გამოიყენება v-bind:class დირექტივა :<!DOCTYPE html> <html> <head> <title>Select images</title> <style> #app { display: flex; flex-wrap: wrap; justify-content: space-around; border: dashed black 1px; } #app > div { display: block; flex-basis: 80px; aspect-ratio: 1; margin: 5px; border: 1px solid grey; } #app > div > div { box-sizing: border-box; width: 100%; height: 100%; padding: 3px; border: solid white 4px; cursor: pointer; display: flex; justify-content: center; align-items: center; } .selClass { border: solid brown 4px; background-color: lightpink; } </style> </head> <body> <div id="app"> <div v-for="(box, index) in boxes"> <!-- selClass მიენიჭება იმ შემთხვევაში თუ მიმდინარე box-ის sale ატრიბუტის მნიშვნელობა იქნება true --> <div v-on:click="select(index)" v-bind:class="{selClass: box.sel}"> {{ box.title }} </div> </div> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { boxes: [ {title: '1', sel: false}, {title: '2', sel: false}, {title: '3', sel: false}, {title: '4', sel: false}, {title: '5', sel: false}, {title: '6', sel: false}, ] } }, methods: { select(number) { <!-- ინდექტის მიხედვით ნაპოვნ box-ს ელემენტს sel ატრიბუტის მნიშვნელობა შევუცვალოთ ასრსებულის საპირისპიროთი --> this.boxes[number].sel = !this.boxes[number].sel } } }) app.mount('#app') </script> </body> </html>
კლასებისა და სტილების მინიჭების სხვა მეთოდები
- როდესაც HTML ელემენტზე მიმაგრებულია კლასი class="" ჩანაწერითაც და v-bind:class="" დირექტივითაც, Vue ახდენს ამ კლასების შერწყმას.
- v-bind:class="{}" დირექტივის ობიექტში შესაძლებელია რამდენიმე კლასის ერთდროულად მითითება.
- ხაზსშიდა სტილებში CSS თვისების მითითებისას ჩვენ გამოვიყენეთ ე.წ 'camelCase', თუმცა შესაძლებელია ე.წ 'kebab-case' სტილის გამოყენებაც თუ თვისების დასახელებას მოვაქცევთ ბრჭყალებში.
- კლასების მითითება შესაძლებელია მასივების მეშვეობითაც.
'class' და 'v-bind:class' ჩანაწერების შერწყმა
<div class="impClass" v-bind:class="{yelClass: isYellow}"> ამ ელემენტს ექნება ორივე კლასი - 'impClass' და 'yelClass' </div>
რამოდენიმე კლასის ერთდროულად მინიჭება v-bind:class დირექტივით
<div v-bind:class="{yelClass: isYellow, impClass: isImportant}"> ამ ელემენტს ექნება ორივე კლასი - 'impClass' და 'yelClass' </div>
camelCase vs kebab-case
<div v-bind:style="{ backgroundColor: 'lightpink', 'font-weight': 'bolder' }"> ელემენტს ექნება ვარდისფერი ფონი და მუქი ტექსტი. </div>
მასივები v-bind:class დირექტივაში
<div v-bind:class="[{ impClass: isImportant }, 'yelClass' ]"> </div>
- 14. Vue გამოთვლადი თვისებები
-
გამოთვლადი თვისებები წააგავნან იმ თვისებებს, რომლებსაც აქამდე Vue-ს ინსტანციის 'data' თვისებაში ვწერდით, განსხვავება ისაა, რომ მათი მნიშვნელობა
დამოკიდებულია სხვა თვისებებზე.
გამოთვლადი თვისებების აღწერა ხდება მეთოდების მსგავსად, უბრალოდ მათ არ გადაეცემათ HTML ფორმის ველებიდან მიღებული მნიშვნელობები.
გამოთვლადი თვისების დადებითი მხარე არის ის, რომ იგი დინამიურია ანუ ავტომატურად იცვლება იმ თვისებების ცვლილებისას, რომლებზეც თავად ეს გამოთვლადი თვისებაა დამოკიდებული.
გამოთვლადი თვისებების აღწერა ხდება Vue-ს ინსტანციის computed კონფიგურაციულ პარამეტრში :const app = Vue.createApp({ data() { ... }, computed: { ... }, methods: { ... } })
<!DOCTYPE html> <html> <head> <title>ამინდი</title> </head> <body> <div id="app"> <form> <p> კარგი ამინდია ? <label> <input type="checkbox" v-model="chbxVal"> {{ isGoodWeather }} </label> </p> </form> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { chbxVal: false } }, computed: { isGoodWeather() { if(this.chbxVal){ return 'დიახ' } else { return 'არა' } } } }) app.mount('#app') </script> </body> </html>
- 15. Vue დამკვირვებლები
-
დამკვირვებლების გამოყენება მოსახერხებელია მაშინ, როდესაც გვსურს თვალი ვადევნოთ Vue-ს ინსტანციაში აღწერილი პარამეტრების ცვლილებას.
დამკვირვებლების აღწერა ხდება Vue-ს ინსტანციის watch კონფიგურაციულ პარამეტრში :
const app = Vue.createApp({ data() { ... }, watch: { ... }, computed: { ... }, methods: { ... } })
<!DOCTYPE html> <html> <head> <title>დამკვირვებელი</title> </head> <body> <div id="app"> <input type="range" min="0" max="100" step="1" v-model="rangeVal"> <p>{{ rangeVal }}</p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { rangeVal: 0 } }, watch: { rangeVal(val) { if( val > 20 ){ alert('შეტყობინება') } } } }) app.mount('#app') </script> </body> </html>
დამკვირვებლები ძველი და ახალი მნიშვნელობებით
დამკვირვებელის მეშვეობით შესაძლებელია მომხმარებლის მიერ აკრეფილი ახალი და ძველი მნიშვნელობების დაჭერაც:<!DOCTYPE html> <html> <head> <title>ძველი და ახალი მნიშვნელობები</title> </head> <body> <div id="app"> <label> <input type="email" v-model="inpAddress"> </label> <p>{{ feedbackText }}</p> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ data() { return { inpAddress: '', feedbackText: '' } }, watch: { inpAddress(newVal,oldVal) { if(!newVal.includes('@')){ this.feedbackText = 'არასწორი ელ_ფოსტა'; } else if(!oldVal.includes('@') && newVal.includes('@')) { this.feedbackText = 'კიბატონო, ძაღლუკა უკვე გვყავს ^_^'; } else { this.feedbackText = 'ელ_ფოსტის მისამართი სწორია'; } } } }) app.mount('#app') </script> </body> </html>
დამკვირვებლები vs გამოთვლადი თვისებები
- მეთოდების გამოძახება ხდება HTML ფორმიდან.
- მეთოდი შეიძლება გამოძახებულ იქნას მაშინაც როცა დაფიქსირდება კონკრეტული მოვლენა.
- მეთოდს ავტომატურად გადაეცემა მოვლენის ობიექტი.
- მეთოდს შეგვიძლია გადავცეთ დამატებითი პარამეტრებიც.
- დამკვირვებლის გამოძახება ხდება მხოლოდ მაშინ, როდესაც იცვლება ის ინფორმაცია რომელსაც ეს კონკრეტული დამკვირვებელი აკვირდება.
- დამკვირვებლები ავტომატურად იღებენ დაკვირვების ობიექტის ახალ და ძველ მნიშვნელობებს.
- ჩვენ არ შეგვიძლია გადავცეთ დაკვირვების ობიექტს რაიმე დამატებითი არგუმენტები გარდა დაკვირვების ობიექტის ახალი და ძველი მნიშვნელობებისა.
დამკვირვებლები vs მეთოდები
- დამკვირვებლის მუშაობა დამოკიდებულია მხოლოდ ერთ კონკრეტულ თვისებაზე.
- გამოთვლადი თვისება შეიძლება დამოკიდებული იყოს რამოდენიმე თვისებაზე.
- 16. Vue შაბლონები
-
Vue-ში შაბლონი ეწოდება აპლიკაციის იმ ნაწილს, რომელშიც HTML-ია აღწერილი. შემდეგ თავებში ვნახავთ, რომ შაბლონებთან სამუშაოდ გამოიყენება
<template> ტეგი. შაბლონი გვეხმარება კოდის სტრუქტურის უკეთესად გამართვაში.
შაბლონის აღწერა ხდება Vue-ს ინსტანციის template კონფიგურაციულ პარამეტრში, შაბლონის შიგთავსი უნდა ჩაისვას `` ბრჭყალებში :
<!DOCTYPE html> <html> <head> <title>შაბლონი</title> </head> <body> <div id="app"></div> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <script> const app = Vue.createApp({ template: `<h1>{{ message }}</h1> <p>HTML შაბლონის მეორე ხაზი</p>`, data() { return { message: "გამარჯობა!" } } }) app.mount('#app') </script> </body> </html>
- 17. *.vue გაფართოების ფაილები
-
*.vue გაფართოების ფაილების გამოყენებას აქვს შემეგი უპირატესობები :
- დიდ პროექტებზე მუშაობისას, ის სქემა, რომლითაც აქამდე ვმუშაობდით, საკმაოდ მოუხერხებელია, უფრო მეტიც - შეუძლებელია ამგვარად მუშაობა. ასეთ პროეტებში დაგვჭირდება შაბლონებისა და კომპონენტების გამოყენება.
- ბრაუზერში გვერდის შიგთავსი ავტომატურად განახლდება მას შემდეგ, რაც ედიტორში შევინახავთ ბოლო ცვლილებებს.
- დღესდღეობით ეს მიდგომაა ყველაზე რეკომენდებული და მიზანშეწონილი, ასე ვთქვათ - თანამედროვე სტანდარტი.
Vite არის ერთგვარი ხელსაწყო, ინსტრუმენტი, რომლის მეშვეობითაც ხდება საბაზისო შაბლონისა და სამუშაო გარემოს გამზადება სამომხმარებლო მხარის (front-end) ფრეიმვორკებსა და ბიბლიოთეკებთან მუშაობისას.1. ედიტორის ინსტალაცია
არსებობს ბევრი სხვადასხვა ედიტორი, თუმცა რეკომენდებულია გამოვიყენოთ VS Code ედიტორი.2. Volar გაფართოება
VS Code ედიტორთან მუშაობისას სასურველია დავაყენოთ Volar გაფართოება, რომელიც Vue-ში მუშაობას ხდის უფრო კომფორტულს.
3. Node.js
Node ანუ Node.js — არის V8 (ავტ. Google) ძრავზე დაფუძნებული პროგრამული პლატფორმა, რომელიც JavaScript-ს, როგორც სპეციალიზირებულ ენას, გარდაქმნის პროგრამირების სრულფასოვან და საერთო დანიშნულების ენად. ამ პლატფორმაზე დაყრდნობით ჯს შეგვიძლია გამოვიყენოთ სერვერული მხარის სამუშაოებშიც.Node.js ის გადმოწერა შესაძლებელია ოფიციალური ვებ-გვერდიდან. ინსტალაცია მიმდინარეობს სტანდარტულად, ყოველგვარი სირთულეების გარეშე. იმისათვის რათა დავრწმუნდეთ, რომ ინსტალაციამ წარმატებით ჩაიარა, ბრძანებათა ველიდან (CMD) გავუშვათ შემდეგი ბრძანება :node -v
4. გადავინაცვლოთ სასურველ საქაღალდეში და გავუშვათ შემდეგი ბრძანება :
npm init vue@latest
npm - Node.js Package Manager ანუ Node.js პაკეტების მენეჯერი. პაკეტის მიღმა იგულისხმება იმ ფაილების ნაკრებები, რომლებიც გვჭირდება კონკრეტული მოდულის შესაქმნელად.npm-ის ვერსიის გასაგებად ბრძანებათა ველიდან გავუშვათ შემდეგი ბრძანება :npm -v
დავაჭიროთ 'enter' ღილაკს შემდეგ ავკრიფოთ ჩვენი პირველი პროექტის დასახელება - firstsfc, ისევ დავაჭიროთ 'enter' ღილაკს.5. ყველგან მივუთითოთ პასუხი 'No' :
ამის შემდეგ თანმიმდევრობით გავუშვათ შემდეგი ბრძანებები :cd firstsfc
npm install
npm run dev
პროექტის სტრუქტურა
პროექტის საწყისი სტრუქტურა იქნება ამდაგვარი :
main.js
main.js ფაილის მეშვეობით Vite გებულობს თუ როგორ დააგენერიროს პროექტი App.vue ფაილზე დაყრდნობით. ეს დაახლოებით იგივეა, როდესაც ჩვენ CDN ბმულით ვატყობინებდით ბრაუზერს თუ როგორ გაეშვა ჩვენი Vue კოდი და თუ როგორ შეექმნა Vue-ს ინსტანცია <div id="app"> ელემენტზე დაფუძნებით.App.vue
ყველა სხვა *.vue ფაილის მსგავსად ეს ფაილიც შედგება სამი ნაწილისაგან : <script>, <template> და <style>. თითოეულ მათგანს ოდნავ მოგვიანებით განვიხილავთ უფრო დაწვრილებით.<script setup> import HelloWorld from './components/HelloWorld.vue' import TheWelcome from './components/TheWelcome.vue' </script> <template> <header> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> <div class="wrapper"> <HelloWorld msg="You did it!" /> </div> </header> <main> <TheWelcome /> </main> </template> <style scoped> header { line-height: 1.5; } .logo { display: block; margin: 0 auto 2rem; } @media (min-width: 1024px) { header { display: flex; place-items: center; padding-right: calc(var(--section-gap) / 2); } .logo { margin: 0 2rem 0 0; } header .wrapper { display: flex; place-items: flex-start; flex-wrap: wrap; } } </style>
'<template>' სექციას თუ დავაკვირდებით შევამჩნევთ <HelloWorld> and <TheWelcome> ტეგებს, რომლებიც სტანდარტული HTML ტეგები არ არიან, სწოერდ ამგვარად ხდება კომპონენტების გამოძახება. მარტივი ენით თუ ვიტყვით - კომპონენტი ეს არის აპლიკაცია აპლიკაციაში, კომპონენტების შესახებ ვისაუბრებთ შემდეგ თავებში.
მაშ ასე, შევუდგეთ საქმეს :) ყველაფერი დავიწყოთ სუფთა ფურცლიდან - პირველ რიგში გავასუფთავოთ main.js ფაილი და მივცეთ ამდაგვარი სახე :import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
<template> <h1>გამარჯობა !</h1> </template> <script></script> <style></style>
ოდნავ გავართულოთ ჩვენი კოდი, App.vue :
<template> <h1>{{ message }}</h1> </template> <script> export default { data() { return{ message: 'ახალი ტექსტი' } } } </script> <style></style>
import App from './App.vue'
- 18. Vue კომპონენტები
-
უვხო სიტყვათა ლექსიკონი : კომპონენტი - რისამე შემადგენელი ნაწილი.ნებისმიერი ვებ-საიტი შეიძლება განხილულ იქნას, როგორც კონკრეტული ფუნქციონალების, ფრაგმენტების, კომპონენტების ერთობლიობა. კომპონენტის უკან შეიძლება მოიაზრებოდეს მაგალითად საიტის ქუდი (header), პროდუქტის ჩამონათვალის გვერდი და ა.შ. რა თქმა უნდა საჭიროა, რომ სადღაც აღიწეროს კონკრეტული ინსტრუქციები, კონკრეტული ლოგიკა, რომელიც დააგენერირებს საჭირო შიგთავსს, ზემოთ ჩამოთვლილი თითოეული ფრაგმენტისათვის.
კომპონენტები ემსახურებიან სამომხმარებლო ინტერფეისის პატარა ფრაგმენტებად დაყოფას. თითოეულ კომპონენტს აქვს თავისი დამოუკიდებელი თვისებები (props), ინსტრუქციები, შაბლონები და ა,შ. კონკრეტული კომპონენტის ცვლილებისას პროექტის დანარჩენ ნაწილს საერთოდ არ ვეხებით, ეს კი საკმაოდ მოსახერხებელი და კომფორტულია.src საქაღალდეში შევქმნათ ქვესაქაღალდე - components, მასში კი ფაილი FoodItem.vue შემდეგი კოდით :
<template> <div> <h2>{{ name }}</h2> <p>{{ message }}</p> </div> </template> <script> export default { data() { return { name: 'ხაჭაპური', message: 'მე მიყვარს ხაჭაპური' } } }; </script> <style></style>
import { createApp } from 'vue' import App from './App.vue' import FoodItem from './components/FoodItem.vue' const app = createApp(App) app.component('food-item', FoodItem) app.mount('#app')
<template> <h1>საკვები</h1> <food-item/> <food-item/> <food-item/> </template> <script></script> <style> #app > div { border: dashed black 1px; display: inline-block; margin: 10px; padding: 10px; background-color: lightgreen; } </style>
ინდივიდუალური კომპონენტები
Vue-ს კომპონენტებთან მუშაობის ერთ-ერთი მნიშვნელოვანი უპირატესობა და დადებითი მხარე არის ის, რომ ჩვენ შეგვიძლია თითოეულ კომპონენტს მოვექცეთ, როგორც ინდივიდუალურ კომპონენტს და თანაც ისე, რომ, სტანდარტული ჯავასკრიპტისაგან განსხვავებით, კომპონენტებისათვის უნიკალური იდენტიფიკატორის (id) მინიჭება არ დაგვჭირდება, Vue ავტომატურად იზრუნებს ამაზე ^_^ჩვენს კომპონენტს დავამატოთ მთვლელი, რომელიც დათვლის თუ რამდენჯერ დავაჭერთ მაუსს თითოეულ კომპონენტს, App.vue :
<template> <div v-on:click="countClicks"> <h2>{{ name }}</h2> <p>{{ message }}</p> <p>დააჭირეთ {{ clicks }} - ჯერ</p> </div> </template> <script> export default { data() { return { name: 'ხაჭაპური', message: 'მე მიყვარს ხაჭაპური', clicks: 0 } }, methods: { countClicks() { this.clicks++; } } }; </script> <style> #red { font-weight: bold; color: rgb(144, 12, 12); } </style>
- 19. Vue რეკვიზიტები (props)
-
ინგ : props - რეკვიზიტირეკვიზიტების მეშვეობით შესაძლებელია კომპონენტების ტეგებს მივამაგროთ ინფორაცია სამომხმარებლო, ანუ არასტანდარტული ატრიბუტებით (custom attributes).
უვხ. სიტყ. ლექს. : რეკვიზიტი - თეატრ. ნივთები, რომლებიც სჭირდებათ მსახიობებს წარმოდგენის მსვლელობის დროს :))როგორც გვახსოვს შვქმენით <food-item/> კომპონენტი, რომელსაც სამჯერ ვიყენებდით App.vue ფაილში, შესაბამისად - ბრაუზერშიც გენერირდებოდა სამი ელემენტი, სამივე მათგანში ხაჭაპურს მივირთმევდით :)) მოდით გავამრავალფეროვნოთ მენიუ :))
შევქმნათ საკუთარი food-name ატრიბუტი, რომლის მეშვეობითაც მივამაგრებთ ინფორმაციას <food-item/> კომპონენტს, App.vue :
<template> <h1>Food</h1> <food-item food-name="ხაჭაპური"/> <food-item food-name="ნამცხვარი"/> <food-item food-name="პიცა"/> </template> <script></script> <style> #app > div { border: dashed black 1px; display: inline-block; width: 120px; margin: 10px; padding: 10px; background-color: lightgreen; } </style>
რეკვიზიტების მიღება კომპონენტში
იმისათვის რათა კომპონენტში დავამუშავოთ რეკვიზიტით გამოგზავნილი ინფორმაცია, უნდა გამოვიყენოთ props კონფიგურაციული თვისება, FoodItem.vue :<template> <div> <h2>{{ foodName }}</h2> </div> </template> <script> export default { props: [ 'foodName' ] } </script> <style></style>
ლოგიკური ტიპის რეკვიზიტები
ჩვენს კომპონენტს დავამატოთ ახალი რეკვიზიტი isFavorite, რომელიც იქნება ლოგიკური ტიპის (true ან false).როდესაც ვქმნით ისეთ რეკვიზიტს, რომელიც არასტრიქონული ტიპისაა, რეკვიზიტის ატრიბუტთან ერთად უნდა გამოვიყენოთ v-bind დირექტივა, App.vue :
<template> <food-item food-name="ხაჭაპური" v-bind:is-favorite="true"/> <food-item food-name="ნამცხვარი" v-bind:is-favorite="false"/> <food-item food-name="პიცა" v-bind:is-favorite="true"/> </template> <script></script> <style> #app > div { border: dashed black 1px; display: inline-block; width: 120px; margin: 10px; padding: 10px; background-color: lightgreen; } </style>
<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="isFavorite">ფავორიტია</h3> </div> </template> <script> export default { props: [ 'foodName', 'isFavorite' ] } </script> <style></style>
<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="isFavorite">ფავორიტია</h3> </div> </template> <script> export default { // props: ['foodName','isFavorite'] props: { foodName: String, isFavorite: Boolean } } </script> <style></style>
აუცილებელი რეკვიზიტები
იმისათვის რათა Vue-მ გაიგოს კონკრეტული რეკვიზიტი არის თუ არა აუცილებელი, მოვიქცეთ ასე, FoodItem.vue<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="isFavorite">ფავორიტია</h3> </div> </template> <script> export default { // props: ['foodName','isFavorite'] props: { foodName: { type: String, required: true }, isFavorite: Boolean } } </script> <style></style>
რეკვიზიტების ნაგულისმები მნიშვნელობები
App.vue ფაილში გამოძახებულ ერთ-ერთ კომპონენტს, მაგილთად ნამცხვარს, წავუშალოთ is-favorite რეკვიზიტი :<template> <food-item food-name="ხაჭაპური"v-bind:is-favorite="true"/> <food-item food-name="ნამცხვარი"/> <food-item food-name="პიცა" v-bind:is-favorite="true"/> </template> <script></script> <style> #app > div { border: dashed black 1px; display: inline-block; width: 120px; margin: 10px; padding: 10px; background-color: lightgreen; } </style>
<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="isFavorite">ფავორიტია</h3> </div> </template> <script> export default { // props: ['foodName','isFavorite'] props: { foodName: { type: String, required: true }, isFavorite: { type: Boolean, required: false, default: true } } } </script> <style></style>
რეკვიზიტთა ვალიდაციის ფუნქცია
შესაძლებელია რეკვიზიტთა ვალიდაციის ფუნქციის აღწერაც, რომელიც დაადგენს ვალიდურია თუ არა ესა თუ ის რეკვიზიტი. ასეთმა ფუნქციამ უნდა დააბრუნოს 'true' ან 'false' მნიშვნელობებიდან ერთ-ერთი. FoodItem.vue :<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="isFavorite">ფავორიტია</h3> </div> </template> <script> export default { // props: ['foodName','isFavorite'] props: { foodName: { type: String, required: true, validator: function(value) { if(value.length < 3) { return false; } else { return true; } } }, isFavorite: { type: Boolean, required: false, default: true } } } </script> <style></style>
რეკვიზიტთა მოდიფიცირება
როდესაც კომპონენტის გამოძახება ხდება მშობელ ელემენტში, ჩვენ არ შეგვიძლია მშობლიდან გამოგზავნილი რეკვიზიტის ცვლილება შვილობილ კომპონენტში. მაგალითად FoodItem.vue კომპონენტში ვერ შევცვლით isFavorite რეკვიზიტის იმ მნიშვნელობას, რომელიც App.vue-დან მივიღეთ. ანუ მშობლიდან გამოგზავნილი რეკვიზიტი არის მხოლოდ წაკითხვადი (read-only).დავუშვათ გვინდა, რომ მოხმარებელს მიეცეს საშუალება ღილაკის მეშვეობით გადაწყვიტოს რომელი პროდუქტია მისთვის ფავორიტი და რომელი არა. პირველი, რაც თავში გაგვიელვებს, ალბათ არის რაღაც ამდაგვარი :
methods: { toggleFavorite() { this.isFavorite = !this.isFavorite; } }
data() { return { foodIsFavorite: this.isFavorite } }
methods: { toggleFavorite() { this.foodIsFavorite = !this.foodIsFavorite; } }
<template> <div> <h2>{{ foodName }}</h2> <h3 v-show="foodIsFavorite">ფავორიტია</h3> <button v-on:click="toggleFavorite">ფავორიტი</button> </div> </template> <script> export default { props: ['foodName','isFavorite'], data() { return { foodIsFavorite: this.isFavorite // foodIsFavorite ადგილობრივია, isFavorite მშობლიდან მოვიდა } }, methods: { toggleFavorite() { this.foodIsFavorite = !this.foodIsFavorite; } } } </script> <style></style>
- 20. Vue v-for კომპონენტები
-
v-for დირექტივის მეშვეობით შესაძლებელია კომპონენტების მრავალჯერადად გამოყენება, კომპონენტების ამ გზით გენერირება საკმაოდ მოსახერხებელია,
რადგან შესაძლებლობა გვექნება თითოეულ მათგანს დინამიურად გადავცეთ რეკვიზიტები.
App.vue :
<template> <div id="wrapper"> <food-item v-for="x in foods" food-name="x" /> </div> </template> <script> export default { data() { return { foods: ['ხაჭაპური','ნამცხვარი','პიცა'] }; } } </script> <style> #wrapper { display: flex; flex-wrap: wrap; } #wrapper > div { border: dashed black 1px; margin: 10px; padding: 0 20px; background-color: lightgreen; } </style>
<template> <div> <h2>{{ foodName }}</h2> </div> </template> <script> export default { props: ['foodName'] }; </script> <style></style>
- 21. Vue $emit()
-
რეკვიზიტები გამოიყენება ინფორმაციის გასაგზავნად მშობელი ელემენტიდან შვილობილ კომპონენტში, Vue-ში ჩადგმული $emit() მეთოდი კი პირიქით -
შვილობილი კომპონენტიდან გზავნის ინფორმაციას მშობელ ელემენტში.
შემდეგი ბიჯები რასაც ახლა გავაკეთებთ, ემსახურება იმას, რომ საკვების 'favorite' სტატუსი შეიცვალოს მშობელ ელემენტ App.vue-ში და არა FoodItem.vue კომპონენტში.
ამის მიზეზი კი გახლავთ ის, რომ სწორედ App.vue ფაილია ის ადგილი სადაც 'favorite' სტატუსი პირველად ჩნდება. გასაგებია, რომ ამ ეტაპზე საკმაოდ მარტივი სქემით ვმუშაობთ, მაგრამ დიდ პროექტში შესაძლებელია App.vue-ში ინფორმაცია მონაცემთა ბაზიდან მოგვქონდეს და მოხდეს ისე, რომ დაგვჭირდეს შვილობილ კომპონენტში ჩატარებული ოპერაციების საფუძველზე ამ ინფორმაციის ბაზაში განახლებაც, რაც ბუნებრივია მოითხოვს შეგვეძლოს კომპონენტიდან მშობელ ელემენტში ინფორმაციის გაგზავნა/განახლება.
FoodItem.vue-ში არსებული toggleFavorite მეთოდი გადავაკეთოთ შემდეგნაირად :methods: { toggleFavorite() { // toggle-favorite არის სამომხმარებლო მოვლენის სახელი, რომელიც უნდა აღვწეროთ App.vue-ში this.$emit('toggle-Favorite'); } }
დავაფიქსიროთ toggle-favorite მოვლენა App.vue-ში :
<food-item v-for="x in foods" :food-name="x.name" :is-favorite="x.favorite" @toggle-favorite="receiveEmit"/>
methods: { receiveEmit() { alert('გამარჯობა !'); } }
methods: { toggleFavorite() { this.$emit('toggle-favorite', this.foodName); } }
methods: { receiveEmit(foodName) { alert( 'თქვენ აირჩიეთ: ' + foodName ); } }
methods: { receiveEmit(foodName) { // მასივში ვიპოვოთ ის ობიექტი, რომლის name ატრიბუტიც არის foodName const foundFood = this.foods.find(food => food.name === foodName); // ნაპოვნი ობიექტის favorite სტატუსი შევცვალოთ არსებულის საპირისპიროთი foundFood.favorite = !foundFood.favorite; } }
<template> <div> <h2> {{ foodName }} </h2> <p v-show="isFavorite">ფავორიტია</p> <button v-on:click="toggleFavorite">ფავორიტი</button> </div> </template> <script> export default { props: ['foodName','isFavorite'], emits: ['toggle-favorite'], // ამ კონფიგურაციული პარამეტრის დამატება ნებაყოფლობითია, უბრალოდ აადვილებს კოდის აღქმას methods: { toggleFavorite() { this.$emit('toggle-favorite', this.foodName); } } }; </script> <style> img { height: 1.5em; float: right; } </style>
- 22. Vue ლოკალური სტილები
-
კომპონენტებში ან App.vue ფაილში <style> ტეგით აღწერილი სტილები გლობალურად ვრცელდება, ანუ მოქმედებს ყველა კომპონენტში.
იმისათვის რათა კომპონენტში აღწერილმა სტილებმა მხოლოდ ლოკალურად იმუშავონ, <style> ტეგი უნდა გამოვიყენოთ scoped
ატრიბუტთან ერთად.
ინგ: scoped - გამოყენების სფერო, თვალთახედვის არე, ფარგლებიTestComponent.vue
<template> <p>ეს p ტეგი ეკუთვნის 'TestComponent.vue' კომპონენტს</p> </template> <script></script> <style scoped> p { background-color: pink; width: 150px; } </style>
- 23. Vue ლოკალური კომპონენტები
-
კომპონენტების გამოძახების ის გზა, რომელსაც აქამდე ვიყენებდით, გულისხმობს იმას, რომ ეს კომპონენტები ხელმისაწვდომია ყველა*.vue ფაილში.
ანუ შეგვიძლია თითოეული მათგანი განვიხილოთ, როგორც გლობალური კომპონენტი.
/src/components საქაღალდეში შევქმნათ სატესტო კომპონენტები CompOne.vue და CompTwo.vue
CompOne.vue
<template> <div class="compOneDiv"> <p>CompOne.vue</p> </div> </template> <script></script> <style></style>
CompTwo.vue
<template> <div class="compTwoDiv"> <p>CompTwo.vue</p> <comp-one /> </div> </template> <script></script> <style></style>
App.vue
<template> <div> <h3>გლობალური კომპონენტები</h3> <p>App.vue</p> <p>CompOne.vue კომპონენტი გამოყენებულია App.vue-შიც და CompTwo.vue-შიც</p> <comp-one /> <comp-two /> </div> </template> <script></script> <style> p { width: 200px; } #app div { border: dashed black 1px; margin: 10px; padding: 10px; display: inline-block; } .compOneDiv { background-color: lightgreen; } .compTwoDiv { background-color: lightcoral; } </style>
main.js
import { createApp } from 'vue' import App from './App.vue' import CompOne from './components/CompOne.vue' import CompTwo from './components/CompTwo.vue' const app = createApp(App) app.component('comp-one', CompOne) app.component('comp-two', CompTwo) app.mount('#app')
ლოკალური კომპონენტები
შეგვიძლია კომპონენტი გამოვიძახოთ კონკრეტული *.vue ფაილის <script> სექციაში და არა main.js ფაილში. ასეთ შემთხვევაში კომპონენტი ხელმისაწვდომი იქნება მხოლოდ ამ *.vue ფაილში და შესაბამისად იგი შეგვიძლია განვიხილოთ, როგორც ლოკალური კომპონენტი.CompOne.vue კომპონენტი ხელმისაწვდომი გავხადოთ მხოლოდ App.vue ფაილში. წავშალოთ ეს კომპონენტი main.js ფაილში :
import { createApp } from 'vue' import App from './App.vue' import CompOne from './components/CompOne.vue' import CompTwo from './components/CompTwo.vue' const app = createApp(App) app.component('comp-one', CompOne) app.component('comp-two', CompTwo) app.mount('#app')
<template> <h3>ლოკალური კომპონენტი</h3> <p>CompOne.vue ლოკალური კომპონენტია და მისი გამოყენება შეიძლება მხოლოდ App.vue-ში</p> <comp-one /> <comp-two /> </template> <script> import CompOne from './components/CompOne.vue'; export default { components: { 'comp-one': CompOne } } </script>
- 24. Vue Slots
-
Vue-ში ე.წ სლოტი არის ინსტრუმენტი, რომლის მეშვეობითაც შეგვიძლია მშობელი ელემენტიდან გადავცეთ შიგთავსი შვილობილი კომპონენტის
<template> სექციას. აქამდე კომპონენტებს <template> სექციაში ვიყენებდით თვითდამხურავი
ტეგების მეშვეობით, App.vue :
<template> <slot-comp /> </template>
<template> <slot-comp>გამარჯობა!</slot-comp> </template>
App.vue
<template> <div> <h3>Slot</h3> <p>App.vue-დან ვაგზავნით ტექსტ 'გამარჯობა!'-ს, რომელიც შეავსებს SlotComp.vue კომპონენტში არსებული slot ტეგის მიერ შექმნილ სივრცეს</p> <slot-comp>გამარჯობა!</slot-comp> </div> </template> <script></script> <style> p { width: 200px; } #app div { border: dashed black 1px; margin: 10px; padding: 10px; display: inline-block; } </style>
<template> <div> <p>SlotComp.vue</p> <slot></slot> </div> </template>
import { createApp } from 'vue' import App from './App.vue' import SlotComp from './components/SlotComp.vue' const app = createApp(App) app.component('slot-comp', SlotComp) app.mount('#app')
App.vue
<template> <div id="wrapper"> <slot-comp v-for="x in foods"> <h4>{{x.name}}</h4> <p>{{x.desc}}</p> </slot-comp> </div> </template> <script> export default { data() { return { foods: [ { name: 'ხაჭაპური', desc: 'იმერული ხაჭაპური' }, { name: 'პიცა', desc: 'იტალიური პიცა', } ] } } } </script> <style> #wrapper { display: flex; flex-wrap: wrap; } #wrapper img { display: block; margin: auto; width: 60%; } </style>
<template> <div> <slot></slot> </div> </template> <script></script> <style scoped> div { background-color: lightgreen; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); transition: 0.3s; flex-basis: 150px; border-radius: 10px; border: solid black 2px; margin: 10px; padding: 20px 10px 0 10px; } div:hover { box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); } </style>
ამ ყველაფრის შედეგს თუ დავაკვირდებით, შევამჩნევთ, რომ SlotComp.vue-ში აღწერილმა კოდმა მოგვცა ბარათის ტიპის (card) ელემენტი კონკრეტული მახასიათებლებით : ჩარჩოს სისქე და ფერი, მომრგვალებული ჩარჩო, შუქჩრდილი და ა.შ. ახლა შეგვიძლია ეს ბარათი გამოვიყენოთ იმდენჯერ და იმდენგან რამდენჯერაც დაგვჭირდება და სადაც დაგვჭირდება, ამასთანავე შესაძლებელია ბარათის შიგთავსის შეცვლა, რაც საკმაოდ მოსახერხებელია. მაგალითად დავამატოთ საიტის ძირი, რომელიც ასეთივე მონაცემების ბარათზე იქნება დაფუძნებული.App.vue
<template> <div id="wrapper"> <slot-comp v-for="x in foods"> <h4>{{x.name}}</h4> <p>{{x.desc}}</p> </slot-comp> </div> <footer> <slot-comp> <!- შეცვლილი შიგთავსი --> <h3>Footer</h3> </slot-comp> </footer> </template> <script> export default { data() { return { foods: [ { name: 'ხაჭაპური', desc: 'იმერული ხაჭაპური' }, { name: 'პიცა', desc: 'იტალიური პიცა', }, { name: 'ბრინჯი', desc: 'ჩინური ბრინჯი', } , { name: 'სუში', desc: 'იაპონური სუში', }, { name: 'ბეკონი', desc: 'ამერიკული ბეკონი', } ] } } } </script> <style> #wrapper { display: flex; flex-wrap: wrap; justify-content: space-around; } #wrapper > div { background-color: lightgreen; } footer > div { background-color: lightpink; } #wrapper img { display: block; margin: 20% auto 0; width: 60%; } h3, h4 { text-align: center; } </style>
<template> <div> <slot></slot> </div> </template> <script></script> <style scoped> div { box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); transition: 0.3s; flex-basis: 150px; border-radius: 10px; border: solid black 2px; margin: 10px; padding: 0 10px 0; } div:hover { box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2); } </style>
- 25. Vue დინამიური კომპონენტები
-
წარმოვიდგინოთ, რომ გვაქვს რამდენიმე კომპონენტი და გვჭირდება მათი გამოჩენა მონაცვლეობით, საჭიროებისამებრ. ამაში დაგვეხმარება <component> ტეგი is
ატრიბუტთან ერთად.
App.vue
<template> <h1>დინამიური კომპონენტები</h1> <button @click="toggleValue = !toggleValue">გადართეთ კომპონენტი</button> <component :is="activeComp"></component> </template> <script> export default { data () { return { toggleValue: true } }, computed: { activeComp() { if(this.toggleValue) { return 'comp-one' } else { return 'comp-two' } } } } </script> <style> #app { width: 350px; margin: 10px; } #app > div { border: solid black 2px; padding: 10px; margin-top: 10px; } </style>
CompOne.vue
<template> <div> <h2>პირველი!</h2> <p>ეს არის პირველი კომპონენტი</p> </div> </template> <script></script> <style scoped> div { background-color: lightgreen; } </style>
<template> <div> <h2>მეორე!</h2> <p>ეს არის მეორე კომპონენტი</p> </div> </template> <script></script> <style scoped> div { background-color: lightpink; } </style>
import { createApp } from 'vue' import App from './App.vue' import CompOne from './components/CompOne.vue' import CompTwo from './components/CompTwo.vue' const app = createApp(App) app.component('comp-one', CompOne) app.component('comp-two', CompTwo) app.mount('#app')
KeepAlive ტეგი
ზემოთ მოყვანილ ორივე კომპონენტში უბრალოდ ტექსტები გამოგვქონდა. წარმოვიდგინოთ, რომ ორივე მათგანში რაიმე ფორმები გვქონოდა, თუ მომხმარებელი შეავსებდა პირველ კომპონენტში არსებულ ფორმას და გადართავდა კომპონენტს, ამის შემდეგ კი ისევ პირველ კომპონენტზე დაბრუნდებოდა, შევსებული ფორმა ცარიელი დახვდებოდა. ამის თავიდან ასაცილებლად <component> ტეგი უნდა მოვაქციოთ <KeepAlive> ტეგში :<!-- დამახსოვრებულ იქნება ორივე კომპონენტის მდგომარეობა --> <KeepAlive> <component :is="activeComp"></component> </KeepAlive> <!-- დამახსოვრებულ იქნება მხოლოდ CompOne კომპონენტის მდგომარეობა --> <KeepAlive include="CompOne"> <component :is="activeComp"></component> </KeepAlive> <!-- დამახსოვრებულ იქნება მხოლოდ CompTwo კომპონენტის მდგომარეობა --> <KeepAlive exclude="CompOne"> <component :is="activeComp"></component> </KeepAlive> <!-- დამახსოვრებულ იქნება ბოლოს ნანახი ორი კომპონენტის მდგომარეობა, ჩვენს შემთხვევაში ორივე კომპონენტს დაიმახსოვრებდა ბრაუზერი, რადგან სულ ორი კომპონენტი გვაქვს --> <KeepAlive :max="2"> <component :is="activeComp"></component> </KeepAlive>
- 26. Vue HTTP მოთხოვნა
-
HTTP ანუ Hyper Text Transfer Protocol არის სერვერსა და მომხმარებლეს შორის კომუნიკაციის გზა, მექანიზმი, პროტოკოლი. მომხმარებელი
სერვერზე აგზავნის მოთხოვნას (HTTP request), სერვერიდან კი ბრუნდება შესაბამისი პასუხი (HTTP response). HTTP მოთხოვნის ყველაზე გავრცელებული ტიპებია POST, GET, PUT, PATCH
და DELETE.
fetch მეთოდი
სერვერიდან ინფორმაციის მისაღებად Vue-ში გამოიყებენა ჯავასკრიპტის ფუნქცია fetch(), რომელსაც ხშირად გამოვიყენებთ ამ თავში, თუმცა არ განვსაზღვრავთ HTTP მოთხოვნის ტიპს, რაც იმას ნიშნავს, რომ ეს მოთხოვნები ნაგულისხმეობის პრინციპით იქნება GET ტიპის.fetch() მეთოდს არგუმენტად უნდა გადაეცეს ის მისამართი, რომლიდანაც გვსურს ინფორმაციის წამოღება. მოვიყვანოთ მარტივი მაგალითი, პროექტის ძირ საქაღალდეში შევქმნათ ტექსტური ფაილი file.txt და მასში შევიტანოთ რაიმე ტექსტი :
Lorem Ipsum საბეჭდი და ტიპოგრაფიული ინდუსტრიის უშინაარსო ტექსტია. იგი სტანდარტად 1500-იანი წლებიდან იქცა.
<template> <div> <button @click="fetchData">ინფორმაციის ამოღება</button> <p v-if="data">{{ data }}</p> </div> </template> <script> export default { data() { return { data: null, }; }, methods: { fetchData() { const response = fetch("file.txt"); this.data = response; console.log(response); } } }; </script>
მაგრამ ეს ის არ არის რაც ჩვენ გვჭირდება.რა არის 'Promise' ?
მანამ, სანამ იმას გავარკვევთ, თუ რა არის promise ჯავასკრიპტში, გავიხსენოთ თუ რას ნიშნავს სინქრონული პროგრამირება და ასინქრონული პროგრამირება.წარმოვიდგინოთ, რომ გვაქვს ასეთი ამოცანა : თავდაპირველად უნდა გავაგზავნოთ მოთხოვნა სერვერზე, შემდეგ დავაგენერიროთ სამომხმარებლო ინტერფეისი და ბოლოს ეს ინტერფეისი შევავსოთ სერვერიდან მიღებული ინფორმაციით.
სინქრონული პროგრამირების შემთხვევაში ინტერფეისის გენერირება არ მოხდება მანამ, სანამ სერვერიდან არ მოვა პასუხი, ანუ ოპერაციათა ჯაჭვის ყოველი რგოლი ელოდება წინას დასრულებას, მაშინ, როდესაც ასინქრონული პროგრამირება გვაძლევს საშუალებას არ დაველოდოთ წინა ამოცანას და გადავიდეთ შემდეგ ეტაპზე, შემდეგი ნაბიჯებიდან გავაკეთოთ ის რისი გაკეთებაც შეგვიძლია, ამასობაში კი წინა ოპერაციების შედეგებიც დაგვეწევა, საბოლოოდ ყველაფერი გაერთიანდება და მივიღებთ შემაჯამებელ სურათს ანუ სასურველ შედეგს.
***
ინგ: Promise - დაპირება; სახელშეკრულებო ვალდებულება (დავალებული პირის შემდეგი მოქმედებების); სიტყვის მიცემა; ვალდებულების აღება.ასინქრონული პროგრამირება სწორედ promise-ზეა დაფუძნებული თანამედროვე ჯავასკრიპტში. promise არის ასინქრონული ფუნქციის მიერ დაბრუნებული ობიექტი, რომელიც ასახავს მოთხოვნის მიმდინარე მდგომარეობას, სტატუსს. promise-ს დაბრუნების მომენტში ოპერაცია ხშირად დასრულებული არ არის, თუმცა აღნიშნული ობიექტი გვაძლევს საშუალებას განვსაზღვროთ წარმატებულია თუ არა კონკრეტული ოპერაცია და მოვიქცეთ ამ პასუხის მიხედვით.promise-ს შეიძლება გააჩნდეს ამ სტატუსებიდან ერთ-ერთი :
- pending - promise-ს ობიექტი შეიქმნა თუმცა ასინქრონული ფუნქცია ჯერ არ შესრულებულა და არ ვიცით წარმატებით დასრულდება თუ არა იგი.
- fulfilled - ასინქრონული ფუნქცია წარმატებით დასრულდა. ასეთ შემთხვევაში ხდება then() დამმუშავებლის (handler) გამოძახება.
- rejected - ასინქრონული ფუნქცია წარუმატებლად დასრულდა. ასეთ შემთხვევაში ხდება catch() დამმუშავებლის გამოძახება.
const fetchPromise = fetch("https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store/products.json"); console.log(fetchPromise); fetchPromise.then((response) => { console.log(`მიღებული პასუხი: ${response.status}`); }); console.log("მოთხოვნა იგზავნება …");
Promise { <state>: "pending" } მოთხოვნა იგზავნება… მიღებული პასუხი: 200
იმისათვის რათა კონკრეტული ფუნქცია ასინქრონულად ვაქციოთ, გამოიყენება async სიტყვაგასაღები, რომელიც ბრაუზერს ეუბნება, რომ ფუნქცია ასინქრონულია, შესაბამისად ელოდება რაღაცის დასრულებას და ამასობაში ბრაუზერს შეუძლია შეასრულოს სხვა ამოცანები. ამ ლოდინის ასაღწერად გამოიყენება await სიტყვაგასაღები :
async function myFunction() { const response = await fetch("something.txt"); }
***
დავუბრუნდეთ App.vue ფაილს :<template> <div> <button @click="fetchData">ინფორმაციის ამოღება</button> <pre v-if="data">{{ data }}</pre> </div> </template> <script> export default { data() { return { data: null, }; }, methods: { async fetchData() { const response = await fetch("file.txt"); this.data = await response.text(); console.log(this.data); } } }; </script>
ინფორმაციის ამოღება JSON ფაილიდან
წინა მაგალითში ინფორმაცია ამოვიღეთ .txt ფაილიდან, ახლა ვნახოთ თუ როგორ შეიძლება იგივეს გაკეთება .json ფაილიდან.
პროექტის ძირ საქაღალდეში შევქმნათ ფაილი animals.json და მასში შევიტანოთ შემდეგი კოდი :
{ "results": [ { "name": "African elephant", "maxWeight": 10000, "carnivore": false, "countries": [ "Namibia", "Angola", "Tanzania", "Kenya", "Mozambique", "Botswana", "South-Africa" ] }, { "name": "Siberian tiger", "maxWeight": 300, "carnivore": true, "countries": [ "Russia", "North Korea", "China" ] }, { "name": "American bison", "maxWeight": 1200, "carnivore": false, "countries": [ "USA", "Canada" ] }, { "name": "Polar bear", "maxWeight": 1000, "carnivore": true, "countries": [ "USA", "Canada", "Norway", "Russia", "Greenland" ] }, { "name": "Gaur", "maxWeight": 1500, "carnivore": false, "countries": [ "India", "Thailand", "Laos", "Cambodia", "Vietnam", "Myanmar", "Malaysia", "China", "Bhutan", "Nepal" ] } ] }
<template> <div> <button @click="fetchData">ინფორმაციის ამოღება</button> <pre v-if="data">{{ data }}</pre> </div> </template> <script> export default { data() { return { data: null, }; }, methods: { async fetchData() { const response = await fetch("animals.json"); this.data = await response.json(); } } }; </script>
import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.mount('#app')
ინფორმაციის ამორება API-დან
API ანუ Application Programming Interface. დაწვრილებითი ინფორმაცია შეგიძლიათ იხილოთ აქ. სადემონსტრაციოდ გამოვიყენოთ random-data-api.com.
App.vue :
<template> <button @click="fetchData">ინფორმაციის ამოღება</button> <pre v-if="data">{{ data }}</pre> </template> <script> export default { data() { return { data: null, }; }, methods: { async fetchData() { const response = await fetch("https://random-data-api.com/api/v2/users"); this.data = await response.json(); } } }; </script>
მოთხოვნის გაგზავნა 'axios' ბიბლიოთეკის მეშვეობით
axios არის ჯავასკრიპტის ბიბლიოთეკა, რომლის მეშვეობითაც შესაძლებელია სხვადასხვა ტიპის მოთხოვნების გაგზავნა სასურველ მისამართზე. როგორც ადრე აღვნიშნეთ, მოთხოვნის ყველაზე გავრცელებული ტიპებია GET, POST, PUT/PATCH და DELETE.იმისათვის რათა შევძლოთ axios-ის გამოყენება, პირველ რიგში უნდა დავაინსტალიროთ ბიბლიოთეკა. ტერმინალიდან გადავინაცვლოთ პროექტის საქაღალდეში და გავუშვათ შემდეგი ბრძანება :
npm install axios
App.vue :
<template> <p> თითოეული დაჭერა აგენერირებს შემთხვევით მომხამერებელს <a href="https://random-data-api.com/" target="_blank">https://random-data-api.com/</a>-დან. </p> <button @click="fetchData">ინფორმაციის ამოღება</button> <div v-if="data" id="dataDiv"> <img :src="data.data.avatar" alt="avatar"> <pre>{{ data.data.first_name + " " + data.data.last_name }}</pre> <p>"{{ data.data.employment.title }}"</p> </div> </template> <script> import axios from 'axios' export default { data() { return { data: null, }; }, methods: { async fetchData() { // get ტიპის მოთხოვნა, ანალოგიურად ხდება სხვა ტიპის მოთხოვნების გაგზავნაც. this.data = await axios.get("https://random-data-api.com/api/v2/users"); } } }; </script> <style> #dataDiv { width: 240px; background-color: aquamarine; border: solid black 1px; margin-top: 10px; padding: 10px; } #dataDiv > img { width: 100%; } pre { font-size: larger; font-weight: bold; } </style>
- 27. Vue $refs ობიექტი
-
თუ რომელიმე ელემენტს მიმაგრებული აქვს ref ატრიბუტი, ეს იმას ნიშნავს, რომ ეს ელემენტი შენახულია Vue-ში ჩადგმულ $refs ობიექტში,
ეს ობიექტი კი გამოიყენება ელემენტთა იდენტიფიკაციისათვის, ელემენტთა ამორჩევისათვის. აღნიშნული ატრიბუტისა და ობიექტის გამოყენება არის ჯავასკრიპტის
ამორჩევითი ფუნქციების : getElementById(), querySelector() და ა.შ ალტერნატივა.
App.vue :
<template> <p ref="p1">დააჭირეთ ღილაკს რათა მოხდეს ამ ტექსტის ტრანსფერი ქვედა პარაგრაფში.</p> <button @click="transferText">Transfer text</button> <p ref="p2">...</p> </template> <script> export default { methods: { transferText() { this.$refs.p2.innerHTML = this.$refs.p1.innerHTML; } } }; </script>
<template> <p>აკრიფეთ ტექსტი ტექსტურ ველში და ეს ტექსტი ავტომატურად ჩაჯდება '$refs' ობიექტში შენახულ პარაგრაფში.</p> <input ref="inputEl" @input="getRefs" placeholder="აკრიფეთ ტექსტი"> <p ref="pEl"></p> </template> <script> export default { methods: { getRefs() { this.$refs.pEl.innerHTML = this.$refs.inputEl.value; } } }; </script>
- 28. Vue კომპონენტის სასიცოცხლო ციკლი
-
Vue-ში კომპონენტის სასიცოცხლო ციკლის ყოველ ფაზაზე შესაძლებელია კონკრეტული ინსტრუქციების შესრულება, კონკრეტული ფუნქციების გაშვება. თითო ფაზას
უკავშირდება ერთი კონკრეტული ფუნქცია, რომელსაც სასიცოცხლო ციკლის ჰუკი ეწოდება. Vue-ში ჩაშენებულია შემდეგი ჰუკები :
- beforeCreate
- created
- beforeMount
- mounted
- beforeUpdate
- updated
- beforeUnmount
- unmounted
- errorCaptured
- renderTracked
- renderTriggered
- activated
- deactivated
- serverPrefetch
beforeCreate ჰუკი
beforeCreate ჰუკი ფიქსირდება კომპონენტის ინიციალიზაციამდე, ანუ მანამ, სანამ Vue მოახდენს ინსტანციაში აღწერილი მონაცემების, გამოთვლადი მეთოდების, სხვა მეთოდებისა და მოვლენათა დამმუშავებლების ჩატვირთვას. სხვა სიტყვებით თუ ვიტყვით ეს არის კომპონენტის სასიცოცხლო ციკლის საწყისი ფაზა.App.vue :
<template> <button @click="this.activeComp = !this.activeComp">კომპონენტის გამოჩენა/დამალვა</button> <div> <comp-one v-if="activeComp"></comp-one> </div> </template> <script> export default { data() { return { activeComp: false } } } </script>
<template> <p id="pResult">{{ text }}</p> </template> <script> export default { data() { return { text: '...' } }, beforeCreate() { this.text = 'განახლებული ტექსტი'; // ეს ინსტრუქცია არ შესრულდება console.log("beforeCreate: კომპონენტი ჯერ არ შექმნილა."); } } </script>
import { createApp } from 'vue' import App from './App.vue' import CompOne from './components/CompOne.vue' const app = createApp(App) app.component('comp-one', CompOne) app.mount('#app')
created ჰუკი
created ჰუკი ფიქსირდება მას შემდეგ რაც მოხდება კომპონენტის ინიციალზაცია, ამ დროს Vue-ს უკვე ჩატვირთული აქვს ინსტანციაში აღწერილი მონაცემები, გამოთვლადი მეთოდები და ა.შ.created ჰუკიდან DOM ელემენტებთან წვდომა შეუძლებელია რადგან ამ დროს DOM ჯერ კიდევ არ არის დაგენერირებული.
created ჰუკი ხელსაყრელი ადგილია HTTP მოთხოვნების გასაგზავნად ან საინიციალიზაციო ინფორმაციების ასაღწერად.
CompOne.vue :<template> <p id="pResult">{{ text }}</p> </template> <script> export default { data() { return { text: '...' } }, created() { this.text = 'საინიციალიზაციო ტექსტი'; console.log("created: კომპონენტი ახლახანს შეიქმნა."); } } </script>
beforeMount ჰუკი
beforeMount ჰუკი ფიქსირდება მანამ სანამ მოხდება კომპონენტის DOM-ში შეტანა, უხეშად თუ ვიტყვით 'დამონტაჟება'. ეს არის mounted ფაზის წინა ფაზა.
DOM ელემენტებთან წვდომა beforeMount ჰუკიდანაც შეუძლებელია. ქვემოთ მოყვანილი მაგალითი, სადაც DOM ელემენტის ტექსტის ცვლილებას ვცდილობთ, შეცდომას გამოიწვევს ბრაუზერის კონსოლში,
CompOne.vue :<template> <p ref="pEl" id="pEl">შევეცადოთ მივწვდეთ ამ ტექსტს 'beforeMount' ჰუკიდან</p> </template> <script> export default { beforeMount() { console.log("beforeMount: კომპონენტის დამონტაჟებამდე დარჩენილია წამის მეასედები :))"); this.$refs.pEl.innerHTML = "გამარჯობა!"; // <-- ჩვენ არ შეგვიძლია მივწვდეთ 'pEl' DOM ელემენტს ამ ფაზაზე } } </script>
mounted ჰუკი
mounted ჰუკი ფიქსირდება მას შემდეგ, რაც კომპონენტი ჩაჯდება DOM-ში. ამ დროს უკვე შესაძლებელია DOM ელემენტებით მანიპულირება.
CompOne.vue :<template> <p>კომპონენტი</p> </template> <script> export default { mounted() { alert("კომპონენტი დამონტაჟდა DOM-ში!"); } } </script>
beforeUpdate ჰუკი
beforeUpdate ჰუკი ფიქსირდება მას შემდეგ, რაც ვახდენთ კომპონენტში აღწერილი ინფორმაციის ცვლილებებს თუმცა ეს ცვლილებები ჯერ კიდევ არ არის ასახული ეკრანზე.
App.vue :<template> <button @click="this.activeComp = !this.activeComp">კომპონენტის გამოჩენა/დამალვა</button> <div> <comp-one v-if="activeComp"></comp-one> </div> <ol ref="divLog"></ol> </template> <script> export default { data() { return { activeComp: true } }, beforeUpdate() { this.$refs.divLog.innerHTML += "<li>beforeUpdate: ეს მოხდება updated ჰუკამდე</li>"; } } </script>
<template> <h2>კომპონენტი</h2> </template>
updated ჰუკი
updated ჰუკი ფიქსირდება მას შემდეგ, კომპონენტი განახლდება DOM-ში.
App.vue :<template> <button @click="this.activeComp = !this.activeComp">კომპონენტის გამოჩენა/დამალვა</button> <div> <comp-one v-if="activeComp"></comp-one> </div> </template> <script> export default { data() { return { activeComp: true } }, updated() { console.log("კომპონენტი განახლდა!"); } } </script>
beforeUnmount ჰუკი
beforeUnmount ჰუკი ფიქსირდება კომპონენტის DOM-იდან წაშლამდე.
App.vue :<template> <button @click="this.activeComp = !this.activeComp">{{ btnText }}</button> <div> <comp-one v-if="activeComp"></comp-one> </div> </template> <script> export default { data() { return { activeComp: true } }, computed: { btnText() { if(this.activeComp) { return 'კომპონენტის წაშლა' } else { return 'კომპონენტის გამოჩენა' } } } } </script>
<template> <p ref="pEl">გამარჯობა!</p> </template> <script> export default { beforeUnmount() { alert("beforeUnmount: p ტეგის ტექსტი არის: " + this.$refs.pEl.innerHTML); } } </script>
unmounted ჰუკი
unmounted ჰუკი ფიქსირდება კომპონენტის DOM-იდან წაშლის შემდეგ.
App.vue :<template> <button @click="this.activeComp = !this.activeComp">{{ btnText }}</button> <div> <comp-one v-if="activeComp"></comp-one> </div> </template> <script> export default { data() { return { activeComp: true } }, computed: { btnText() { if(this.activeComp) { return 'კომპონენტის წაშლა' } else { return 'კომპონენტის გამოჩენა' } } } } </script>
<template> <h2>კომპონენტი</h2> </template> <script> export default { unmounted() { alert("კომპონენტი წაიშალა (unmounted)!"); } } </script>
- 29. Vue მარშრუტიზაცია
-
Vue-ში მარშრუტიზაცია გამოიყენება აპლიკაციაში ნავიგაციისათვის, თანაც ეს ხდება კლიენტის მხარეს (ბრაუზერში), გვერდის ხელახალი ჩატვირთვის (refresh) გარეშე,
ეს კი განაპრობებს სამომხმარებლო ინტერფეისის სისწრაფესა და კომფორტულობას. ჩვენ უკვე შევეხეთ ამდაგვარ საკითხს დინამიური კომპონენტების განხილვისას, მაგრამ
მარშრუტიზცია გაცილებით დახვეწილი და მასშტაბური სისტემაა, რომელსაც ამ თავში განვიხილავთ.
როგორც ადრე აღვნიშნეთ Vue-ს მეშვეობით იქმნება ერთგვერდიანი აპლიკაციები (SPA) რომლებშიც მხოლოდ ერთი .html ფაილი გვაქვს, რაც იმას ნიშნავს, რომ შეუძლებელია მომხმარებელს გავუხსნათ სხვა .html ფაილი განსხვავებული შიგთავსის სანახავად.
Vue Router ბიბლიოთეკა
პირველ რიგში უნდა დავაინსტალიროთ Vue Router ბიბლიოთეკა, ამისათვის გადავინაცვლოთ პროექტის საქაღალდეში და გავუშვათ შემდეგი ბრძანება :npm install vue-router@4
import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import App from './App.vue' import CompOne from './components/CompOne.vue' import CompTwo from './components/CompTwo.vue' const router = createRouter({ history: createWebHistory(), routes: [ { path: '/one', component: CompOne }, { path: '/two', component: CompTwo } ] }); const app = createApp(App) app.use(router); app.mount('#app')
<template> <p> <!-- router-link კომპონენტი გამოიყენება სანავიგაციო ბმულების დასაგენერირებლად --> <!-- ბმულის გზის განსაზღვრა ხდება `to` ატრიბუტის მეშვეობით --> <!-- <router-link> კომპონენტი დააგენერირებს `<a>` ტეგს კორექტული `href` ატრიბუტითურთ --> <router-link to="/one">პირველი</router-link> <router-link to="/two">მეორე</router-link> </p> <!-- აქ ჩაიტვირტება კომპონენტი, რომლის შესაბამის ბმულსაც დავაწვებით --> <router-view></router-view> </template>
<template> <h2>პირველი კომპონენტი</h2> </template>
<template> <h2>მეორე კომპონენტი</h2> </template>
ბმულებს თუ გადავამოწმებთ ვიხილავთ შემდეგ სურათს :
router-link
როგორც ზემოთ ვნახეთ, სტანდარტული <a> ტეგის ნაცვლად გამოვიყენეთ <router-link> კომპონენტი, ეს Vue-ს საშუალებას აძლევს შეცვალოს მისამართი ბრაუზერის სამისამართო ველში, გვერდის ხელახალი ჩატვირთვის გარეშე (refresh).router-view
<router-view> დირექტივა ქმნის წინასწარგამზადებულ სივრცეს, რომლის შევსებაც მოხდება იმ კომპონენტით, რომლის შესაბამის ბმულსაც დავაწვებით. ამ დირექტივის განთავსება შეგვიძლია ნებისმიერ ადგილას.დინამიური მარშრუტები პარამეტრებით
ძალიან ხშირად საჭიროა, რომ მარშრუტს გადაეცეს დამატებითი პარამეტრები. წარმოვიდგინოთ ასეთი სიტუაცია: დავუშვათ გვინდა, რომ ჩვენს CompOne.vue კომპონენტში გამოვიტანოთ ინფორმაცია კონკრეტული მომხმარებლის შესახებ, ბუნებრივია სისტემას რამენაირად უნდა მივაწოთ საჭირო პარამეტრები იმის დასადგენად, თუ კონკრეტულად რომელი მომხმარებელი გვესაჭიროება. ამისათვის მარშრუტს უნდა გადავცეთ დამატებითი პარამეტრი. main.js :import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import App from './App.vue' import CompOne from './components/CompOne.vue' import CompTwo from './components/CompTwo.vue' const router = createRouter({ history: createWebHistory(), routes: [ { path: '/one/:id', component: CompOne }, { path: '/two', component: CompTwo } ] }); const app = createApp(App) app.use(router); app.mount('#app')
ამის შემდეგ /one/vaso და /one/giorgi და მათნაირ ბმულებს ერთი და იგივე მარშრუტი დაამუშავებს ასევე მოხდება ერთი და იგივე კომპონენტის ჩატვირთვა.
კომპონენტში მარშრუტის პარამეტრების გასაგებად გამოიყენება this.$route.params ჩანაწერი:
<template> <h2>პირველი კომპონენტი</h2> <div>{{ id }}</div> </template> <script> export default { data() { return { id: this.$route.params.id } } } </script>
შაბლონი გზაბმული $route.params /users/:username /users/vaso { username: 'vaso' } /users/:username/posts/:postId /users/vaso/posts/123 { username: 'vaso', postId: '123' } - 30. Vue ფორმის ველები
-
რადიო ღილაკები
რადიო ღილაკებს v-model ატრიბუტთან ერთად უნდა განესაზღვროს value ატრიბუტიც, App.vue :<template> <form @submit.prevent="registerAnswer"> <label> <input type="radio" name="favFood" v-model="inpVal" value="ხაჭაპური"> ხაჭაპური </label> <label> <input type="radio" name="favFood" v-model="inpVal" value="პიცა"> პიცა </label> <label> <input type="radio" name="favFood" v-model="inpVal" value="ლობიანი"> ლობიანი </label> <button type="submit">არჩევა</button> </form> <div> <h3>არჩეული საკვები:</h3> <p >{{ inpValSubmitted }}</p> </div> </template> <script> export default { data() { return { inpVal: '', inpValSubmitted: 'ჯერ არ არის არჩეული' } }, methods: { registerAnswer() { if(this.inpVal) { this.inpValSubmitted = this.inpVal; } } } } </script>
import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) app.mount('#app')
ჩეკბოქსები
როდესაც <input type="checkbox"> ველების არჩეული მნიშვნელობები ინახება მასივში, App.vue :<template> <form @submit.prevent="registerAnswer"> <label> <input type="checkbox" v-model="likeFoods" value="ხაჭაპური"> ხაჭაპური </label> <label> <input type="checkbox" v-model="likeFoods" value="ლობიანი"> ლობიანი </label> <label> <input type="checkbox" v-model="likeFoods" value="პიცა"> პიცა </label> <button type="submit">არჩევა</button> </form> <div> <h3>არჩეული საკვები:</h3> <p id="pAnswer">{{ inpValSubmitted }}</p> </div> </template> <script> export default { data() { return { likeFoods: [], inpValSubmitted: 'არ არის არჩეული' } }, methods: { registerAnswer() { this.inpValSubmitted = this.likeFoods; } } } </script>
ჩამოსაშლელი სიები
App.vue :<template> <form @submit.prevent="registerAnswer"> <label for="cars">აირჩიეთ მანქანა:</label> <select v-model="carSelected"> <option disabled value="">აირჩიეთ მანქანა</option> <option>Volvo</option> <option>Saab</option> <option>Opel</option> <option>Audi</option> </select> <br><br> <input type="submit" value="არჩევა"> </form> <div> <h3>არჩეული მანქანა:</h3> <p id="pAnswer">{{ inpValSubmitted }}</p> </div> </template> <script> export default { data() { return { carSelected: '', inpValSubmitted: 'არ არის არჩეული' } }, methods: { registerAnswer() { if(this.carSelected) { this.inpValSubmitted = this.carSelected; } } } } </script>
<select multiple>
App.vue :<template> <form @submit.prevent="registerAnswer"> <select v-model="carsSelected" multiple> <option>Volvo</option> <option>Saab</option> <option>Opel</option> <option>Audi</option> <option>Kia</option> </select> <button type="submit">არჩევა</button> </form> <div> <h3>არჩეული მანქანები:</h3> <p>{{ inpValSubmitted }}</p> </div> </template> <script> export default { data() { return { carsSelected: [], inpValSubmitted: 'არ არის არჩეული' } }, methods: { registerAnswer() { if(this.carsSelected) { this.inpValSubmitted = this.carsSelected; } } } } </script>
- 31. Vue 'build' რეჟიმი
-
პროექტზე მუშაობისას, ანუ 'დამზადების რეჟიმში' (development mode), ხელსაწყო Vite ახდენს ამ რეჟიმის შესაბამისი სერვერის ამუშავებას.
როდესაც პროექტში შეგვაქვს ცვლილებები Vite დაუყოვნებლივ ახდენს ბრაუზერის განახლებას. ეს კი დიდ რესურსებს მოითხოვს კომპიუტერისგან.
საჭიროა, რომ პროექტის დასრულების შემდეგ მოვახდინოთ პროექტის საბოლოო გენერირება, აგება, 'დაბილდვა' build ბრძანების დახმარებით. ბრძანება შექმნის .html, .js და .css ფაილებს, რომლებსაც ბრაუზერი 'დამზადების რეჟიმში' გაშვებული Vite ხელსაწყოს გარეშეც აღიქვამს, რაც შეამცირებს დატვირთვას სერვერზე.
პირველ რიგში უნდა გამოვრთოთ 'დამზადების რეჟიმი', ბრძანებათა ველიდან ავკრიფოთ 'Q' ან 'ctrl'+'C', შემდეგ კი გავუშვათ შემდეგი ბრძანება :
npm run build
დაბილდული პროექტის სანახავად უნდა გავუშვათ შემდეგი ბრძანება :
npm run preview
- 32. Vue Options vs Composition
-
როგორც გვახსოვს, კურსის მსვლელობისას არაერთხელ ვახსენეთ ტერმინი 'კონფიგურაციული პარამეტრი', ამ პარამეტრების უკან მოიაზრდებოდა Vue-ს ინსტანციაში აღწერილი,
ერთგბარი ბლოკები, კოდის ფრაგმენტები, რომლებიც გვიმარტივებდნენ კოდის საერთო იერსახის ჩამოყალიბებისა და სტრუქტურიზების პროცესს :
const app = Vue.createApp({ data() { ... }, watch: { ... }, computed: { ... }, methods: { ... } ... })
- შესაძლებელია რელევანტური ანუ ერთი და იმავე საკითხთან დაკავშირებული კოდის ფრაგმენტების დაჯგუფება, რის შედეგადაც იწერება უფრო ორგანიზებული და ლამაზი კოდი.
- მარტივადაა შესაძლებელი კოდის განმეორებითად (reuse) გამოყენება კომპონენტებში.
ლამაზი და ორგანიზებული კოდი
წარმოვიდგინოთ, რომ გვაქვს ორი მეთოდი - ერთი უკავშირდება პროდუქტს, მეორე კი მომხმარებლებს. პარამეტრული მიდგომის (Options Api) შემთხვევაში, მიუხედავად იმისა, რომ ამ მეთოდებს საერთო არაფერი აქვთ, ორივე მათგანის აღწერა უნდა მოხდეს methods პარამეტრში.
ასევე თუ გვაქვს მომხმარებლებთან და პროდუქტთან დაკავშირებული ორი გამოთვლადი თვისება, ორივეს აღწერა უნდა მოხდეს computed პარამეტრში.
მომხმარებელთან დაკავშირებული თვისება და გამოთვლადი პარამეტრი, ნაცვლად იმისა, რომ ერთ სივრცეში, ერთ სექციაში მოექცეს, კოდის ორ სხვადასხვა ადგილას 'გაიფანტება', ანალოგიურად მოხდება პროდუქტისთვისაც. არადა უფრო ლოგიკურია პროდუქტთან დაკავშირებული კოდი გვქონდეს ცალკე, მომხმარებლებთან დაკავშირებული კოდი ცალკე და ა.შ
ამ ყველაფრის კიდევ უფრო კარგად გასაგებად დავაკვირდეთ ფოტოს :
ფოტოზე აღწერილ კოდში მანიპულირება ხდება სამი ძირითად საკითხით, ესენია :
- პერსონალური ინფორმაცია
- მომხმარებელთა სია
- სასიცოცხლო ციკლის ჰუკები
კოდის მრავალგამოყენებადობა
მოვიყვანოთ კომპოზიციური მიდგომით (Composition Api) დაწერილი კოდის მაგალითი, დავუშვათ რომელიმე კომპონენტში აღწერილი გვაქვს useUserList() ფუნქცია, რომელიც აბრუნებს users, usersList, addUser() და removeUser() მონაცემებსა და მეთოდებს :// src/composables/user-list.js import { computed, ref } from 'vue'; export const useUserList = () => { const users = ref(['Jane', 'Mark', 'Bob']); const usersList = computed(() => users.value.join(', ')); const addUser = (user) => { users.value.push(user); }; const removeUser = (username) => { users.value = users.value.filter((user) => user !== username); }; return { users, usersList, addUser, removeUser, }; };
<script setup> import { useUserList } from '@/composables/user-list'; const { users, usersList, addUser, removeUser } = useUserList(); </script>
***
ვთანხმდებით იმაზე, რომ კომპოზიციური მიდგომისას (Composition Api) არ ვიყენებთ ისეთ კონფიგურაციულ ბლოკებს როგორებიცაა data(), computed, methods, watch ... კომპოზიციური მიდგომაში მათ ნაცვლად გამოიყენება Vue-ში ჩაშენებული ფუნქციები, რომელთა იმპორტირებასაც ვახდენთ კომპონენტებში :
<template> <p>საწყისი რაოდენობა: {{ number }}</p> <button @click="remove">ერთის მოკლება</button> <p>"{{ storageComment }}"</p> </template> <script setup> import { ref, computed } from 'vue' const number = ref(10); function remove(){ if(number.value>0){ number.value--; } } const storageComment = computed( function(){ if(number.value > 5) { return "ჯერ კიდევ არის მარაგი" } else if(number.value > 0){ return "მარაგი იწურება" } else { return "მარაგი ამოიწურა" } } ) </script>