- Templates are a big part of VUE
- Separate UI from the business logic
- Vue is responsible for compiling the templates into what user sees
- minimizes amount of code to write
- protect you from changes
- UI and data are bind together by declarative bindings
- they hold ui and data together
- simplify development
- can separate working on ui from working on backend
- remove the burden of managing the DOM (things update automatically)
Size of vue: 74.8 kb
Run-time performance
- VDOM: Virtual DOM
- vue uses a virtual document object model - this makes it run fast
- it does not blocking the user while it updates the dom
- virtual dom minimizes the number of calculation browsers needs to make to change the page the user sees
- it is a lightweight copy og the actual DOM
- it is responsible for what needs updating
- it batches the updates (instead of performing each update individually)
Browser support:
- Supports legacy browsers
- SupportsChrome, Apple, Microsoft, Mozilla
- Supports Safari on ios, Android
Licensing: MIT (like jQuery, Angular)
- Vue.js (Core library)
- via CDN - unpkg - it is kept in sync
- add the bottom of the body html
- Axios (HTTP requests)
- library for http requests - recommended by axios
- reference from unpkg
- ability to make http request sin the vue apps
Example of AXIOS request to weatherAPI: https://www.sitepoint.com/fetching-data-third-party-api-vue-axios/
var weatherData = new Vue({
el: '#weatherData',
data: {
results: []
},
mounted() {
axios
.get('http://localhost:3000/api/data')
.then(response => (this.results = response.data.data.reverse()));
}
});
- invoke the Vue constructor function
- instance of Vue = view (has a role)
var weatherData = new Vue(){
el: 'weatherData',
data:{
}
}
- this code initializes weatherData
- if you visit a page with this in the script html, you see nothing
- Vue constructor
new Vue
, was imported from the vue js core library from above - can pass options to constructor to make weatherData more functional
var weatherData = new Vue(){el:'weatherData', data:{}}
Mounting weatherData onto the DOM
-
serves as the bridge between the UI and data we want to show
-
mounting is when VUEs virtual dom is shown to the user
-
this is when the view becomes visible to the user
-
to mount an instance of VUE onto the DOM, use the
el
option -
el identifies the HTML element the vue instance will be mounted onto
-
2 choices
- assign to an html element:
el: document.getElementById('weatherData')
- or via a css selector:
el: '#weatherData'
- assign to an html element:
-
-
mounting an instance of view replaces the actual HTML DOM element with the VUE generated DOM
- don't set el option to html or body elements
Lifecycle of a view Has 4 stages
- creation
- mounting
- updating
- destroy
Each stage has 2 hooks: before and after
- each hook is created in this format: beforeCreate / created or beforeMount / mounted
Creation:
- when you call the view constructor
- beforeCreate hook fires first
- after implementing logic in the beforeCreate hook, it gets executed
- state gets initialized (loading properties, event handlers, data and watchers)
- after the state gets initialized, the created hook will fired
- after view has completed its creation stage, the template is compiled
- once template is compiled, the view's life-cycle move into the mounting stage
Mounting:
- responsible for inserting the view into the dom
- beforeMount is triggered first
- custom code can be executed here
- view's virtual dom gets created
- this dom replaces the actual html dom identified by the el property discussed above
- virtual dom enables UI changes to happen fast
- after this swap, the mounted hook gets fired
- after the view completes the mounting stage, it begins listening for changes to the data
- view spends most of its time in this listening stage
- beforeMount is triggered first
Updating:
- if any property in the initialized data object gets changed, the view goes through the update stage
- responsible for modifying the virtual DOM and re-rendering the UI
- if a data property in vue, that's bound to the UI is modified, the beforeUpdate hook is fired
- the beforeUpdate can execute custom code
- once completed, this stage re-renders the virtual dom with the fewest number of changes necessary
- these changes are called patches
- once patches are generated, the virtual DOM gets updated
- UI on screen gets updated
- updated hook gets fired
Destroy:
- VUE instance method - this stage happens only if the method is called on the VUE instance
- when this is called the view enters in the destroy stage
- starts with beforeDestroy and any custom code being executed
- moves to tearing down the virtual DOM
- stop watching for changes to data
- vue instance will trigger the destroyed hook
- destroy stage is not called if user navigates to a different page
- created with HTML (valid html)
- data that drives these templates are defined in the Vue instance it
- to drive the view we need data
data property: object with 2 roles
- at design time it represents the schema
- at runtime it serves as the model
var weatherData = new Vue(){
el: 'weatherData',
data:{ // <- data property //
appName: 'WeatherData' // Plain Old JS Object (POJO)
} //
}
-
data property is a POJO
- nothing is unique to Vue in that
- it means I can access view data from outside of the Vue
weatherData.data.appName
-
VUE automatically creates shortcuts to data properties
-
means I can work with VUE's data like this:
weatherData.appName
-
apparently it's not as easy as this in other UI frameworks
- VUE loads them during the creation stage (see life cycle)
- for each property in the data object, VUE uses JS built in Object.defineProperty method to create Getters / Setters
- this enables change notifications and dependency tracking under the covers
- this means that when the data property changes, everything that relies on it will know about the change
- this means making the property REACTIVE
Caveats:
- can only modify properties defined in the data object
- can't add properties to the data object at runtime
- can't remove properties from the data object at runtime
- because data properties are converted to getters/setters during the creation stage
- this all shows how the data object of VUE serves as a schema, like when creating a database table
- if you know you need a property in the view eventually, but not when the view is created, just assign it to null or empty value
- in browser console, data properties with JS objects are formatted differently, because VUE adds getters/setters
- to get around this and be able to read the objects created by vue, install an extension in chrome: vue-devtools - we'll be able to see JS objects
- can be anything
- use js naming rules: start with letter, case-sensitive, cannot use reserved words
- SPECIFIC TO VUE: property names should not start with $ or _
- these can conflict with VUE internal operations
- each property in the data:{} aka data object has a value
- the value will be shown in the view
- if i modify a value, the UI will async change to reflect the change
- dependency tracking and change modification is important
- data property values should JUST BE DATA
- supports primitive values: numbers, string, dates arrays
- does not support native objects: Number, String, Date, Array
- SICK with RAW DATA
- this simplifies state management
- once data object is defined, we can bind it to a template
Binding text: plain text
- semantic syntax
- declarative syntax
- onetime bindings
Semantic binding
- create a data binding by using a semantic syntax: use {{ ... }}
Example:
<h1>Some text {{appName}}</h1>
<h1>{{appName}}</h1>
<h1>{{appName}} {{someOtherData}}</h1>
var weatherData = new Vue(){
el: 'weatherData',
data:{ // <- data property //
appName: 'WeatherData' // Plain Old JS Object (POJO)
} //
}
<h1>Some text {{appName}}</h1>
- if this code is executed, vue would look for {{..}} and execute/replace them with actual values from the data object
- VUE looks inside each pair of {{...}} and evaluate the code
- in this case, code is a variable called
appName
- vue looks for
appName
in the data object on the vue instance - if a property named appName is found, vue replaces {{appName}} with its value at runtime
- if no property is found in the data object, the replacement is a "" and a warning in console window
- vue looks for
- this is called interpolation
Declarative bindings
- created via directives
- directives are predefined tokens that tell Vue to do something specific to a DOM element
- they provide a way to reactively update the DOM when an associated value changes
- vue has several directives from the box
- they all begin with
v-
Example: v-text
- helps interpolate a property value as the text of an HTML element
Example:
<h2 v-text="appName"></h2>
- at runtime VUE assigns the text content property of the html element to the property value
- this bind the element's entire content to a property
- you can bind to part of an element's content by using the semantic syntax {{...}}
One time bindings
- helps optimize view performance
- use v-once in the html tag when you don't need to listen to changes
- this tells vue to render the element is hosting it
<h2 v-once>
to run only once - this skips the updated stage of the cycle - any child of an element with the once directive will also be rendered only once
<h2 v-once>{{appName}}</h2>
- when the page loads, the appName binding takes effect = value is displayed
- if you try to change the appName property by dowing weatherData.appName = "something else" - will not work
- can show plain html inside the element by adding the html directive to an element
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>'
}
}
- appName is now a link, and tipically you wouldnt do this
- you want to keep the ui separate to the data
- but you might get data some a webservice that might include HTML
- to bind an html to a template you can use the html directive
<h2 v-html="appName"></h2>
- v-html updates the innerHTML property of the element it's attached to
v-bind
- binds html attributes
- can bind data property values to HTML attributes
- {{...}} can;t be used inside HTML attributes
- must use a bind directive to the src attribute
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png'
}
}
<div id="weatherData">
<img v-bind:src="appLogo" />
</div>
- can get css props from a JS object during binding
- similar to traditional CSS approach
- style string is a JS object
- each property name of the object represents the name of a CSS property
- value associated with each property can be a property name or a static value
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png',
color: '#FF6A00'
}
}
<div id="weatherData">
<h2 v-bind:style="{color:color}">{{appName}}</h2>
</div>
- binding to the css color property
Problem
- you can't set variables with dashes in JS objects
v-bind:style="{color:color}"
<- this is the JS object which is used to assign css properties in the style tag
Solution: To add something like font-family use camel case
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png',
color: '#FF6A00',
appNameFontFamily: 'someFont'
}
}
<h2
v-text="appName"
v-bind:style="{
color:color,
fontFamily:appNameFontFamily
}"
/>
The above can be refactored to a data value property like this: (cleans up code)
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png',
appStyle:{
color: '#FF6A00',
fontFamily: 'Verdana',
margin: 0
}
}
}
<h2 v-text="appName" v-bind:style="appStyle" />
- styles shared across multiple elements
- ex: color of an element shared with other elements
- when we need to use multiple style definitions during binding: use a JS array
- it is a way of separating styles and make them reusable across multiple elements
- properties are stacked from left to right
- latest property setting has the greatest precedence
Example:
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png',
accentColor:{
color: '#FF6A00',
},
headers: {
fontFamily:'Verdana',
margin: 0
}
}
}
<h2 v-text="appName" v-bind:style="[accentColor, headers]" />
Strive to keep CSS separate from data
- instead of defining CSS properties in the data object
- define them in standards CSS classes and bind to those classes
- a way of getting CSS classes from a JS object
- improvement from binding to css properties
- helps maintain separation between design and data - keep code clean and maintainable
Example: code above refactored
DATA Object
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName: '<a href="/">WeatherData</a>',
appLogo = '/public/img/logo.png',
accentColor: 'accent-color',
headers: 'headers'
}
}
UI
<style>
.headers {
font-family: 'Verdana';
margin: 0;
}
.accent-color {
color: #ff6a00;
}
</style>
<h2 v-text="appName" v-bind:class="[accentColor, headers]"></h2>
- separated UI from data
- not generating html and css from js, we complement HTML and CSS
- this approach works by prepending the class attribute withe the bind directive
v-bind:class=
- similar to binding to the style attribute
v-bind:style
- can combine a class attributes to a JS array or a JS object
Differences:
- example binds class attribute to a JS array
- each element in array is name of a property
- the property references the name of an actual CSS class
accentColor
orheaders
- at runtime, H2 element becomes this:
- we can make this
v-bind:class="[accentColor, headers]">
intov-bind:class="headerStyles">
and adapt the data object of the VUE instance
Binding to a JS object
<h2
v-text="appName"
v-bind:class="{
'headers:' true //<name:headers and flag true
}"
></h2>
- this is a way to conditionally apply CSS classes to an element
- code above binds the headers css class to the h2 element via a JS object - by setting it to true we accomplish this
- headers css class gets added the the h2 element in the update stage
- can use conditionals from the data object to assign css attributes to an html element
DATA OBJECT
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName:"WeatherData",
isOnline: false //<-this
}
}
UI CSS
<style>
.headers {
font-family: 'Verdana';
margin: 0;
}
.accent-color {
color: #ff6a00;
}
</style>
HML and bindings
<h2
v-text="appName"
v-bind:class="
'headers': true,
'accent-color': isOnline //<- sets condition here of when to apply the accent-color class
"
></h2>
- now, when the data property isOnline changes, the UI will reflect the change
- expression is a line of code that produces a value
- only expressions can be used in bindings
- use a JS expression in a template by using {{..}}
- they are evaluated withing the context of a view
- when evaluated, an expression is scoped to the hosting view instance
Example
<h2 v-test="appName" , v-bind:style="{color:isOnline? '#FF6A00' : '#000'}"></h2>
This is an expression: {color:isOnline? '#FF6A00' : '#000'}
- determines the color of the header
- uses the isOnline property of the data field to make that decision
- style is applied conditionally at runtime
- if the value isOnline changes, the expression will be reevaluated
- expressions run within a sandbox - gets executed in an isolated environment
- global variables can't be used in expressions, like $
- no way to whitelist them
- they conflict with VUE itself
- collect data through forms
- bind to forms in view
- use input bindings to collect data
- clean up data when collecting it - remove whitespace / perform utility type tasks
- modify bound values
- create a two way binding to collect data
- use the v-model directive
- can be used with input text, text area and select tags
- can use the model directive with text fields, checkboxes, radio buttons and drop down lists
input tag
- enter a search query in an html input element
- in vue, you can bind to the input element using a v-model directive like this:
<input v-model="query" placeholder="Search...">
- this binds to an html input element
- this assumes there is a property in data scope called query
- query property bridges the UI and the data with the help of the model directive
var weatherData = new Vue(){
el: 'weatherData',
data:{
appName:"WeatherData",
query: '' //<-this is the query element for the input
}
}
using v-model directive to bind the input to the query in data property
<div id="growler">
<input v-model="query" placeholder="Search..." />
<div>Searching for: {{query}}</div>
</div>
- with this, if you type something in the input area, the query will be updated and update the ui accordingly
- this is the magic of 2 way binding - change notifications impact the ui
Textarea Example:
var weatherData = new Vue({
el: '#weatherData',
data: {
query: '',
emailMessage: ''
}
});
<input v-model="query" placeholder="Search..." />
<div>Searching for: {{ query }}</div>
<textarea v-model = "emailMessage"></textarea>
<div>Email text: {{ emailMessage }}</div>
Check boxes
- choose a single value
- choose multiple values - checkbox list
Example:
<input type="checkbox" v-model="isPowerSyntaxEnabled" />
- input type is set for checkbox
- and binding is to isPowerSyntaxEnabled
With multiple options
- you have to create a property that holds an array, and each checkbox selected by client will save its value to this array.
- once that is done you can show the selected checkboxes
- this is updated live
Example:
var weatherData = new Vue({
el: '#weatherData',
data: {
isPowerSyntaxEnabled: false,
searchIndex: []
}
});
<label><input type="checkbox" v-model="searchIndexes" value="temperature" />Temperature</label>
<label><input type="checkbox" v-model="searchIndexes" value="pressure"/>Pressure</label>
<label><input type="checkbox" v-model="searchIndexes" value="humidity"/>Humidity</label><br>
<small>Selected: {{selectedIndexes}}</small>
Drop down lists
- created with select element
- to make a single choice
- to make multiple choices
- use v-model directive
Example:
var weatherData = new Vue({
el: '#weatherData',
data: {
selectedSearchIndex: 'temperature'
}
});
<div id="weatherData">
<select multiple v-model="selectedSearchIndex">
<option value="temperature">Temperature</option>
<option value="pressure">Pressure</option>
<option value="pressure">Humidity</option>
</select>
<p>Selected: {{selectedSearchIndex}}</p>
</div>
- vue syncs a value input by the user with the data whenever an input event is fired
- input event is triggered when an html input or select element collects user input
- this occurs after the keypress html dom event but before the keyup event
- once the keyup event is fired, the value input from the user can be modified
- VUE provides 2 modifiers: trim string values and automatically convert input values to numbers
To use it, append .trim to the model directive:
<input v-model.trim="query" placeholder="Search..." />
- once the white space is removed, the modified value is sent to the query property in the Vue data property
Use .number modifier to cast user input to a number:
- useful as html elements always return strings
- this tries to get a Number object out of the input value
- to use number modifier append .number to the model directive
<input v-model.number="result" placeholder="2+3=" />
- this will take a value, cast it to a number and send it to the result property in the Vue data property
- it is cast to float - uses a js parseFloat
- property will be a number if at least the first character of the input is a number
- leading and trailing whitespace ignore
- if leading char is not a number, than the value will be interpreted as a string
- example: do a search when the input has changed only, not with every letter typed
- it fires after the input event has lost its focus
- the data model updates after the input field loses focus: this is called lazy binding
- append .lazy modifier to the model directive
Example:
<input v-model.lazy="query" placeholder="Search:..." />
Can chain modifiers
- remove white space after the query has changed
Form elements
<input v-model="query" placeholder="Search..." />
<div>Searching for: {{ query }}</div>
<textarea v-model="emailMessage" placeholder="Message..." /></textarea>
<div>Email text: {{ emailMessage }}</div>
<label><input type="checkbox" v-model="searchIndexes" value="temperature" />Temperature</label>
<label><input type="checkbox" v-model="searchIndexes" value="pressure"/>Pressure</label>
<label><input type="checkbox" v-model="searchIndexes" value="humidity"/>Humidity</label><br>
<small>selected: {{searchIndexes}}</small>
</br>
</br>
<select multiple v-model="selectedSearchIndexes">
<option value="temperature">Temperature</option>
<option value="pressure">Pressure</option>
<option value="humidity">Humidity</option>
</select>
<p>Selected: {{selectedSearchIndexes}}</p>
- attach to events
- use the v-on directive
- listens for events in the html dom
Example
<button v-on:click="executeSearch">Search</button>
- this executes a search when the button is clicked
- using the v-on directive to attach to the button click event
- this event can be any JS event listener
- custom JS can be run when an event is triggered
- in this example I'm using executeSearch custom JS
- executeSearch is the name of a JS function
- this can be found in the methods property of the VUE instance
- this function must be defined within the scope fo the view
- for this you must set up the methods option
Example:
var menu = new Vue({
el: '#menu',
data: {
componentName: 'Menu',
list: ['Option 1', 'Option 2']
},
methods: {
retrieveWeatherData: function() {
alert('Weather data retrieved');
}
}
});
<input v-model="query" placeholder="Search..." />
<div>Searching for: {{ query }}</div>
<button type="button" v-on:click="executeSearch">Search</button>
- include an optional event parameter in the method
- this shows the query
- and also the text of the button aka event.target.innerText Example:
methods: {
executeSearch: function(event) {
alert("Query: " + this.query + '"Button:"' + event.target.innerText + '"');
}
}
- use inline JS statement
- expand the the event reference in the on directive
Example
- on a server, search might assign a token to a user
- that token can be passed to the eventHandler
- to do this, expand the event reference
var growler = new Vue({
el: '#weatherData',
data: {
query: ''
},
methods: {
executeSearch: function(t, e) {
var msg = 'Token: ' + t + '\n' +
'Query: ' + this.query + '\n' +
'Button: ' + e.target.innerText
;
alert(msg);
}
}
<button
v-on:click="executeSearch(12345, $event)"
type="button"
class="btn btn-primary"
>
Search
</button>
- $event is a reserved variable in vue
- will give me access to the html dom event that was triggered
- provides same event object as above
- only diff si that here we are passing it to the event handler with another parameter
- Event propagation
- React to keyboard and mouse events
- Consider special keys