Recently, I dedicated some time to revisit Vue.js, the first JavaScript framework I explored several years ago. Over the past two years, the framework has evolved, and revisiting it has provided me with a fresh and enriched perspective on its capabilities and applications. I am thrilled to share my insights and experiences with you!
14. The Life Cycle of A Component
There are many hooks in a Vue.js Component. Typically, there're in a certain order as follows:
-$$-
In a Vue.js component, a variety of lifecycle hooks are available, which typically follow a specific sequence for orderly execution:
- createApp
- breforeCreate()
- created()
- beforeMount()
- Mounted()
- Mounted Vue instance
- Data Changed
- beforeUpdate()
- updated()
- Instance Unmounted
- beforeUnmount()
- unmounted()
You can use these hooks when create a new instance:
-$$-
You can leverage these lifecycle hooks during the instantiation of a new Vue.js component to execute code at specific stages of the component's lifecycle.
const app = Vue.createApp({
data() {
return {};
},
beforeCreated() {
console.log("beforeCreated:", beforeCreated);
},
created() {
console.log("created:", created);
},
beforeMount() {
console.log("beforeMount:", beforeMount);
},
Mounted() {
console.log("Mounted:", Mounted);
},
beforeUpdate() {
console.log("beforeUpdate:", beforeUpdate);
},
updated() {
console.log("updated:", updated);
},
beforeUnmount() {
console.log("beforeUnmount:", beforeUnmount);
},
unmounted() {
console.log("unmounted:", unmounted);
},
});
Currently, we can manually invoke unmount hook in Vue instance.
-$$-
Currently, in Vue.js, it is possible to manually trigger the 'unmount' lifecycle hook for a component instance.
app.mount("#app2");
setTimeout(() => {
app.unmount();
}, 3000);
I think the colors in the following card is very beautiful and I must record it!
-$$-
I find the colors in the following card exceptionally appealing, and I must capture this aesthetic!
15. How to Create a Brand New Vue Component
Why do we need to use Vue components? A simple but powerful answer is when using component, it's much easier than using array to organize tags in our Vue instance.
-$$-
Why opt for Vue components? A straightforward yet potent reason is that employing components simplifies the organization of elements within our Vue instance, making it more efficient than managing tags through arrays.
You can use the method component
in aa Vue instance to create its component, as following code shows:
-$$-
You can utilize the component
method within a Vue instance to instantiate its components, as demonstrated in the following code example:
app.component("friend-contact", {
data() {
return { detailsAreVisible: true };
},
methods: {
toggleDetails() {
this.detailsAreVisible = !this.detailsAreVisible;
},
},
});
But where is the html code, as a component, it must render some doms in the document, right?
-$$-
But where is the HTML code? As a component, it must render some elements in the document, correct?
In a Vue.js component, we can use property template to define a html template.
-$$-
In Vue.js components, we can define an HTML template using the template property.
app.component("friend-contact", {
template: `<span :style="styleObj" >Use Vue Component</span>`,
data() {
return {
detailsAreVisible: true,
};
},
computed: {
styleObj() {
return {
display: this.detailsAreVisible ? "block" : "none",
};
},
},
methods: {
toggleDetails() {
this.detailsAreVisible = !this.detailsAreVisible;
},
},
});
The method component exists in a Vue instance but Vue, so you can only use the component in the scope of this Vue instance.
-$$-
The component method is available within a Vue instance, which means that the components you create using this method are scoped to and can only be used within that specific Vue instance.
After defining a component, you can use its selector directly in its parent component or in root component.
<section id="app">
<ul>
<friend-content></friend-content>
</ul>
</section>
16. Vue Cli
When comes to components in Vue, the project changes to be very complicated very soon. So, it's not properly to continue writing code in an index.html file. What we need is a more powerful tool named @vue/cli
.
-$$-
When dealing with components in Vue, projects can quickly become complex. As a result, it's no longer advisable to continue writing code solely in an index.html file. What we need is a more robust tool, namely @vue/cli, to streamline the development process.
There are at least 3 advantages when you decide to use @vue/cli
:
- we need to use
http
protocol notfile
- we can use some model javascript through adding pollify
- we can deploy our project
@vue/cli
offers a development web server- better developer experience:
- reload/update automatically
- auto-completion and hints
- split the code using export/import features in ES6
-$$-
There are several compelling reasons to adopt @vue/cli
in your Vue projects:
- Protocol Standardization: It enforces the use of the
http
protocol instead of thefile
protocol, ensuring a more production-like environment. - Enhanced Modularity: It allows for the incorporation of modern JavaScript features through tools like Babel, facilitating the use of features such as modules.
- Deployment Capabilities: It simplifies the process of deploying your project to various environments.
- Integrated Development Server:
@vue/cli
provides a built-in development web server that streamlines the development workflow. - Enhanced Developer Experience:
- Automatic Reloading: The server automatically reloads or updates the page upon code changes.
- Intelligent Code Assistance: It supports auto-completion and inline hints to speed up development.
- Modular Code Organization: It leverages ES6's export/import syntax for cleaner and more maintainable code.
How to use the tool
npm install -g @vue/cli
vue create vue-first-app
After we use @vue/cli to establish a vue3 project, we can see a entrance named main.js in the src directory.
-$$- After utilizing @vue/cli
to initiate a Vue 3 project, one can observe an entry point file named main.js
within the src
directory.
// main.js
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#app");
From the bottom to the top, let's compare the code line by line with the code in index.html
-$$-Starting from the bottom and moving to the top, let's conduct a line-by-line comparison of the code with that in index.html
.
const options = {
data() {},
methods: {},
computed: {},
};
Vue.createApp(options).mount("#app");
We can easily notice that the biggest difference is all about options. Now, the options is replaced by the export thing in a new file type .vue
.
The vue file has 3 important parts: template, script and style.
So, why vue file can be recognized and used by nodeJS? That's because the package tool webpack translates the code in vue file into standard Javascript.
-$$-Upon careful examination from the bottom up, comparing line by line with the contents of index.html
, it becomes evident that the primary distinction lies in the concept of 'options'. In the new .vue
file format, these options are supplanted by an 'export' statement.
The .vue
file comprises three pivotal sections: the template
, script
, and style
.
The reason why .vue
files are intelligible and executable by Node.js is due to the bundling tool Webpack, which transpiles the code within .vue
files into standard JavaScript. -$$-
17. Use Components in Vue Project
If you want to register a component globally in your Vue project, you can do as follows:
-$$-To achieve global registration of a component within your Vue project, you can proceed with the following steps:
import { createApp } from "vue";
import App from "./App.vue";
import FriendContact from "./components/FriendContact.vue";
const app = createApp(App);
app.component("friend-contact", FriendContact);
app.mount("#app");
After doing that, you can use <friend-contact>
tag in this project anywhere.
-$$-Upon completion of the aforementioned process, you will be able to employ the <friend-contact>
tag ubiquitously throughout the project.
Change the code in App.vue as follows:
-$$- Modify the contents of App.vue
with the subsequent adjustments:
<template>
<friend-contact></friend-contact>
</template>
and delete the original HelloWorld.vue and in components directory, we need to create a brand new file named FriendContact.vue
-$$- Subsequently, eliminate the original HelloWorld.vue
within the components directory, and in its stead, craft an entirely new file christened FriendContact.vue
.
<template>
<p>This is my first Vue component!</p>
</template>
<script>
export default {
name: "friend-contact",
};
</script>
<style>
p {
color: red;
}
</style>
18. Communication within Components
I personally think the props and states organization is not as clear as it in React.js or in Angular.js. Because, in the later ones, they use syntax to avoid any potential error, but in Vue.js, you must ensure that you don't create a variable in data with the same name of a variable in props.
-$$-Personally, I find the delineation of props and state to be less distinct in Vue.js compared to React.js or Angular.js. In the latter frameworks, syntactic conventions are employed to preempt any prospective errors. Conversely, in Vue.js, it is incumbent upon the developer to ensure that no variable within the data
option is given the same name as one within props
to avert potential conflicts.
You must bear in mind that there is only one direction of the data flow that the data should pass from parent component to child component. So that, if you change the data in child components, an error will popup:
-$$-It is imperative to remember that data flow in Vue.js is unidirectional, with data cascading down from parent to child components. Consequently, any attempt to mutate the data within child components will result in an error.
Unexpected mutation of"isFavorite" prop
But what if you do want to change the data in child component? There's a common solution: you can use the value of variable in props as the initial value of the corresponding variable in data(or I should call it as state).
-$$-However, if the necessity arises to alter data within a child component, a prevalent strategy can be employed: you can initialize the corresponding variable in the data
(or more aptly, state) with the value inherited through props
.
props: ['outerVisible'], data(){ return { innerVisible: this.outerVisible, } }
AS the above code shows, we save the value of outerVisible into the variable innerVisible. Remeber the this.
.
-$$-As demonstrated in the aforementioned code, we assign the value of outerVisible
to the variable innerVisible
. Take note of the use of this.
when referencing Vue instance properties.
Assign Type to Props
Although we are not writing typescript code, we can also confine the type of variables in props:
-$$-Even though we are not authoring TypeScript code, it is still feasible to restrict the types of variables received through props:
export default {
props: [
name: {type: String},
phoneNumber: String,
emailAddress: {type: String, required: true},
isFavorite: {type: String, required: false, default: '0'},
sex: bool,
age: function(){},
title: {
type: String,
required: false,
default: '1',
validator: function(value) {
return typeof value === 'number' && value >= 0;
}
}
],
}
How to transmit bool
There is a little trick when you need to transmit value in boolean type. You can not pass it directly, otherwise you will get a string, so you need some extra trick.
-$$-There exists a subtle trick when it comes to passing values of boolean type. Direct transmission is not viable, as this would result in the value being interpreted as a string. Consequently, an additional trick is required to ensure the correct type is maintained.
<friend-contact :bool="true"> </friend-contact>
Use key attribute when you want to use v-for
directive
<friend-contact v-for="friend in friends" :key="friend.id"> </friend-contact>
How to transmit data in a reverse direction
What if I do really want to pass data from child component to parent component? As I said above, you can not change the value of variables in props directly. So we need another method to do so.
-$$- What if there is a genuine requirement to convey data from a child component to its parent? As previously mentioned, directly modifying the value of prop variables is not permissible. Therefore, an alternative approach is necessary to facilitate this data transmission.
Child component can invoke the funtions tansmitted by parent component, during this process, we can pass the data from child component to its parent component.
-$$- A child component has the capacity to invoke functions that are transmitted by its parent component. Within this process, data can be passed from the child back to the parent component.
In child component, we can invoke the method in parent component through a indirect way:
-$$- Within the child component, methods of the parent component can be invoked through an indirect approach:
// invoke in child component this.$emit('communication-topic'); // receive in
parent component <child @communication-topic="handleInvoke"> </child>
Because @
means click
in nature, so through this way, we actually customize a new event named @communication-top
.
-$$- Given that @
is inherently synonymous with the click
event, by employing this method, we effectively create and customize a new event designated as @communication-top
.
Use emits to refactor communication process
You can use emits array to define callback when child component emits a event.
-$$-You can utilize the emits array to specify callback functions that should be triggered when a child component emits an event.
<script>
export default {
name: "friend-contact",
emits: {
"button-clicked": function () {
console.log("print when button clicked!");
return true;
},
},
methods: {
invokeEmit() {
this.$emit("button-clicked");
},
},
};
</script>
Remember to return true
if you define the value of "button-clicked"
as a function.
-$$-Ensure to return true when you define the value of button-clicked as a function to indicate successful execution of the callback.
However, you can simplify the value to a simple string.
-$$-Alternatively, you can simplify the process by assigning a straightforward string value to the button-clicked event.
<script>
export default {
name: "friend-contact",
emits: ["button-clicked"],
methods: {
invokeEmit() {
this.$emit("button-clicked");
},
},
};
</script>
You may feel strange that we write extra code to implement the same result. Currently, you can see the strategy as improving performance.
-$$-You might find it unusual that we write additional code to achieve the same outcome. For now, consider this approach as a strategy to enhance performance.
19. Making a Form
In this chapter, we are trying to use Vue.js to establish a form to strengthen our understanding of communication between components.
-$$-In this chapter, we aim to leverage Vue.js to create a form, thereby deepening our comprehension of inter-component communication.
<template>
<form @submit.prevent="handleSubmit" :style="formStyle">
<div>
<label for="name">Name:</label>
<input v-model="name" id="name" type="text" />
</div>
<div>
<label for="email">Email:</label>
<input v-model="email" id="email" type="text" />
</div>
<div>
<label for="sex">Sex:</label>
<label>
Male
<input v-model="sex" type="radio" id="male" name="sex" :value="true" />
</label>
<label>
Female
<input
v-model="sex"
type="radio"
id="female"
name="sex"
:value="false"
/>
</label>
</div>
<button type="submit">Submit</button>
</form>
</template>
<script>
export default {
name: "demo-form",
data() {
return {
name: "",
email: "",
sex: true,
formStyle: {
display: "flex",
flexDirection: "column",
maxWidth: "400px",
margin: "100px auto",
},
};
},
computed: {
formData() {
return {
name: this.name,
email: this.email,
sex: this.sex,
};
},
},
methods: {
handleSubmit() {
console.log("this.formData:", this.formData);
this.$emit("form-submit", this.formData);
},
},
};
</script>
<style>
div {
min-width: 300px;
display: flex;
justify-content: space-between;
}
form > *:not(:first-child) {
margin-top: 12px;
}
</style>
20. Provide & Inject
If a component has a very large hierarchy, then we will write many extra code if we want to pass some data from top to the bottom although many components between them don't need these data at all!
-$$-When a component possesses an extensive hierarchy, attempting to pass data from the top to the bottom can result in the necessity to write considerable additional code, even though many intermediate components may not require this data at all.
So, we must find an efficient way to pass the data. We can use provide in ancestor component and use inject in son component. Through this way, not only can we pass plain data but also methods from ancestor component, thus by invoking the passing methods we can change the data in ancestor component and refresh the whole hierarchy system.
-$$-To efficiently transfer data within a deep component hierarchy, we can employ the provide and inject mechanisms. By using provide in an ancestor component and inject in a descendant component, we can pass not only plain data but also methods from the ancestor. This approach allows us to manipulate data in the ancestor component and trigger updates across the entire component hierarchy through the injected methods.
The following code shows how to transmit the plain data as well as method from top to bottom.
-$$-The subsequent code illustrates the process of cascading both plain data and methods from the top-level component down to its nested descendants.
// App.vue
<template>
<friend-contact></friend-contact>
{{ count }}
</template>
<script>
export default {
provide() {
return {
msgFromancestor: "this is a message from ancestor",
methodFromAncestor: this.methodFromAncestor,
};
},
methods: {
methodFromAncestor() {
this.count += 1;
},
},
data() {
return {
count: 0,
};
},
};
</script>
<template>
<p @click="methodFromAncestor">{{ msgFromancestor }}</p>
</template>
<script>
export default {
name: "friend-contact",
inject: ["msgFromancestor", "methodFromAncestor"],
};
</script>
<style>
p {
color: red;
}
</style>
I must remind you that when you prepare to pass method using provide-inject system, you must define a processing function in method, and then use it in provide, just as follows:
-$$-I must emphasize that when you intend to pass methods using the provide-inject system, it is essential to define a processing function within the method itself and then expose it using provide. Here is an example of how to do it:
<script>
export default {
provide() {
return {
methodFromAncestor: this.methodFromAncestor,
};
},
methods: {
methodFromAncestor() {
this.count += 1;
},
},
};
</script>
Remeber, you shouldn't write like this:
<script>
export default {
provide() {
return {
methodFromAncestor() {
this.count += 1;
},
};
},
};
</script>
21. Scoped style or not
By default, your styles in a certain component will be registed globally. If you want to confine the style into this component, you only need to add an attribute named scoped
on the style tag.
-$$-By default, the styles defined in a Vue component are applied globally. To restrict the scope of the styles to the component itself, simply add the scoped attribute to the <style>
tag within the component.
<style scoped>
p {
color: red;
}
</style>
The principle behind the scoped is pretty easy. When Vue.js render the elements on the screen, it will automatically add each of these DOM element a unique attribute, such as <p data-v-9a9f6144>...</p>
.
-$$-The concept of scoped styles in Vue.js is quite straightforward. When Vue.js renders elements to the screen, it automatically assigns a unique attribute to each DOM element, thereby encapsulating the styles. For instance, an element like <p>
might be rendered with a distinctive attribute such as <p data-v-9a9f6144>...</p>
, ensuring that the styles are confined to the component's scope.
Then, if you define the style to be scoped, the style p {color:red}
will change to be p[data-v-9a9f6144] {color:red}
. And because data-v-9a9f6144
is unique, so the styling is then confined.
-$$-When you apply scoped styles in a Vue.js component, the CSS selectors are automatically adjusted to include the component's unique identifier. For example, a style rule like p { color: red; }
is transformed into p[data-v-9a9f6144] { color: red; }
. Since the attribute data-v-9a9f6144
is unique to that component's elements, the styling is effectively confined to the component's scope.
22. Register a component to be globally or locally
Remeber these two rules about how to register components:
- If the component is only be used in a certain component, then register it locally.
- If there are more than 1 other component use this component, then register it globally.
-$$-Adhere to these two principles when registering Vue.js components:
- -$$-Local Registration: If a component is intended for use in only one specific component, it should be registered locally within that component. This approach keeps the component scoped to its usage context and reduces the global namespace pollution.
- -$$-Global Registration: If a component is to be utilized by multiple other components across the application, it should be registered globally. This makes the component available throughout the application, promoting reusability without the need for repetitive local registrations."
Register globally
import { createApp } from "vue";
import App from "./App.vue";
import FriendContact from "./components/FriendContact.vue";
import DemoForm from "./components/DemoForm.vue";
const app = createApp(App);
app.component("friend-contact", FriendContact);
app.component("demo-form", DemoForm);
app.mount("#app");
Register locally
<template>
<button>点我 <Badge /></button>
</template>
<script>
import Badge from "./Badge.vue";
export default {
name: "friend-contact",
components: {
Badge,
},
};
</script>
<template>
<span>{{ num }}</span>
</template>
<script>
export default {
name: "app-badge",
props: {
num: {
required: true,
type: Number,
default: 10,
},
},
};
</script>
<style scoped>
span {
color: red;
}
</style>
As you can see, we can type <Badge />
rather than <app-badge></app-badge>
, and this form is very much like using components in React.js.
-$$-As you can observe, we have the option to use the self-closing tag syntax with components in Vue.js, such as <Badge />
, instead of the standard HTML-style component notation like <app-badge></app-badge>
. This syntax is reminiscent of using components in React.js, offering a more concise and familiar way to declare component instances.
There is one last thing that even you register a component in a parent component, you can't use it directly in its son component, in this case, you should register it globally.
-$$-While it may seem intuitive that registering a component in a parent would make it available to its child components, this is not the case in Vue.js
. If you find yourself needing to use a component within a child that has been registered in its parent, you must instead opt for global registration to ensure that the component is accessible throughout the component hierarchy.
23. Slot in Vue.js
The purpose of using slot in Vue.js is to make the encapsulated components to be more dynamic and flexible. By using default slot or named slot, we can extend the usage of our common component futher.
-$$-The use of slots in Vue.js serves to enhance the dynamism and flexibility of encapsulated components. By leveraging default slots or named slots, we can significantly broaden the applicability of our reusable components, allowing for more tailored and contextual content distribution within their templates.
From another aspect, slot can be thought as using the space of the innerHTML of the encapsulated component.
-$$-From another perspective, slots in Vue.js can be conceptualized as utilizing the space analogous to the innerHTML of an encapsulated component. This approach allows for injecting content into the component's template dynamically, much like how innerHTML is used to set the content of an HTML element.
The following code shows how to use default and named slot in Vue.js.
-$$-The forthcoming code snippet illustrates the utilization of both default and named slots in Vue.js, demonstrating how to inject content into a component's template in a structured and semantic manner.
<Badge>
<template v-slot:dot>
<span
style="
display: block;
width: 10px;
height: 10px;
border-radius: 50%;
background-color: red;
"
></span>
</template>
<template v-slot:content>10</template>
<p>This 10 will be accepted by default slot</p>
</Badge>
<template>
<span>
<slot name="dot"></slot>
<slot name="content"></slot>
<slot></slot>
</span>
</template>
<script>
export default {
name: "app-badge",
props: {
num: {
required: true,
type: Number,
default: 10,
},
},
};
</script>
<style scoped>
span {
display: flex;
justify-content: center;
align-items: center;
}
</style>
And it will be rendered as follows:
-$$-The resulting rendering will be as follows:
<span data-v-6cb3fe23="">
<span
style="display: block; width: 10px; height: 10px; border-radius: 50%; background-color: red;"
></span>
10
<p>This 10 will be accepted by default slot</p>
</span>
Remove empty slot container
Look at the following code:
-$$-Please take a look at the following code:
<template>
<div>
<header>
<slot name="header"></slot>
</header>
</div>
</template>
Now, think about this question that what if the invoker doesn't pass the content corresponding to header slot? Then the encapsulated component will render an empty <header>
element on the page. It's definately not the best practice, and we can utilize the strategy as follows:
-$$-Now, consider the following question: what if the invoker does not pass any content corresponding to the header slot? In that case, the encapsulated component will render an empty
element on the page. This is definitely not the best practice, and we can utilize the following strategy to address this issue:<template>
<div>
<header v-if="$slots.header">
<slot name="header"></slot>
</header>
</div>
</template>
That's to say, besides this.$refs
, we can use this.$slots
to get the references of all slots in the template.
-$$-That is to say, in addition to using this.$refs
, we can also use this.$slots
to obtain references to all the slots in the template.
Pass data to the slot
Certainly, there's more than one attribute in the slot
tag. In above, we can use name
to match the content provided by the invoker. And we also can use a dynamic attribute :item
to transmit data into a certain slot.
-$$-Certainly, there are more than one attribute that can be used in the slot tag. In the example above, we used the name attribute to match the content provided by the invoker. Additionally, we can also use a dynamic attribute, such as :item
, to transmit data into a specific slot.
<template>
<ul>
<li v-for="goal in goals" :key="goal">
<slot :item="goal"></slot>
</li>
</ul>
</template>
As you can see, through the item attribute, we pass the data into the slot regardless that it comes from an iteration.
Actually, we can pass any attributes as we like:
-$$-Observe that data is transferred to the slot via the item attribute, irrespective of its origin from an iteration. We have the flexibility to pass any desired attributes.
<template>
<ul>
<li v-for="goal in goals" :key="goal">
<slot :item="goal" another-prop="..."></slot>
</li>
</ul>
</template>
And we can get this infomation in the encapsulated component by a assigned variable:
-$$-We can retrieve this data within the encapsulated component using a designated variable.
<template #default="slotProps">
<h2>{{ slotProps.item }}</h2>
<h2>{{ slotProps['another-prop'] }}</h2>
</template>
All of these can be applied to named slot:
-$$-All these methods can be applied to the named slots.
<template>
<ul>
<li v-for="goal in goals" :key="goal">
<slot :item="goal" another-prop="..." name="header"></slot>
</li>
</ul>
</template>
<template v-slot:header="slotProps">
<h2>{{ slotProps.item }}</h2>
<h2>{{ slotProps['another-prop'] }}</h2>
</template>
A little summary here:
- default slot:
#default="slotProps"
- named slot:
v-slot:header="slotProps"
24. Dynamic commponent
Vue.js equips developer a powerful weapon called <component>
. Utilizing this palceholder component, we can easily make our code flexible.
-$$-Vue.js provides developers with a powerful tool: the <component>
tag. By leveraging this placeholder, we can enhance the flexibility of our code.
<component :is="selectedComponent"></component>
The value of attribute is
is dynamic, and it should be the name of a certain component. We can make this process more clearly.
-$$-The is
attribute's value is dynamic, representing the name of a specific component. To clarify this process, ensure that the attribute is set to the correct component identifier.
<template>
<div>
<the-header></the-header>
<!-- <TheHeader />-->
<button @click="setSelectedComponent('active-goals')">Active Goals</button>
<button @click="setSelectedComponent('manage-goals')">Manage Goals</button>
<!-- <active-goals v-if="selectedComponent === 'active-goals'"></active-goals> -->
<!-- <manage-goals v-if="selectedComponent === 'manage-goals'"></manage-goals> -->
<component :is="selectedComponent"></component>
</div>
</template>
These two strings 'active-goals' and 'manage-goals' are both the name of a certain customized component.
There is a little issue there that if we change the value of selectedComponent
, the page will show a different component but with no previous state. That's to say, we will lose the data if we switch the component.
To solve this issue, Vue.js provides us with another component named keep-alive
. Only if we wrap the dynamic component within the keep-alive
component, we can sustain the previous state of the dynamic component.
-$$-The strings 'active-goals' and 'manage-goals' represent the names of specific custom components. However, there is a challenge: when the value of selectedComponent changes, the page transitions to a different component, but without retaining its previous state, leading to data loss upon component switching. Vue.js addresses this challenge by offering the keep-alive component. By encapsulating the dynamic component within keep-alive, we can preserve its state, ensuring that data is maintained even when switching between components.
<keep-alive>
<component :is="selectedComponent"></component>
</keep-alive>
25. Using dialog to encapsulate an ErrorAlert component
The dialog
tag is a native element provided by the browser. Now, let's seal a component using the dialog tag.
-$$-The dialog
element is a native browser feature. We can utilize it to encapsulate a component within a modal dialog interface.
<template>
<dialog open>
<slot></slot>
</dialog>
</template>
<script>
export default {
name: 'error-alert',
}
</script>
<style scoped>
dialog {
position:fixed;
top:20vh;
left:30%;
width:40%;
background-color: #fff;
box-shadow: 0 2px 8px rgba(0,0,0,0.26);
}
</style>
Put the above code into a file named ErrorAlert.vue
and name the sealed component to be error-alert
.
Please place the aforementioned code into a file entitled ErrorAlert.vue
. Ensure that the encapsulated component is designated with the name error-alert
.
26. Render the content by your wish
Another advantage of slot is that we can use slot to pass content from one component to another. And at the same time, the transmited content has a reference to the first component, and that's the point!
-$$-One of the key advantages of slots in Vue.js is their ability to facilitate the transfer of content between components. Importantly, the content passed through slots retains a reference to the originating component, which is a significant feature!
<error-alert v-if="inputIsInvalid">
<h2>Input is invalid!</h2>
<p>Please enter at least a few characters...</p>
<button @click="confirmError">Okay</button>
</error-alert>
Besides slot, we can use a component named teleport
to render any element we assigned.
-$$-In addition to slots, we can utilize the teleport component in Vue.js to render elements at a specified location in the DOM, which we designate.
<teleport to="body">
<error-alert v-if="inputIsInvalid">
<h2>Input is invalid!</h2>
<p>Please enter at least a few characters...</p>
<button @click="confirmError">Okay</button>
</error-alert>
</teleport>
The value of the attribute to
is actually a css selector, and the body
refers to <body>
.
-$$-The to
attribute's value should be a CSS selector that targets the desired DOM element. When specified as body
, it targets the document's <body>
element.
Al little summary:
- component: change to be any customized compoennt dynamically
- keep-alive: cache the state during the changing process
- teleport: render by your wish.
A Brief Summary:
- Components: Enable dynamic switching to any custom component.
- Keep-Alive: Caches the state during component transitions.
- Teleport: Allows rendering elements at specified DOM locations.
Reminder: In Vue.js version 2, you must use a div to seprates the template tag with your content, like:
-$$-In Vue.js version 2, it is necessary to encapsulate the <template>
tag and your content within a <div>
element, as demonstrated below:
<template>
<div>
....
</div>
</template>
In Vue.js version 2, this div is neccessary. But in version 3, you don't need to do so.
-$$-In Vue.js version 2, a <div>
element is required to encapsulate the content. However, in version 3, this requirement has been removed.
style guide:https://v2.vuejs.org/v2/style-guide/