- Options API
- Composition API
SFC (Single-File Component) or Html mode. SFC is what most use when they use Vue with a build step
SFC is when HTML, css, and js are in a single file, .vue file
-
declarative rendering: using a template syntax that extends HTML - core feature of Vue.
-
State that can trigger updates when changed are considered reactive - reactive state is held in compoenents.
You can declare reactive state using the data component option.
export default {
data() {
return {
message: 'Hello World!'
}
}
}
The message prop will be available in the template.
<h1>{{ message }}</h1>
BTW, we can use any JS expression
<h1>{{ message.split('').reverse().join('') }}</h1>
- In Vue, mustaches are only used for text interpolation.
- To bind an attribute to a dynamiv value use the
v-bind
directive <div v-bind:id="dynamicId"></div>
- To bind an attribute to a dynamiv value use the
A directive is a special attribute that starts with v-
prefix.
- Whatever is after the colon is the 'arg'. in this case 'id'
Because v-bind:
is used the most, the shorthand is below
<div :id="dynamicId"></div>
- Listen to DOM events using the
v-on
directive
<button v-on:click="increment">{{ count }}</button>
- Because of the frequent use of listening to DOM events, below is the shorthand
<button @click="increment">{{ count }}</button>
@ is the event listener shorthand.
export default {
data() {
return {
count: 0
}
},
methods: {
increment() {
// update component state
this.count++
}
}
}
- Inside a method, we can access the component instance using
this
. The component instance exposes the data properties declared BYdata
. Update the state by mutating these properties.
- Using
v-bind
andv-on
together, we can create two-way bindings on form input elements.
<input :value="text" @input="onInput">
methods: {
onInput(e) {
// a v-on handler receives the native DOM event
// as the argument.
this.text = e.target.value
}
}
<input v-model="text">
v-model
auto syncs the value with the bound statev-model
works not only on text inputs but also on checkboxes, radio, select dropdowns
- Using the
v-if
directive to conditionally render an element- Also we can use
v-else
andv-else-if
- Also we can use
- use the
v-for
directive to render a list of elements based on a source array:
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>
</ul>
- the key allows Vue to accurately move each
li
to match the position of its corresponding object in the array.
- Computed property is a property that is reactively computed from other properties using the
computed
option. - A computed property tracks other reactive state used in its computation as dependencies,
- it caches the result and automatically updates it when its depenendies change.
- There will be cases where we need to manually update the DOM.
- a template ref, is a reference to an element in the template, we can reference it using the special
ref
attribute
<p ref="p">hello</p>
The element will be exposed on this.$refs
as this.$refs.p
. You can only access it ** after the component is mounted **
To run the code after mount, we use the mounted
option
export default {
mounted() {
// component is now mounted.
}
}
- Lifecycle hooks allow us to register a callback to be called AT certain times of the components lifecycle.
- other hooks are created, and updated
- Watchers perform 'side effects' reatively, ie logging a number to the console wien it changes
export default {
data() {
return {
count: 0
}
},
watch: {
count(newCount) {
// yes, console.log() is a side effect
console.log(`new count is: ${newCount}`)
}
}
}
Above, we are using the watch option to change the count
property.
- Watch callback is called WHEN
count
changes, AND receives the new value as the argument
A better example would be fetching new data when an ID changes.
<script>
export default {
data() {
return {
todoId: 1,
todoData: null
}
},
methods: {
async fetchData() {
this.todoData = null
const res = await fetch(
`https://jsonplaceholder.typicode.com/todos/${this.todoId}`
)
this.todoData = await res.json()
}
},
mounted() {
this.fetchData()
},
watch: {
todoId() {
this.fetchData()
}
}
}
</script>
<template>
<p>Todo id: {{ todoId }}</p>
<button @click="todoId++">Fetch next todo</button>
<p v-if="!todoData">Loading...</p>
<pre v-else>{{ todoData }}</pre>
</template>
- My understanding the above. The button, increments todoId, with a simple ++.
- the watch is pointed only at that property, It notices a change, and then will fire fetchData.
- fetchData is called, and utilizes that updated property.
In Real SPA apps, there are nested components
- A parent component CAN render another component in its template AS a child component. * To use a child component, Import the component
import ChildComp from './ChildComp.vue'
expore default {
components: {
ChildComp
}
}
You must also register the component using the components
option.
Then we can use the component in the template as <ChildComp />
- A child component can accept input from the parent via
props
. * First it needs to DECLARE the props it accepts.
// in child component
export default {
props: {
msg: String
}
}
A child component can also emit events to the parent.
export default {
// declare emitted events
emits: ['response'],
created() {
// emit with argument
this.$emit('response', 'hello from child')
}
}
The first arg to this.$emit()
is the event name. Additional args are passed on to the event listener
** The parent can LISTEN to child-emitted events using v-on
**
<ChildComp @response="(msg) => childMsg = msg" />
Here the handler receives the extra arg from the child emit call AND assigns it to local state
Parent component passing down template framents to the child via slots
<ChildComp>
This is some slot content!
</ChildComp>
In the child component, it can render the slot conent from the parent using the <slot>
element as outlet
<!-- in child template -->
<slot/>
Content inside the slot
outlet will be treated as ** fallback ** content: it will be displayed if the parent did NOT pass down any slot conent
<slot>Fallback content</slot>