Front words

   Most of the options accepted by components are related toVue Same example, Optionsprops Is a very important option in the component. stay Vue in, The parent-child relationship can be summarized as props down,
events up. Parent component passed props  Passing data down to subcomponents, Sub components pass events  Send message to parent component. This article will introduce in detailVue Component optionsprops

 

Parent child component

   Introducingprops before, First, introduce the writing method of parent-child components

   It is important to decouple parent-child components as much as possible in a well-defined interface. This ensures that each component can be written and understood in a relatively isolated environment, It also greatly improves the maintainability and reusability of components

【 Wrong writing】

   Now let's introduce two wrong ways to write parent-child components

   The following form is wrong, Because when a child component is registered with a parent component,Vue.js The template of the parent component will be compiled, The content of the template has determined what the parent component will renderHTML
  <parent>...</parent>
Runtime, Some of its sub tags will only be treated as normalHTML To execute,<child></child> Not standardHTML Label, Will be ignored by the browser directly
<div id="example"> <parent> <child></child> <child></child> </parent> </div>
    It is also an error to use a child component outside the parent component label
<div id="example"> <parent></parent> <child></child> </div>
【 Correct writing】
<div id="example"> <parent></parent> </div> <script> var childNode = {
template: '<div>childNode</div>', } var parentNode = { template: ` <div
class="parent"> <child></child> <child></child> </div> `, components: {
'child': childNode } }; // Create root instance new Vue({ el: '#example', components: {
'parent': parentNode } }) </script>
 

static stateprops

   The scope of the component instance is isolated. That means no ( Nor should it be) Directly reference the data of the parent component within the template of the child component. To have child components use the data of the parent component, The props  option

   UseProp Data transfer includes static and dynamic forms, Let's start with staticprops

   Subcomponents to be used explicitly props  Option to declare the data it expects
var childNode = { template: '<div>{{message}}</div>', props:['message'] }
   static stateProp Pass values by adding properties to the placeholders of the child component in the parent component
<div id="example"> <parent></parent> </div> <script> var childNode = {
template:'<div>{{message}}</div>', props:['message'] } var parentNode = {
template: `<div class="parent"> <child message="aaa"></child> <child message="
bbb"></child> </div>`, components: { 'child': childNode } }; // Create root instance new
Vue({ el:'#example', components: { 'parent': parentNode } }) </script>
 

Naming convention

   aboutprops For declared properties, At parent levelHTML Template, Attribute name needs to be written with middle dash
var parentNode = { template: ` <div class="parent"> <child my-message="aaa"></
child> <child my-message="bbb"></child> </div>`, components: { 'child':
childNode } };
   Sub levelprops When a property is declared, It can be written with small hump or middle dash; When a child template uses a variable from the parent, It needs to use the corresponding small hump writing method
var childNode = { template: '<div>{{myMessage}}</div>', props:['myMessage'] }
var childNode = { template: '<div>{{myMessage}}</div>', props:['my-message'] }
 

dynamicprops

   In template, To dynamically bind the data of the parent component to the data of the child template props, And bind to any normalHTML Similar characteristics, Just use v-bind
. Whenever the data of the parent component changes, This change is also transmitted to the subcomponents
var childNode = { template: '<div>{{myMessage}}</div>', props:['myMessage'] }
var parentNode = { template: ` <div class="parent"> <child
:my-message="data1"></child> <child :my-message="data2"></child> </div>`,
components: { 'child': childNode }, data(){ return { 'data1':'aaa',
'data2':'bbb' } } };
  

Transmit number

   A common mistake for beginners is to use literal grammar to transfer values
<!-- Passed a string "1" --> <comp some-prop="1"></comp> <div id="example"> <my-parent
></my-parent> </div> <script> var childNode = { template: '
<div>{{myMessage}} The type is{{type}}</div>', props:['myMessage'], computed:{ type(){
return typeof this.myMessage } } } var parentNode = { template: ` <div class="
parent"> <my-child my-message="1"></my-child> </div>`, components: { 'myChild'
: childNode } };// Create root instance new Vue({ el: '#example', components: { 'MyParent':
parentNode } })</script>
   Because it's a literal prop, Its value is a string "1" Instead of number. If you want to pass on an actual number, Need to use v-bind
, So that its value is treated asJS Expression evaluation 
<!-- Pass the actual number --> <comp v-bind:some-prop="1"></comp> var parentNode = {
template: `<div class="parent"> <my-child :my-message="1"></my-child> </div>`,
components: { 'myChild': childNode } };
   Or you can use dynamicprops, staydata Set the corresponding number in the1
var parentNode = { template: ` <div class="parent"> <my-child :my-message
="data"></my-child> </div>`, components: { 'myChild': childNode }, data(){
return { 'data': 1 } } };
 

props Verification

   Can be props Specify validation specifications. If the incoming data does not meet the specifications,Vue Warning will be given. When components are used by others, This is very useful.

   To specify validation specifications, Need to be in the form of an object, Instead of string array
Vue.component('example', { props: { // Basic type test (`null` It means anything) propA:
Number, // Multiple types propB: [String, Number], // Required and string propC: { type: String,
required: true }, // number, There are default values. propD: { type: Number, default: 100 }, //
array/ The default value of the object should be returned by a factory function propE: { type: Object, default: function () { return {
message: 'hello' } } }, // Custom validation function propF: { validator: function (value) {
return value > 10 } } } })
  type It can be the following native constructor
String Number Boolean Function Object Array Symbol
  type It can also be a custom constructor function, Use instanceof Testing.

   When prop Validation failed,Vue Warning will be thrown ( If you are using a development version).props Verification will be performed before the component instance is created, So in default or
validator Function inside, such as data,computed or methods Instance properties such as

   Here is a simple example, If themessage Not numbers, Then a warning is thrown
<div id="example"> <parent></parent> </div> <script> var childNode = {
template: '<div>{{message}}</div>', props:{ 'message':Number } } var parentNode
= { template: ` <div class="parent"> <child :message="msg"></child> </div>`,
components: { 'child': childNode }, data(){ return{ msg: '123' } } }; // Create root instance
new Vue({ el: '#example', components: { 'parent': parentNode } }) </script>
   Incoming numbers123 Time, No warning. Incoming string'123' Time, The results are as follows

   In the above code, The content of the subcomponent is modified as follows, Customizable validation function, When the function returns tofalse Time, Output warning prompt
var childNode = { template: '<div>{{message}}</div>', props:{ 'message':{
validator: function (value) { return value > 10 } } } }
   Pass in in the parent componentmsg The value is1, Less than10, Output warning prompt
var parentNode = { template: ` <div class="parent"> <child
:message="msg"></child> </div>`, components: { 'child': childNode }, data(){
return{ msg:1 } } };
 

One way data flow

  prop Is one-way bound: When the properties of the parent component change, Transmit to sub assembly, But not the other way around. This is to prevent the child component from inadvertently modifying the state of the parent component—— This makes the application's data flow difficult to understand

   in addition, Every time the parent component is updated, All of the subcomponents prop Will be updated to the latest value. This means that changes should not be made within subcomponents prop. If you do,Vue A warning will be given at the console

   Here is a typical example
<div id="example"> <parent></parent> </div> <script> var childNode = {
template: ` <div class="child"> <div> <span> Subcomponent data</span> <input
v-model="childMsg"> </div> <p>{{childMsg}}</p> </div> `, props:['childMsg'] }
var parentNode = { template: ` <div class="parent"> <div> <span> Parent component data</span>
<input v-model="msg"> </div> <p>{{msg}}</p> <child :child-msg="msg"></child>
</div> `, components: { 'child': childNode }, data(){ return { 'msg':'match' }
} }; // Create root instance new Vue({ el: '#example', components: { 'parent': parentNode } })
</script>
   When the parent component data changes, Sub component data will change accordingly; When the data of sub components changes, Parent component data unchanged, And display a warning on the console



   When modifying subcomponent data, Open the browser console and a warning will appear as shown in the figure below

 

modifyprop data

   modifyprop Data in, There are usually two reasons

  1,prop After passed in as initial value, Subcomponent wants to use it as local data

  2,prop Passed in as initial value, Processing from sub components to other data output

  [ Be careful]JS Objects and arrays in are reference types, Point to the same memory space, If prop Is an object or array, Changing it within a child component affects the state of the parent component

   For both cases, The right response is

  1, Define a local variable, And use prop The value of initializes it
props: ['initialCounter'], data: function () { return { counter:
this.initialCounter } }
   however, Defined local variablescounter Can only acceptinitialCounter Initial value, When the value to be passed by the parent component changes,counter Cannot receive latest value
<div id="example"> <parent></parent> </div> <script src="https://unpkg.com/vue"
></script> <script> var childNode = { template: ` <div class="child"> <div> <
span> Subcomponent data</span> <input v-model="temp"> </div> <p>{{temp}}</p> </div> `,
props:['childMsg'], data(){ return{ temp:this.childMsg } }, }; var parentNode =
{ template: `<div class="parent"> <div> <span> Parent component data</span> <input v-model="msg">
</div> <p>{{msg}}</p> <child :child-msg="msg"></child> </div> `, components: {
'child': childNode }, data(){ return { 'msg':'match' } } }; // Create root instance new Vue({
el:'#example', components: { 'parent': parentNode } }) </script>
   In the following example, Except for the initial value, The value of the parent component cannot be updated into the child component



  2, Define a calculation property, Handle prop And return
props: ['size'], computed: { normalizedSize: function () { return
this.size.trim().toLowerCase() } }
   however, Because it's a calculated property, Only values can be displayed, Instead of setting the value
<script src="https://unpkg.com/vue"></script> <script> var childNode = {
template: `<div class="child"> <div> <span> Subcomponent data</span> <input v-model="temp"> <
/div> <p>{{temp}}</p> </div> `, props:['childMsg'], computed:{ temp(){ return
this.childMsg } }, }; var parentNode = { template: ` <div class="parent"> <div>
<span> Parent component data</span> <input v-model="msg"> </div> <p>{{msg}}</p> <child :child-msg
="msg"></child> </div> `, components: { 'child': childNode }, data(){ return {
'msg':'match' } } }; // Create root instance new Vue({ el: '#example', components: { 'parent':
parentNode } })</script>
   In the following example, Because subcomponents use calculated properties, therefore, Data of subcomponent cannot be modified manually



  3, The more appropriate solution is, Using variable storageprop Initial value, And usewatch To observeprop Change in value of. When there is a change, Update value of variable
<div id="example"> <parent></parent> </div> <script src="https://unpkg.com/vue"
></script> <script> var childNode = { template: ` <div class="child"> <div> <
span> Subcomponent data</span> <input v-model="temp"> </div> <p>{{temp}}</p> </div> `,
props:['childMsg'], data(){ return{ temp:this.childMsg } }, watch:{ childMsg(){
this.temp = this.childMsg } } }; var parentNode = { template: ` <div class="
parent"> <div> <span> Parent component data</span> <input v-model="msg"> </div> <p>{{msg}}</p> <
child :child-msg="msg"></child> </div> `, components: { 'child': childNode },
data(){return { 'msg':'match' } } }; // Create root instance new Vue({ el: '#example',
components: {'parent': parentNode } }) </script>