1. Routing parameter decoupling
Typically with route parameters in components, most people do the following.
export default { methods: { getParamsId() { return this.$route.params.id } }}
Using $route in a component results in a high coupling to its corresponding route, limiting the flexibility of the component by restricting it to certain URL s.
The correct approach is to decouple through props.
const router = new VueRouter({ routes: [{ path: /user/:id , component: User, props: true }]})
After setting the props attribute of the route to true, the component can receive params parameters through props.
export default { props: [ id ], methods: { getParamsId() { return this.id } }}
You can also return props via the function pattern.
const router = new VueRouter({ routes: [{ path: /user/:id , component: User, props: (route) => ({ id: route.query.id }) }]})
2. Functional components
A functional component is stateless, it cannot be instantiated and does not have any lifecycle or methods. Creating a functional component is also simple, just add the function declaration in the template.
It is generally suitable for components that only depend on external data changes, and improves rendering performance due to its lightweight.
Everything the component needs is passed through the context parameter. It is a context object, see the documentation for specific properties. Here props is an object containing all bound properties.
<template functional> <div class="list"> <div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)"> <p>{{item.title}}</p> <p>{{item.content}}</p> </div> </div></template>
The parent component uses
<template> <div> <List :list="list" :itemClick="item => (currentItem = item)" /> </div></template>
import List from @/components/List.vueexport default { components: { List }, data() { return { list: [{ title: title , content: content }], currentItem: } }}
3. Range of styles
It is very common to modify the style of third-party components during development, but due to the style isolation of the scoped attribute, it may be necessary to remove the scoped or create another style. These practices have side effects (component style pollution, lack of elegance), and use style penetration in the css preprocessor to take effect.
We can use >>> or /deep/ to solve this problem:
<style scoped>Outer layer >>> .el-checkbox { display: block; font-size: 26px; .el-checkbox__label { font-size: 16px; }}</style>
<style scoped>/deep/ .el-checkbox { display: block; font-size: 26px; .el-checkbox__label { font-size: 16px; }}</style>
4. Advanced use of watch
Watch fires when the listener property changes, and sometimes we want the watch to execute right after the component is created.
The way that might come to mind is to call it once in the creation lifetime, but that's not an elegant way to write it, so maybe we can use something like this.
export default { data() { return { name: Joe } }, watch: { name: { handler: sayName , immediate: true } }, methods: { sayName() { console.log(this.name) } }}
Deep Listening
When listening to an object, when the internal properties of the object change, the watch will not be triggered, so we can set up deep monitoring for it.
export default { data: { studen: { name: Joe , skill: { run: { speed: fast } } } }, watch: { studen: { handler: sayName , deep: true } }, methods: { sayName() { console.log(this.studen) } }}
Trigger listeners to execute multiple methods
Using arrays, you can set multiple forms, including strings, functions, objects.
export default { data: { name: Joe }, watch: { name: [ sayName1 , function(newVal, oldVal) { this.sayName2() }, { handler: sayName3 , immaediate: true } ] }, methods: { sayName1() { console.log( sayName1==> , this.name) }, sayName2() { console.log( sayName2==> , this.name) }, sayName3() { console.log( sayName3==> , this.name) } }}
5.watch monitors multiple variables
watch itself cannot monitor multiple variables. However, we can "listen to multiple variables" by returning an object with a computed property and then listening to that object.
export default { data() { return { msg1: apple , msg2: banana } }, compouted: { msgObj() { const { msg1, msg2 } = this return { msg1, msg2 } } }, watch: { msgObj: { handler(newVal, oldVal) { if (newVal.msg1 != oldVal.msg1) { console.log( msg1 is change ) } if (newVal.msg2 != oldVal.msg2) { console.log( msg2 is change ) } }, deep: true } }}
6. Event parameter $event
$event is a special variable of the event object, which provides us with more available parameters to achieve complex functions in some scenarios.
Native Events: Behaves the same as the default event object in Native Events.
<template> <div> <input type="text" @input="inputHandler( hello , $event)" /> </div></template>
export default { methods: { inputHandler(msg, e) { console.log(e.target.value) } }}
Custom Events: Represented in custom events as capturing values thrown from child components.
export default { methods: { customEvent() { this.$emit( custom-event , some value ) } }}
<template> <div> <my-item v-for="(item, index) in list" @custom-event="customEvent(index, $event)"> </my-list> </div></template>
export default { methods: { customEvent(index, e) { console.log(e) // some value } }}
7. Programmatic event listeners
For example, if a timer is defined when the page is mounted, the timer needs to be cleared when the page is destroyed. This doesn't seem to be a problem. But look closely, the only purpose of this.timer is to be able to get the timer number in beforeDestroy, otherwise it is useless.
export default { mounted() { this.timer = setInterval(() => { console.log(Date.now()) }, 1000) }, beforeDestroy() { clearInterval(this.timer) }}
It's best to only access lifecycle hooks if possible. This is not a serious problem, but can be considered confusion.
We can fix this by using $on or $once to listen for page lifecycle destruction:
export default { mounted() { this.creatInterval( hello ) this.creatInterval( world ) }, creatInterval(msg) { let timer = setInterval(() => { console.log(msg) }, 1000) this.$once( hook:beforeDestroy , function() { clearInterval(timer) }) }}
Using this method, even if we create multiple timers at the same time, the effect will not be affected. This is because they will be automatically cleared programmatically after the page is destroyed.
8. Monitor component life cycle
Usually we use $emit to monitor the component life cycle, and the parent component receives the event for notification.
Subassembly
export default { mounted() { this.$emit( listenMounted ) }}
parent component
<template> <div> <List @listenMounted="listenMounted" /> </div></template>
In fact, there is a simple way to use @hook to monitor the life cycle of the component without making any changes inside the component. Similarly, create, update, etc. can also use this method.
<template> <List @hook:mounted="listenMounted" /></template>