preface
Spare watching Denver found community pushed the 7 clock in this activity, in line with the state of mind to participate clock in joined the army, then I will share the Vue higher-order usage, seven consecutive days let us at the time of writing component has more flexibility, improve component combination of scalable, can be split |.
Seven-day plan:
- 7 clock in | Vue project component packaging ideas
- 7 clock in | Vue. Mixin, Vue. Exend advanced usage
- 7 clock in | Vue $watch, Vue.com puted combination usage
- 7 clock in | Vue dynamic, recursive, asynchronous components
- 7 clock in | Vue slots content distribution
- 7 clock in | Vue JSX & Functional writing higher-order functions (components)
- 7 clock in | Vue higher-order usage of best practices
It wasn’t the series of the first article in this, on the evening see the nuggets of 7 clock in activities, I’m going to write article relatively foundation but also relatively important component of communication, but actually there are too many articles for components communication, as far as I’m writing to have full article want to come my heart is uneasy, At first glance, is on the document, some things, so in the evening after work to modify the content, this article will first tell the indispensable component in the actual packaging components under the communication mode, combined with actual project about the above knowledge in some of the good usage and may encounter problems and solutions, because technology co., LTD., if in any piece of writing is not quite right, Welcome to point out, I will respond immediately
Component communication
There are two dimensions for communication between components:
- There are references between components: parent and child components
- There are no references between components: sibling components, generational components
So communication between components is the same as communication between the three roles above:
- props/
on | Event Bus
children/$root/refs
listeners- provied/inject
- vuex/Storage
- slots
children/$root/refs
- $parent Parent instance of the component
- $children example component
- $root Instance root component, or itself if not
- $refs refers to either a DOM element or a component instance
None of these methods are responsive and are rarely used in real projects, except for $refs, which is available in official documentation and will not be covered here
Component communication between reference relationships
props/$emit
Parent: props props props props props props props props props props props props props props props props props props props props props props props props props props props props props propsCopy the code
demo
A component
<template> <div class="A"> I am A <B :list="list" :name="name" @handlerclick ="handlerClick" /> </div> </template> <script> Import B from './B' export default {name: 'A', components: {B}, data() {return {name: 'beigue ', list: [{name:'Beige', ..xxxx}, {...}] } }, methods: HandlerClick ({row, index}, callBack) {callBack(this.list[index]) // do a series of things},}} </script>Copy the code
B component
<template> <div class="B"> I am {{name}} <div class="title" @click="clickHandler(item, $I)" v-for="(item, $I) $i) of list" :key="item.id" > {{item.name}} </div> <p>foo:{{ foo }}</p> </div> </template> <script> export default { Name: 'B', props: ['list', 'name'], // Accept data from parent component This.$emit('handlerClick', {item, index: $i}, this.callBack) }, callBack(item) { console.log(item) } } } </script>Copy the code
This way is more commonly used in daily life, but there will be some problems
- Different representations of $event
- For basic data types, such as pop-up show/hide, can it be simpler?
- If components are deeply nested and I want to get to the lowest level of data, should I keep throwing events up?
Different representations of $event
@click="clickHandler($event)" clickHandler(e) {e= >Event object} @customClick="clickHandler($event)" clickHandler(. data) { data= >Data thrown by child components}Copy the code
If I listen for a custom event, not only do I need the child component’s data, I also need the event object of the current event, and I need to pass other parameters to the event method (clickHandler), what do I do?
The most typical one is that the table obtains row data and the data thrown by the sub-component. As shown in the figure, when we add a new row, the popup box is the sub-component we refer to. We need to obtain data of both the sub-component and the whole row
So at this point our parent component A listens for custom events and also needs to pass data
<template #documentType="{row}"> <! <B :foo="foo" @confirm="confirmHandler($event, row)" $event </template> = $event </template>Copy the code
There is a problem here. I need the event object of the current custom event. I cannot get the child component until it is thrown, so we must remember to throw the event object when encapsulating some special components (such as DragDialog)
clickHandler(item, $i, e) {
// Pass data to the parent component
this.$emit('handlerClick', { item, index: $i, event: e })
},
Copy the code
use.sync
Simplify custom events
When encapsulating a popbox component, popboxes are usually shown and hidden by passing a variable, the child component throws an event, and the parent component changes the variable. The.sync syntax simplifies this operation
Normal operation
Vue.component('BaseDialog', {
template: '
content...
'.props: {
show: {
type: Boolean.// Whether to pop up a window
required: true}}data() {
return {dialogShow: this.show}
},
methods: {
handleClose() {
this.dialogShow = false
this.$emit('close'.this.dialogShow); }}});<BaseDialog :show="isShow" @close="isShow = false" />
Copy the code
Simplified operation
Vue.component('BaseDialog', {
template: '
content...
'.props: {
show: {
type: Boolean.// Whether to pop up a window
required: true}}watch: {
show(val) {
this.dialogShow = val
},
dialogShow(val) {
this.$emit('update:show', val)
}
}
});
<BaseDialog :show.sync="isShow" /> // => Equivalent to the following
<BaseDialog :show="isShow" @update:show="(show) => (isShow = show)" />
Copy the code
provied/inject
In real projects, the reference relationship of components is relatively not so simple, components may be deeply nested, which must be known to all, so provied/ Inject this way also come out
- Provide: Infuses data in this manner and penetrates all the way down
- Inject: Data injected by the component can be retrieved only if it has a reference relationship with the component
It’s very simple to use
var app=new Vue({ el:'#app', Template: ` < div > < parent "> < / parent" > < / div > `}) Vue.com ponent (' A ', {template: ` < div > < / p > < p > A component < / B > < / div > `, Provide (){// Ancestor components inject data down return {FormModel: This.form}}, data(){return {form:{form object data}}}}) Vue.component('B',{inject: {// Sub-component gets the data injected from "above" FormModel: {default: {}} // If there is no default empty object, in case of program error}, // => do not do default processing inject: ['editTable'], data(){ return { FormModel:this.form } }, Template: '<DragDialog> <p>B component </p> <input type="tet" V-model ="form"> </DragDialog>) Vue.component('C',{inject: FormModel: {default: {}}}, the data () {return {FormModel: enclosing form}}, the template: ` < div > < p > C component < / p > < input type = "tet" v - model = "form" > < / div >)Copy the code
The most common way to do this is to open a Dialog inside a Form, and then open a Form inside a Dialog. This is a Form nesting scenario. A lot of times we call the API on the back end and actually pass the object data to it. Omit many objects and merge a series of data operations.
As shown in the figure, all forms seen from the detail page, including the large Form of Dialog, and the Form that pops up by clicking on the Input box, can be placed in a Form object. At this point, we inject the outer Form, which is very easy to use if we need the outer data.
Note: provide injected objects are not reactive, so we need to do reactive processing ourselves before injection
A component
<template> <p>A component </p> < button@click ="changeForm(val)"> </button> <B/> <C/> </template> <script> export default { data() { return { form: { a: '1', b: {b1: 1, b2: [{xxx}]} } }; }, provide() {return {formModel: this. Form does not inject data in response}}, methods: { changeColor(color) { if (color) { this.color = color; } else { this.color = this.color === "blue" ? "red" : "blue"; }}} methods: {changeColor(val) {// Change the form data, but the form object referenced by B component is still the original injected form object form.b.b2.push(val)}}} </script>Copy the code
So component A can do reactive processing on the injected object before injection
Provide () {this.formModel = vue.Observable (this.form); // Provide () {this.formModel = Vue.Observable (this.form); return { formModel: this.formModel }; },Copy the code
. Not done. Time is up. Send it out first