VIEW JS the progressive framwork
-
VUE.JS IS A PROGRESSIVE FRAMEWORK
-
Means it does not seek for exclusive control over your projet
-
you can easily integrate it with other libraries and existing projects
-
View helps us build user iterface
-
A view is created using HTML and css
What does Vue Do ?:
Vue’s main job is to present data or collect data of a user
How about vue ?
view simply contains static elements , it does not store data of a particular user view needs some kind of connection to a database. we need a middle man , aka a model to operate the database
SINGLETON AND FACTORY PATTERNS
SINGLETON
ONE object is shared with all other instances
FACTORY PATTERN
CREATING OUR FIRST VIEW PROGRAM
Steps
Step1 Create Empty html file with the basic syntax
step2 link to a vue cdn
step3 create a root component template
step4 create our first view app using
- Vue.CreateApp( { options obj. }).mount(‘#vue_app’)
- data properties
- data-processing methods
- …
- ‘auto Execution’
-
3.lifecyle hook functions
-
5.watchers
-
…
-
Example Of a Vuew Program
Vue Bind
When adding view bind to an attribute it become a view component and you can use expressions or data passed from the view to it
{{car.brand}}
An html property that does not accept any argument such as the Disable attribute you can decide wether it is shown or not
V-bind example
VIEW DIRECTIVES
- V-text
- v-html
- v-once
- v-pre
- v-is
- v-cloak
v-text:
The mustache tag {{}} is not the only way of displaying text we can replace it using the v-text directive
v-text
v-html(Not Recommended)
used to display html code as native html instead of simple string Cote will inserted as plain html html: ’Hello there i am happy’
v-once
Informs view to only render the current element once only
v-once
v-pre
This tells view to skip compiling the current element and everything nested in it the raw code will be directly presented to users
{{person.name}}
output: {{person.name}}v-is(Deprecated by version 3.1)
using this attribute we can convert an html tag to another attribute tag eg: we can convert the h2 tag into a b tag (the tag name needs to be a string)
{{person.name}}
It will become {{person.name}}v-cloak
When we refresh the page for a few moment users can see the raw template code , they can see all the mustache tags , this is because the compilation of the template did not finish instantly usin the v-cloak we can hide the raw template code until the complitaion is over and do to that we will wrap our rendered element in an outer div we add the v-cloak in the outer div and after that we add the css class using the v-cloak directive
CONDITION RENDERING
Vue offers us four condition rendering for this job
- v-show
- v-if,
- v-else,
- v-else-if v-show works alone while the last 3 works together condition rendering just like the name states is , renders somethin based on a condition
example:
v-show
This one will hide an element using the display none property
you can put it directly inside of an element you want to apply change to
Hello there cake
//will showNot there cake
//will not showThe Code bellow will make sure only one item is showing ,
Hello there cake
Not there cake
daga(){
return{
have:false
}
}
?W?V6f,$4@tL9fe
v-if v-else,v-else-if directive
Unlike v-show , v-if completely removes an element from the html file, it does not apply a display none property
will run if a condition is only true, otherwise , jump to the else statement
!!! note that , there must not be any element in between these two elements bellow(p )
Otherwise it will not work
v-if and v-else needs to be adjacent to each other
Hello there cake
Not there cake
You can compare with the v-if directive
- Apple
- Apple
- Other
THE ref ATTRIBUTE AND vm.$refs
==============================
This attriutes helps us understand more how view works
You can think of the ref vue attribute as the equivalent id of the html attribute
it is a unique identifier and helps us retrieve page elements, the ref value is set by us
and must be unique , the ref attribute is set by us and must be unique
-The ref attribute is used by vue internally and wont show up in the final rendered html code ,
-The ref attribute helps us sellect DOM elements, they are stored in the vm.$refs property
{{title}}
{{msg}}
v-for Directive
===============
This is simply the equivalent of the for loop
we use it to itterate over arrays or objects
-
{{elem}} - {{index}}
Syntax for a list or array:
(it is best to give every dynamically generated element a key, so that view can )
differentiate betwen the geenrated elements :key=”
{{element}} - {{index}}
car=[‘Toyota’,‘Nissan’,‘Honda’]
Suntax for an object
compared with arrays objects an store an extra piece of value using the property name
value and index , the index is not needed , it simply helps us create unique generated values
{{value}} - {{property_name}} ({{index}})
car: { brand: ‘Nissan’, model: ‘GT-R’, year: 2021 },
ITERATING OVER A LIST OF OBJECTS
-
{{prop}}: {{val}}
json: [
{ brand: ‘TOyota’, model: ‘Camry’, year: 2015 },
{ brand: ‘Nissan’, model: ‘GT-R’, year: 2035 },
{ brand: ‘Honda’, model: ‘NSX’, year: 2025 },
]
COMPUTED
+=======+
data(){
return{
brand:‘Toyota’,
model:‘Land Cruiser’,
reg_year:2015
}},
We have 3 properties brand,model an reg_year , in a real life example these 3 pieces values are retrieved from a backend
API, sometimes we need to process retrieved data before presenting them to user
EX: Present the car age to the user , the car age is presented by substructing the registration year to the current year
we can define the math expression in the component template vue will execute the expression and return the result
Age: {{new Date().getFullYear() - reg_year}}
But This is not recommended at all, it is best to keep logic code in the option objects
the template must be kept clean and simple , prefferably only displaying vue properties
!!!!!
To help us create new values based on data properties , vue offeres us computed properties
computer properties are extention of properties
!!!!!!!
!!!!!!!
To create them we must add a computed option,then add a new property called car_age , we can set its value using the
function syntax or the object syntax
most of the the time the object syntax is the best option
data(){
…
},
computed:{
car_age: //object syntax
car_age(){} //function syntax
}
computed:{
car_age(){
return: new Date().getFullYear() - this.reg_year
}
//this is a getter of registration year property, it return a value that is based on the registration year property
value
}
!!!!
Computed property get added to the root level of the target object
computed object are not data properties they won’t be added in the $data object
Computed properties are reactive, component templates get updated automatically,
The car_age Property is read-only, the reason is , we defined it using the function syntact, it only
has a getter , there is no setter to handle the value, most of the time a read only value is exactly what we need , we
don’t need to worry about data properties being modified.
IF we use the object syntax, we hense set a getter and a setter, making it read and write
XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
!!! Computed properties and data properties should never be named the same
XXXXXXXXXXXXXXXXXXXXXXXX
data(){
brand:‘Toyota’
},
computed:{
brand(){
return ‘duplicate brand property’;
}
}
XXXXXXXXXXXXXXXXXXXXXXXXXXXX
EXAMPLE
=======
Age: {{ car_age }}
// Age: 7
Name: {{ full_name }}
//Name: Ilunga Car Mozerfoker
After Modification in the console:
vm.full_name=[‘Ilunga Car’,‘Mozerfoker’]
//Name: Ilunga Car Mozerfoker
data() {
return {
brand: ‘Toyota’, model: ‘Land Cruiser’, reg_year: 2015
};
},
computed: {
car_age() {
//This is simply read only, defined using function syntac car_age()..
return new Date().getFullYear() - this.reg_year;
},
full_name: {
//Read and write , property , because we defined it using the object suntax
get() {
return this.brand + ’ ’ + this.model;
},
set(newName) {
this.brand = newName[0];
this.model = newName[1];
}
}
}
vm.full_name=[‘Ilunga Car’,‘Mozerfoker’]
Array [ “Ilunga Car”, “Mozerfoker” ]
VIEW METHODS
===========
View methods are defined inside of the method option , every view method should be defined using the full function
not the arrow function , the reason is the same as before , we need the view method to have a controleable this
data(){…},
computed:{…},
methods:{
test(){
console.log(‘the test method’)
return this
}
},
once a view method has been define, it will be added to the root level of the component intance
view method can be accessed via this, and is also visible in the component templates
vm.test()
Let’s Create a simple counter when a button is clicked
Number: {{number}}
‘How to add an event on a button ’
// Traditional js event addEventListener(‘click’, ()=>{})
The Equivalent vue listener:
Example of an increment Program
===================
{{num}}
<button @click=“num++“>Click Me
<button @click=“m2,m2”>Click Me
<button @click=“num++“>Click Me
data(){
return{
num:0
}
}
methods:{
increment(){
console.log(‘the test method’)
this.num++
}
},
Triggering Multiple Methods: WHen you want to trigger multiple methods
the paranthesis is needed
<button @click=“m1(event)“>ClickMe
You cacn even mix view methods with custom methods
data(){
return{
num:0
}
}
methods:{
m1(){
console.log(‘the test method 1’)
},
m2(){
console.log(‘the test method 1’)
},
increment(){
console.log(‘the test method’)
this.num++
}
},
CLOSURE AND VIEW-ON DIRECTIRE Function EVENTS (to listen to events to trigger events)
===============================
Simple COunter program
Now let’s Demostrate the closure on vue
<button @click=“outer($event)()“>Vue Button
Vue counter app will not work , each execution of the inner function has it’s own outer scop ,
therefore when we click the vue button we will always get 100
EVENT MODIFIERS (once,stop,self,capture,prevent )
Let’s create a simple program to demonstrate this:
<button @click=“test(click
)“>Native Button
Everytime a button get clicked the event gets triggered
ONCE
The event will only get triggered once ,and get ignored other times
<button @click.once=“test(click
)“>Native Button
STOP MODIFIER (What is propagation?)
the stop modifier is used to stop propagation, it is used to stop event from traveling from child to parent
we should put the stop modifer in the innder div
let’s say you have two div one nested in another,
outer
<div class=‘bgTwo’ @click.stop=‘test(inner
)‘>
inner
<button @click=‘test(inner button
)‘>Inner Button
and you bind events to both, if you click the outher div , everythign is alright
if you click the inner one , even the outer gets triggered , that is called propagation and to
stop propagation we use the stop modifier that is why we did put it in the inner div
SELF MODIFIER:
As for The self modifier, what it does it simply tell to the parent to mind it’s business and not get triggered
when the child element gets clicked
outer
<div class=‘bgTwo’ @click.self=‘test(inner
)‘>
inner
<button @click=‘test(inner button
)‘>Inner Button
In the code above there wont be any propagation
CAPTURE Modifier
The element with the capture modifier captured the event from its inner element it will be triggered first
then the normal propagation process will follow
outer
<div class=‘bgTwo’ @click.capture=‘test(inner
)‘>
Middle
<div class=‘bgOne’ @click=‘test(inner
)‘>
inner
<button @click=‘test(inner button
)‘>Inner Button
PREVENT and PASSIVE modifier (VIDEO: the .passive modifier)
It disables the html Default behavior by calling the Event.PreventDefault method
<a href=“/test” @click.prevent>Link
!!! Prevent and passive modifiers can not be used together
they mitually exclude each other
The passive modifier is for improving program efficiency during a scrolling or zoom operation
it ensures the browser that we won’t call the event.prevent default method
COLLECT USER SUBMITED DATA USING VIEW MODEL
<input type=“text” id=“input” :value=“msg” @input=“msg=$event.target.value” />
// We can now control the msg value property in real time
but if we take a look in the input box we are going to see two directives , this is rather inconvenient
View offers us a syntax sugar , the V-model directive
SYntax sugar is simply an alias for a longer piece of code
the v-model works as a substitute for type=“text” id=“input” :value=“msg” @input=“msg=$event.target.value”
we simply change our code to this and we are done
How can we improve the V-model Directive
.number: captures numeric values if types otherwise simply captured string
.lazy: makes sure that evenets does not get triggered every time , they get triggered when enter is pressed or when
focus
is lost
.trim : makes sure there is no space before and after a group of string
==================================================
MINI APP LIMITING USER SUBMITTED DATA
<input v-model.trim=“msg” @input=“check” />
{{max-msg.length}}/{{max}}
!!! As we can see in the program above , the @input does a better job limiting user input
in the commented section we can as well use change , but it gets applied later offering a bad user Experience
================================
RADIO BUTTON EVENTS
<input type=“radio” value=“apple” name=“fruit” @change=“picked=$event.target.value” :checked=“picked==apple
“>Apple
<input type=“radio” value=“orange” name=“fruit” @change=“picked=$event.target.value” :checked=“picked==orange
“>Orange
<input type=“radio” value=“banana” name=“fruit” @change=“picked=$event.target.value” :checked=“picked==banana
“>Banana
!!!! THE TOUGH WAY
<input type=“radio” value=“apple” @change=“picked=$event.target.value” :checked=“picked==apple
“>Apple
<input type=“radio” value=“orange” @change=“picked=$event.target.value” :checked=“picked==orange
“>Orange
<input type=“radio” value=“banana” @change=“picked=$event.target.value” :checked=“picked==banana
“>Banana
!!!! THE EASY WAY
~The code below represent the whole statement in the code above with the @change and :cheked directives when used with
the radio
Apple
Orange
Banana
CHECKBOX LIST BOX V-MODEL DIRECTIVE
===========================
Apple
Orange
Banana
<input type=“checkbox” value=“pineaple”
@input=“list.includes(‘pineaple’) ? list.splice(list.indexOf(‘pineaple’),1) : list.push(‘pineaple’)”
:cheked=“list.includes(‘pineaple’)“> Pineaple
{{list}}
SELECTION LIST V-MODEL
<select :value=“picked” @input=“picked=$event.target.value”>
data() {
return {
picked: ‘orange’
};
},
ALTERNATIVELY WE CAN simply assignn the v-model picked to the select box
MULTIPLE SELECTION
data() {
return {
list:[‘apple’,‘mango’,‘orange’]
};
},
====================================================================================
SIMPLE TODO APP IN VUE JS
{{title}}
<input type=“Text” v-model.trim=“new_item” @input=“check” :placeholder=“msg”>
<button @click=“add_item” :disabled=“new_item.length==0”>Add
{{max-new_item.length}}/{{max}}
-
{{element}} <button @click=“delete_item(index)“>Delete
Nothing in this thing
Out Vue Codes:
data() {
return {
title: “To-do List App”,
new_item: ”,
list: [“applet”, “orange”],
max: 8
};
},
computed: {
msg() {
if (this.list.length == 0) return “Add New Item”;
return (this.list.length === 1) ? “One Item” : this.list.length + ” Items”;
}
},
methods: {
check() {
if (this.new_item.length > this.max) {
this.new_item = this.new_item.substring(0, this.max);
}
},
delete_item(item) {
this.list.splice(item, 1);
},
add_item() {
if (this.new_item == 0) return;
this.list.push(this.new_item);
this.new_item = ”;
},
}
CONTROLLING CSS USING VUE
We can simply controll css by adding or removing classes or simply Adding inline styles
.bgOne{
background-color:#3CB881;text-align:center;padding:10px;margin:5px;
}
.bgTwo{
background-color:#34495E;text-align:center;padding:10px;margin:5px;
}
.textOne{
color:wheat;font-size:24px;font-family:cursive;
}
.textTwo{
color:white;font-size:24px;font-family:Impact;
}
Now to controll the addition and removal of class we bind to the class
{{msg}}
<button @click=“bg=!bg”>ChangeBg
<button @click=“text=!text”>ChangeBg
{{msg}}
<button @click=“bg=!bg”>ChangeBg
<button @click=“text=!text”>ChangeBg
USING THEME As an Object and Array
============
{{title}}
VUE LIVECYLE HOOKS
Hooks are function that are automatically executed at predefined timings, it is a very efficient way of integrating our custom codes into an established program
Vue Hooks are defined at the component leverl
Root or child component
LiveCycle Hooks
BeforeCreate
created
beforeMount
Mounted
beforeUpdate
updated
active
deactivated
beforeUnmount
unmounted
errorCaptured
renderTracked
renderTriggered
Vue Live CycleHooks
================
Updated and Before Update Hooks
Modifying any property which is displayed in the component template triggers the updated and beforeUpdate hooks,But Changes made via the DOM object won’t trigger the hooks
===============================================================
WATCHERS
wATCHERS Helps in watching a property in 360 angle,
everywhere it can possibly be modified from
!Remember our program to check user input and delimiter him from a specific max chars?
<input v-model=“msg” @input=“check” />
{{max-msg.length}}/{{max}}
This works and it is good , but if the user modifies things from the console there is no way we can be able to prevent that
vm.msg=“MessageLonger than required length”
Now this is when watchers come for rescue
Vue offeres us 3 ways to use watchers
let’s see how we can fix the above problem with watchers
Watcher usage
{{max - msg.length}} / {{max}}
{{msg}}
ANOTHER USE CASE USING THE WATCHER
Kigali
Gisenyi
Goma
{{city}} : {{weather}}
!!!!!!!!!!!!!
Now let’s say we want to give an initial value,so that the query method gets triggered automatically,
what are we going to do ?
Solution 1
The simplest method would be to call the create query in teh created hook
methods:{
…
},
created() {
this.query(this.city);
}
Solution 2
=============
We can Ask the city watcher to respond during the initial loading of the program
for that we are going to use the object syntax in the wather property
watch:{
city: {
handler(newval, oldval) {
console.log(oldval + ”->” + newval);
this.query(newval);
},
immediate: true
}
}
WATCHING A REFERENCE TYPE VALUE OR OBJECT
watch: {
list: {
handler(newVal, preVal) {
console.log(preVal, ”->”, newVal);
},
deep: true
// without this deep true , the array watcher will //only get triggered when we asign a new array to it
//Now any change to our array will trigger the watcher(pop, push, edit etc…)
},
Trigger on element size change
watch: {
list: {
handler(newVal, preVal) {
console.log(preVal, ”->”, newVal);
},
‘list.length’(newVal,preVal){
console.log(‘elem total:‘+prevVal+’->‘+newVal);
}
We can not watch a specific array element
!!!! avaoid doing so
‘list[0]’:{
handler(newval,preval){
console.log(preval+”->“+newval)
},
deep=true
}
Watching object properties
object properties on the other hand can be watched
‘car.brand’(newval,preval){
console.log(preval+” -> “+newval)
}
FLUSH TIMING OF WATCHER
flush property decides if a watcher property is executed before the page renders or after it
WE HAVE tree options,
pre, post and sync
Pre is the default value and also the recommended one
watch: {
msg: {
handler(newVal, preVal) {
console.log(preVal, ”->”, newVal);
},
immediate: true,
flush: ‘sync’
},
Hooks
A watcher is a very special typepe of hook , it mornitors the ttarget value and triggers when the value changes
we can monitor an different watchers , we just have to ut them in the array
Using A function Syntac
watch: {
msg: [
function (newVal, preVal) {
console.log(“first msg watcher”);
console.log(preVal, ”->”, newVal);
},
function (newVal, preVal) {
console.log(“first msg watcher”);
console.log(preVal, ”->”, newVal);
}
]
},
Using an object Syntax
watch: {
msg: [
{
handler() {
console.log(“first msg watcher”);
},
immediate: true, flush: ‘pre’,
},
{
handler() {
console.log(“Second msg watcher”);
},
immediate: true, flush: ‘pre’,
}
]
},
!Now we have two watchers with complete different settings,
==================================
SECOND WAY OF USING WATCHERS $watch
monitoring a property change via the watch function is convenient , we just need to list the target name as a property name then assign either a function name or an obejct to it.
This is what we have been doing above.
*=>Now As a trade off , the watch funtion does not offers us enough control over the watcher and the watch source, we can not control the start and end of a watcher
*=>Using the target name as a property name, means we can not set a complicated expression to monitor a calculated a value
That’s when $watch() comes to the rescue
$Watch in action
created() {
// the watcher Will start automatically when the app instance is created
this.$watch(
‘msg’,
(newval, preval) => {
// uses the arrow function so that it can inherit the this from the created hook
console.log(preval + ’=>’ + newval);
},
{
// Because of immediate true, the watcher will trigger when we first load the page
immediate: true
}
);
},
You can Stop A watcher from running by stopping it
data() {
return {
msg: ‘danielement’,
stop: null,
stop_2: null,
};
},
created() {
// You can also declare multiple watchers
// the watcher Will start automatically when the app instance is created
this.stop = this.$watch(
‘msg’,
(newval, preval) => {
// uses the arrow function so that it can inherit the this from the created hook
console.log(“First watcher in action”);
console.log(preval + ’=>’ + newval);
},
{
// Because of immediate true, the watcher will trigger when we first load the page
immediate: true
}
);
this.stop_2 = this.$watch(
‘msg’,
(newval, preval) => {
console.log(“Second watcher in action”);
// uses the arrow function so that it can inherit the this from the created hook
console.log(preval + ’=>’ + newval);
},
{
// Because of immediate true, the watcher will trigger when we first load the page
immediate: false
}
);
},
Now: By invocking the stop property which holds a function, a watcher can me modified
- Uppon the loading of the page:
//The first watcher will be runned
-vm.msg=“Dan”
// uppon the modification of the msg property Both watcher will be executed
-vm.stop
//Display to you the function it holds fro the watcher
-vm.stop()
//by calling this function, the watcher will not run anymore,
If you were to call the vm.msg=‘test’
only the secon will run
WATCHING COMPLEX OBJECTS(NON PRIMITIE VALUES)
created() {
this.$watch(
// ‘list’,
// ‘car’,
// ‘list.length’,
// ‘list[0]’, Does not work
‘car.brand’,
(newval, preval) => {
console.log(“First watcher in action”);
console.log(preval + ’=>’ + newval);
},
{
immediate: true,
deep: false,
}
);
},
SETTING A GETTER TO WATCH COMPLICATED RESULTS
created() {
this.$watch(
() => {
// Now we can watch multiple properties with a single watcher
return [this.city, this.nation ];
// You can also watch a mathematical expression without any problem
return this.a+this.b
// You can also watch every elements from a list by converting it from a proxy to an array
return […this.list]
// Yes you can also watch a single instance of a list
return this.list[0]
},
(newval, preval) => {
console.log(“First watcher in action”);
console.log(preval + ’=>’ + newval);
},
{
immediate: true,
deep: false,
}
);
},
==================================================================
LOCAL AND GLOBAL COMPONENTS
{{title}}
let app = Vue.createApp({
data() {
return {
title: “Root Componenet”
};
},
// Local Component, works only within the root component
components: {
localComp: {
name: ‘local_comp’,
data() {
return { title: “Local comp in root comp” };
},
template: ”
{{title}}
“,}
}
});
// Global Component works outside and can be resused everywhere you want ,
app.component(‘childComp’, {
name: ‘child_comp’,
data() {
return {
title: ‘Child Component’
};
},
template: “#child_temp”
});
let vm = app.mount(‘#vue_app’)
The Root componenct interact with the vue on the app.mount(…)
a child component interract with the vue on a template
EXCHANGING Data FROM PARENT TO CHILD COMPONENT
Using PROPS
===========================
{{msg}}
{{title}}
DEFINING PROPS USING THE OBJECT SYNTAX
app.component(“childComp”, {
beforeCreate() { console.log(this.$props); },
props: {
mail: {
default: ‘Default primiteive value’,
// Factory patters for reference type values
// We can limit the acceptable values too!
type: String,
// Or Set Multiple acceptable values
type: [String, Number, Boolean, Array, Object, Function, Date, Symbol],
// You can also set a validator to check the values authenticity
validator(val) {
// failed validator only generates a warnings
console.log(“validator:” + val);
// Not returning true, the chec will fail (false of nothing will make the test fail)
console.log(this);
throw new Error(“failed to validate shit:” + val);
return true;
}
}
},
CUSTOM EVENTS SENDING DATA FROM A CHILD COMPONENT TO IT’S PARENT COMPONENT
Sending data from child to parent component require custom event.
Custom events are declared in the child component, we emit it using the child coponent emit method
this.$emit(“custom event”,pieceOfDataBoundedToTheEmitedEvent)
Example:
=========
{{msg}}
<child-comp ref=“cc” @relay=“msg=$event”>
let app = Vue.createApp({
data() {
return {
title: “Title of the Root Componenet”,
msg: “Root Component message”,
car: { brand: “Toyota”, model: “Supra” }
};
},
});
app.component(“childComp”, {
emits: [‘relay’],
methods: {
send() {
this.$emit(‘relay’, this.msg);
}
},
data() {
return {
msg: ‘child Comp’
};
},
name: “child_component”,
template: “#child_temp”
});
let vm = app.mount(‘#vue_app’)
s
BUILDING A TWO WAY DATA PATH BETWEEN A PARENT COMPONENT AND ITS CHILD COMPONENT
{{msg}}
<child-comp ref=“cc” :mail=“msg” @relay=“msg=$event”>
let app = Vue.createApp({
data() {
return {
title: “Title of the Root Componenet”,
msg: “Root Component input tag”,
car: { brand: “Toyota”, model: “Supra” }
};
},
});
app.component(“childComp”, {
props: [‘mail’],
emits: [‘relay’],
methods: {
send($event) {
this.event.target.value);
}
},
data() {
return {
msg: ‘child Comp’
};
},
name: “child_component”,
template: “#child_temp”
});
let vm = app.mount(‘#vue_app’)
SLOTS BASICS
-------------
Slots allow us to display the parent component data using the child component withouth actually sending anything into the child component
TRANSITIONS AND ANIMATION
LEAVE and ENTER transition
-Vue offer us 6 transition classes
-And transition class hooking points[9]
-And Transition events [11] hooks