Do you really know how long it takes Vue to develop these skills

catalogue

preface

1. Restrict a prop to a list of types

2. Use quotation marks to listen for nested attributes

3. Know when to use v-if

4. Abbreviation for a single scope slot

5. Mix local and global style s

6. Override styles for subcomponents

7. How to create a responsive variable outside Vue

8. Deconstruction in v-for

9. Cycle within the specified range

10. Steal prop type

11. Detect clicks outside (or inside) an element

12. Call a method from outside the component

13. Listen for arrays and objects

14. Another use of the template tag

15. Better ways to handle errors (and warnings)

preface

Learning to be a better Vue developer is not always about big concepts that take time and effort to master.

Mastering some skills and tricks can make our programming life easier - without a lot of repetitive work.

In the past few years of Vue development, it will always be useful to master some useful skills and use some more advanced technical points.

1. Restrict a prop to a list of types

When using prop, we may sometimes need to judge whether the prop is within the specified range (or the specified value). At this time, we can use the validator option in the prop definition to limit a prop type to a specific set of values.

export?default?{
??name:?'Test',
??props:?{
????name:?{
??????type:?String,
????},
????size:?{
??????type:?String,
??????validator:?s?=>?['small',?'middle'].includes(s)
????}
??}
};

This validation function accepts a prop and returns true or false if the prop is valid or invalid. I usually use this method when only passing in true or false to control that some conditions cannot meet the requirements.

2. Use quotation marks to listen for nested attributes

You may have used watch to listen to a property, but you may not know this. We can easily listen to nested values directly by using quotation marks

watch?{
??'obj.message.name'()?{
????//?...
??}
}

3. Know when to use v-if

Sometimes v-if is used instead of v-show, which will have higher performance.

<TableList v-show="isShow" />

When v-if is turned on or off, it creates and completely destroys the element. On the contrary, v-show will create the element and leave it there, and hide it by setting its style to display: none. If the rendering cost of the component you want to switch is very high, it will be more efficient, especially for the component or page with complex structure. V-show is recommended.

Conversely, if you don't need to execute expensive components immediately, you can use v-if, which will skip rendering it and make the page load faster.

4. Abbreviation for a single scope slot

Delimited slots are interesting, but in order to use them, you must also use many template tags. Fortunately, there is a shorthand that allows us to get rid of it, but only if we use a single scope slot.

You may have used it like this

<TableList>
??<template?#header="attrList">
????<TableHeader?v-bind="attrList"?/>
??</template>
</TableList>

Do not use template

<TableList #header="attrList">
??<TableHeader?v-bind="attrList"?/>
</TableList>

Simple and straightforward, amazing.

5. Mix local and global style s

Typically, when dealing with styles, we want them to work only within the current component

<style?scoped>
??.content?{
????background:?green;
??}
</style>

However, you can also add a non scoped style block to add global styles if needed

<style>
??/*?overall situation?*/
??.content?p?{
????font-size:?12px;
??}
</style>
 
<style?scoped>
??/*?Valid within this component?*/
??.content?{
????background:?green;
??}
</style>

Note that global styles are dangerous and difficult to track. But sometimes they are a perfect escape hatch, just what you need.

6. Override styles for subcomponents

Scoped CSS is great at keeping content clean and tidy, and does not introduce styles into other components of the application. But sometimes we need to override the style of a sub component and jump out of this scope.

Vue has a deep selector to complete the above functions

<style?scoped>
.my-content?>>>?.child-component?{
??font-size:?16px;
}
</style>

Note: if you use CSS preprocessors like LESS, you may need to use / deep / instead

<style lang="less"?scoped>
.my-content?/deep/?.child-component?{
??font-size:?16px;
}
</style>

7. How to create a responsive variable outside Vue

If you get a variable from outside Vue, it's good to make it reactive. In this way, we can use it in computed props, watch and anywhere else, and it works just like any other state in Vue.

If we use the option API, all we need is to put it in the data part of the component

const?externalVariable?=?getValue();
 
export?default?{
??data()?{
????return?{
??????reactiveVariable:?externalVariable,
????};
??}
};

If you use Vue3's composite API, you can directly use ref or reactive

import?{?ref?}?from?'vue';
 
//? It can be done completely outside the Vue component
const?externalVariable?=?getValue();
const?reactiveVariable?=?ref(externalVariable);   //Use ref to make it responsive

Use reactive instead

import?{?reactive?}?from?'vue';
 
//?? It can be done completely outside the Vue component
const?externalVariable?=?getValue();
//? reactive? Works only on objects and arrays
const?anotherReactiveVariable?=?reactive(externalVariable);

If you are still using Vue2, you can use observable instead of reactive to achieve exactly the same results

import Vue from 'vue'

//?? It can be done completely outside the Vue component
const?externalVariable?=?getValue();
const?anotherReactiveVariable?=?Vue.observable(externalVariable);

8. Deconstruction in v-for

Do you use deconstruction in v-for?

// users: [{name:'leo',id:'1'},{name:'lion',id:'2'}]
<li
??v-for="{?name,?id?}?in?users"
??:key="id"
>
??{{?name?}}
</li>

It is better known that indexes can be extracted from v-for by using such tuples

<li?v-for="(movie,?index)?in?[
??'Lion?King',
??'Frozen',
??'The?Princess?Bride'
]">
??{{?index?+?1?}}?=>?{{?movie?}}
</li>

When using an object, you can use key in this way

<li?v-for="(value,?key)?in?{
??name:?'Lion?King',
??released:?2019,
??director:?'Jon?Favreau',
}">
??{{?key?}}:?{{?value?}}
</li>

You can also combine the two methods to obtain the key and attribute index

<li?v-for="(value,?key,?index)?in?{
??name:?'Lion?King',
??released:?2019,
??director:?'Jon?Favreau',
}">
??{{?index?+?1?}} => {{?key?}}:?{{?value?}}
</li>

9. Cycle within the specified range

v-for allows us to traverse an array and a range

<template>
??<ul>
????<li?v-for="num?in?6">Item?{{?num?}}</li>
??</ul>
</template>

Render results

Item?1
Item?2
Item?3
Item?4
Item?5
Item?6

Here's a note. When we use v-for to traverse a range, it will start with 1 and end with the number we specify.

10. Steal prop type

We copy prop types from a child component just to use them in a parent component. But it's often better to steal these prop types than just copy them. What do you mean?

For example, we use a List component in a component

<template>
??<div>
????<h2>{{?title?}}</h2>
????<List
??????:type="listType"
??????:size="listSize"
      :name="listName"
????/>
??</div>
</template>

In order for it to work properly, we need to add the correct prop type and copy it from the List component

import?List?from?'./List';
export?default?{
??components:?{?List?},
??props:?{
????listType:?{
??????type:?String,
??????required:?true,
????},
????listSize:?{
??????type:?String,
??????default:?'medium',
??????validator:?size?=>?[
????????'small',
????????'medium',
????????'large',
????????'x-large'
??????].includes(size),
????},
????listName:?{
??????type:?String,
??????default:?'list',
????},
????title:?{
??????type:?String,
??????required:?true,
????},
??},
};

Look, do you feel very troublesome?

When the prop type of the List component is updated, we will certainly forget to return the component and update them. Over time, errors are introduced when the prop type of the component begins to deviate from the prop type in the List component.

Therefore, this is why we want to steal the prop type of the component, as follows

import?List?from?'./List';
export?default?{
??components:?{?List?},
??props:?{
????...List.props,  // Steal the prop s of the List, and there is no need to List them one by one
????title:?{
??????type:?String,
??????required:?true,
????},
??},
};

Is it a lot easier?

Except in the above example, we add List at the beginning of each prop name. So we must do some extra work to achieve this

import?List?from?'./List';
 
const?listProps?=?{};
 
Object.entries(List.props).forEach((key,?val)?=>?{
??listProps[`list${key.toUpperCase()}`]?=?val;
});
 
export?default?{
??components:?{?List?},
??props:?{
????...listProps,
????title:?{
??????type:?String,
??????required:?true,
????},
??},
};

Now, if the prop type in the List component is modified, our component will remain up-to-date. But what if a prop type is added or removed from the List component? To cope with these situations, we can use v-bind and a calculated prop to keep dynamic.

11. Detect clicks outside (or inside) an element

When we need to detect whether a click occurs inside or outside a specific element el, we usually use the method

window.addEventListener('click',?e?=>?{
??//? Get the clicked element
??const?currtentEl?=?e.target;

??// Detect whether it is inside or outside the el element
??if?(el.contains(currtentEl))?{
???// Click inside el
??}?else?{
???// Click outside
??}
});

12. Call a method from outside the component

We can call a method from outside a component by giving it a ref

<!--?Parent.vue?-->
<template>
??<Child?ref="child"?/>
</template>

//? The method of the subcomponent is called in this component
this.$refs.child.method();

Usually, we use props and events to communicate between components. Props is distributed to the child component, while events are uploaded to the parent component

<template>
??<Child
????:tell-me-what-to-do="someInstructions"
????@something-happened="hereIWillHelpYouWithThat"
??/>
</template>

//?Child.vue
export?default?{
??props:?['trigger'],
??watch:?{
????shouldCallMethod(newVal)?{
??????if?(newVal)?{
????????//?Call?the?method?when?the?trigger?is?set?to?`true`
????????this.method();
??????}
????}
??}
}

This works, but can only be used on the first call. If you need to trigger this operation multiple times, you must clean it up and reset the status. The logic is as follows

  • The parent component passes true to the trigger prop
  • The Watch is triggered, and then the Child component calls the method
  • The child component sends an event to tell the parent component that the method has been successfully triggered
  • The Parent component resets the trigger to false, so we can do it all over again

On the contrary, if we set a ref on the sub component, we can call the method directly (as in the beginning). We break the rule of "props down, events up", and we break the encapsulation, but this is clearer and easier to understand.

13. Listen for arrays and objects

Sometimes the use of watcher cannot trigger correctly. In many cases, it is because we try to listen to arrays or objects, but do not set deep to true

export?default?{
??name:?'namesChange',
??props:?{
????names:?{
??????type:?Array,
??????required:?true,
????},
??},
??watch:?{
????names:?{
??????//? This will let Vue know to look inside the array. If it is not added, deep listening cannot be performed
??????deep:?true,
 
??????handler(newVal,oldVal)
????????console.log('The?list?of?names?has?changed!');
??????}
????}
??}
}

Use in vue3

watch(
??names,
??(newVal,oldVal)?=>?{
????console.log('The?list?of?names?has?changed!');
??},
??{
????deep:?true,
??}
);

14. Another use of the template tag

The template tag can be used anywhere in the template to better organize the code. Sometimes it simplifies v-if logic, and sometimes it uses v-for. As follows, we have several elements that use the same v-if condition

<template>
??<div?class="card">
????<img?src="imgPath"?/>
????<h3>
??????{{?title?}}
????</h3>
????<h4?v-if="expanded">
??????{{?subheading?}}
????</h4>
????<div
??????v-if="expanded"
??????class="card-content"
????>
??????<slot?/>
????</div>
????<SocialShare?v-if="expanded"?/>
??</div>
</template>

Looking closely at the above code, we will find that the display and hiding conditions of some elements are the same, but it is not friendly to write like this. It may be a bad situation when it is on a larger and more complex component.

We can use the template tag to group these elements (elements with consistent v-if conditions), and promote v-if to the template itself to achieve the purpose of optimization

<template>
??<div?class="card">
????<img?src="imgPath"?/>
????<h3>
??????{{?title?}}
????</h3>
    <!-- take v-if Promote to group -->
????<template?v-if="expanded">
??????<h4>
????????{{?subheading?}}
??????</h4>
??????<div?class="card-content">
????????<slot?/>
??????</div>
??????<SocialShare?/>
????</template>
??</div>
</template>

Now it looks much clearer and easier to understand, and what it is doing is clear at a glance.

15. Better ways to handle errors (and warnings)

We can provide a global custom handler for errors and warnings in Vue

//?Vue?2
Vue.config.errorHandler?=?(err)?=>?{
??alert(err);
};

//?Vue?3
const?app?=?createApp(App);
app.config.errorHandler?=?(err)?=>?{
??alert(err);
};

Of course, you can also use them to handle errors more gracefully for a better user experience. For example, if an error is not handled, the application will not crash directly, but a complete error screen will be displayed, prompting the user to refresh or try another operation.

See here, don't be stingy with your little fingers. Walk three times with one button~~~

Keywords: Javascript Front-end Vue.js html Interview

Added by andreash on Thu, 24 Feb 2022 14:13:59 +0200