Vue.js the communication _javascript skills between components and components every day

Source: Internet
Author: User
Tags extend modifier naming convention

What is a component?

Component (Component) is one of the most powerful features of Vue.js. Components can extend HTML elements and encapsulate reusable code. At a higher level, the component is a custom element, and the Vue.js compiler adds special features to it. In some cases, a component can also be in the form of a native HTML element, which is extended in the IS attribute.

Working with Components

Registered

As I said before, we can create a component constructor with Vue.extend ():

var mycomponent = vue.extend ({
 //Options ...
})

To use this constructor as a component, you need to register with ' Vue.component (tag, constructor) ' * *:

Global registration component, tag for my-component
vue.component (' my-component ', mycomponent)

<p class= "Tip" > for a custom label name, Vue.js does not enforce the requirement to follow the rules of the game (lowercase, and contain a short bar), although it is better to follow this rule.

Once the component is registered, it can be used as a custom element <my-component> in the module of the parent instance. To ensure that the component is registered before the root instance is initialized:

<div id= "Example" >
 <my-component></my-component>
</div>

//define
var MyComponent = Vue.extend ({
 Template: ' <div>a custom component!</div> '
})

//Registration
Vue.component (' my-component ', mycomponent)

//Create root instance
new Vue ({
 el: ' #example '
})

Render as:

<div id= "Example" >
 <div>a custom component!</div>
</div>

Note that the template of the component replaces the custom element, and the custom element acts only as a mount point. You can use the instance option replace to decide whether to replace.

Local registration

You do not need to register each component globally. You can make a component available only in other components and register with the instance option components:

var child = Vue.extend ({/* ... */})

var Parent = vue.extend ({
 Template: ' ... ',
 components: {
 //< My-component> can only be used within the parent component Template
 ' my-component ': Child
 }
}

This encapsulation also applies to other resources, such as directives, filters, and transitions.

Register Grammar Candy

To make the event simpler, you can simply pass in the option object instead of the constructor to the Vue.component () and component options. Vue.js automatically calls Vue.extend () on the back:

Expand and register Vue.component in one step
(' my-component ', {
 Template: ' <div>a custom component!</div> '
}

//Local registration you can do this.
var Parent = vue.extend ({
 components: {
 ' my-component ': {
  Template: ' <div>a Custom component!</div> '
 }}}
)

Component Options Issues

Most of the options passed into the Vue constructor can also be used in Vue.extend (), but there are two exceptions: Data and El. Imagine if we simply passed an object as the data option to Vue.extend ():

var data = {A:1}
var mycomponent = vue.extend ({
 data:data
})

The problem with this is that all instances of ' mycomponent ' will share the same ' data ' Object! This is basically not what we want, so we should use a function as the ' data ' option to have this function return a new object:

 var mycomponent = vue.extend ({
 data:function () {return
 {a:1}}}
)

Similarly, the ' El ' option must also be a function when used in ' Vue.extend () '.

Template parsing

The Vue template is a DOM template that uses the browser native parser instead of implementing one yourself. There are some benefits to a DOM template compared to a string template, but there are also problems, and it must be a valid HTML fragment. Some HTML elements have restrictions on what elements can be placed inside it. Common limitations:
A cannot contain other interactive elements (such as buttons, links)
UL and ol can only contain Li directly
Select can only contain option and Optgroup
table can only directly include THEAD, Tbody, TFOOT, TR, caption, Col, Colgroup
tr can only contain th and TD directly

In practice, these restrictions can lead to unexpected results. Although it may work in a simple situation, you cannot rely on custom components to expand the results before the browser validates. For example, <my-select><option>...</option></my-select> is not a valid template, even if the My-select component eventually expands to <select> ...</select>.

Another result is that custom tags (including custom elements and special tags, such as <component>, <template>, <partial>) cannot be used in tags that are restricted to internal elements such as UL, select, table, etc. The custom tags placed inside these elements will be referred to the outside of the element, rendering it incorrect.

For custom elements, you should use the IS attribute:

<table>
 <tr is= "my-component" ></tr>
</table>

' cannot be used in ', then use ', '
' Can have multiple ':

<table>
 <tbody v-for= "item in Items" >
 <tr>even row</tr>
 <tr>odd row</ tr>
 </tbody>
</table>

Props

Passing Data using Props

The scope of the component instance is isolated. This means that the parent component's data cannot and should not be referenced directly within the subassembly's template. You can use props to pass data to a subassembly.

"Prop" is a field of component data that is expected to pass from the parent component. Subcomponents need to explicitly declare props with the props option:

Vue.component (' child ', {
 //Declaration props
 Props: [' msg '],
 ///prop can be used in the template
 //can be set
 with ' this.msg ' Template: ' <span>{{msg}}</span> '
})

Then pass it to a normal string:
<child msg= "hello!" ></child>

Hump vs. Cross bar type

HTML attributes are not case-sensitive. Prop used as an attribute when the name form is CamelCase, it needs to be converted to Kebab-case (short horizontal):

Vue.component (' child ', {
 //CamelCase in JavaScript
 props: [' mymessage '],
 Template: ' <span>{{ Mymessage}}</span> '
})

<!--kebab-case in HTML-->
<child my-message= "hello!" ></child>

Dynamic Props

Similar to binding HTML attributes to an expression with V-bind, you can also use V-bind to bind dynamic Props to the parent component's data. The child component is also transmitted whenever the data of the parent component changes:

<div>
 <input v-model= "parentmsg" >
 <br>
 <child v-bind:my-message= "Parentmsg" ></child>
</div>

The abbreviation syntax for using ' v-bind ' is usually simpler:
<child:my-message= "parentmsg" ></child>

literal syntax vs. dynamic syntax

One mistake beginners often make is to use literal syntax to pass values:

<!--passed a string "1"-->
<comp some-prop= "1" ></comp>
because it is a literal prop, its value is passed in the string ' "1" instead of the actual number. If you want to pass an actual JavaScript number, you need to use dynamic syntax so that its value is evaluated as a JavaScript expression:
<!--pass the actual digital-->
<comp:some-prop= "1" ></comp>

Prop binding Type

Prop default is one-way binding: when a parent component's properties change, it is passed to the subassembly, but the reverse does not. This is to prevent the child component from unintentionally modifying the state of the parent component-which makes the application's data flow difficult to understand. However, you can also use the. sync or. Once binding modifier modifier explicitly to force bidirectional or single binding:

Comparison syntax:

<!--default is one-way binding-->
<child:msg= "parentmsg" ></child>

<!--bidirectional binding-->
<child: Msg.sync= "Parentmsg" ></child>

<!--single bind-->
<child:msg.once= "Parentmsg" ></child >

The two-way binding synchronizes the Msg property of the component back to the Parentmsg property of the parent component. The change after a single binding is not synchronized after it is established.

Note If prop is an object or array, it is passed by reference. modifying it within a subassembly affects the state of the parent component, regardless of which binding type is used.

Prop Verification

Component can specify authentication requirements for props. This is useful when components are used by others, because these validation requirements form the component's API to ensure that others use the component correctly. At this point the value of the props is an object containing the validation requirements:

Vue.component (' example ', {
 props: {
 //underlying type detection (' null ' means any type can be)
 Propa:number,
 //multiple types (1.0.21+)
 propm: [String, number],
 //required and is a string
 PROPB: {
  type:string,
  required:true},//
 digits, There is a default value of
 propc: {
  type:number,
  default:100
 },
 //object/array defaults should be returned by a function
 propd: {
  type: Object,
  default:function () {
  return {msg: ' Hello '}}}
 ,
 //Specify this prop as bidirectional binding
 ///If the binding type is not Throw a warning
 prope: {
  twoway:true
 },
 //custom validation function
 Propf: {
  validator:function (value) {
  return value >
  {}
 },
 //conversion function (1.0.12 added)
 //Convert value before setting value
 PROPG: {
  coerce:function (val) {
  return val + '//convert value to String
  }
 },
 proph: {
  coerce:function (val) {
  Json.parse (val //Convert JSON string to Object}}
  }


Type can be the following native constructor:
string
number
Boolean
function
Object
Array

Type can also be a custom constructor, using instanceof detection.

When prop validation fails, Vue will refuse to set this value on the subassembly, and a warning will be thrown if the development version is used.

Parent-Child Component communication

Parent chain

A subassembly can access its parent component using this. $parent. Descendants of the root instance can access it using this. $root. The parent component has an array of this. $children, containing all of its child elements.

Although you can access any instance on the parent chain, the subcomponent should avoid directly relying on the data of the parent component and use props to pass the data as explicitly as possible. In addition, modifying the state of a parent component in a subassembly is a very bad practice because:
1. This makes the parent component tightly coupled to the subassembly;

2. It is difficult to understand the state of the parent component just by looking at the parent component. Because it may be modified by any subassembly! Ideally, only the component itself can modify its state.

Custom events

The Vue instance implements a custom event interface for communication in the component tree. This event system is independent of native DOM events and is used differently.

Each Vue instance is an event trigger:
• Use $on () to monitor events;

• Use $emit () to trigger events above it;

• Use $dispatch () to distribute events, and events are bubbling along the parent chain;

• Use $broadcast () broadcast event, and the event is passed down to all descendants.

Unlike DOM events, the Vue event automatically stops bubbling after the first triggering of a callback in the bubbling process, unless the callback explicitly returns TRUE.

Simple example:

<!--subassembly template-->
<template id= "Child-template" >
 <input v-model= "msg" >
 <button v-on: Click= "Notify" >dispatch event</button>
</template>

<!--parent component Templates--> <div id=
" Events-example ">
 <p>messages: {{Messages | json}}</p>
 <child></child>
< /div>/

/Register subassembly
//Send out the current message
vue.component (' child ', {
 template: ' #child-template ',
 data : function () {return
 {msg: ' Hello '}
 },
 methods: {
 notify:function () {
  if (This.msg.trim ()) {This
  . $dispatch (' child-msg ', this.msg)
  this.msg = '}}}}
)

//Initialize parent component
/ /push event into an array when message is received
= new Vue ({
 el: ' #events-example ',
 data: {
 messages: []
 },
 When creating an instance the ' events ' option simply invokes ' $on '
 events: {
 ' child-msg ': function (msg) {
  //Event callback ' This ' is automatically bound to the instance on which it is registered 
   this.messages.push (MSG)}}}
)

Using v-on to bind custom events

The example above is very good, but it is not intuitive to see where the "Child-msg" event comes from in the parent component's code. It would be better if we declared the event handler where the neutron component of the template was used. This subassembly allows you to listen for custom events with v-on:

<child v-on:child-msg= "Handleit" ></child>
This is clear: when the subassembly triggers the ' child-msg ' event, the parent component's ' Handleit ' method is invoked. All code that affects the state of the parent component is placed in the ' Handleit ' method of the parent component, and the child component only focuses on the triggering event.
Sub-component Index

Although there are props and events, there are times when you still need to access subcomponents directly in JavaScript. To do this you can use V-ref to specify an index ID for the subassembly. For example:

<div id= "Parent" >
 <user-profile v-ref:profile></user-profile>
</div>

var Parent = new Vue ({el: ' #parent '})
//Access subassembly
var child = parent. $refs

When V-ref and v-for are together, ref is an array or object that contains the corresponding subcomponents.

Distributing content using Slot

When using components, you often combine them like this:

<app>
 <app-header></app-header>
 <app-footer></app-footer>
</app >

Note two points:
The 1.<app> component does not know what the mount point will be, and the content of the mount point is determined by the <app> parent component.

The 2.<app> component is likely to have its own template.

In order for the components to be grouped, we need a way to mix the contents of the parent component with the child component's own template. This process is called content distribution (or "transclusion" if you are familiar with angular). Vue.js implements a content distribution API that references the current WEB component specification drafts and uses special <slot> elements as slots for the original content.

Compilation scope

Before we dive into the content distribution API, we'll be clear about the compilation scope of the content. Suppose the template is:

<child-component>
{{msg}}}
</child-component>

Should msg be bound to the parent component's data, or is it bound to the child component's data? The answer is the parent component. The component scope simply says:

The contents of the parent component template are compiled within the parent component scope; The contents of the child component template are compiled within the child component scope
A common error is an attempt to bind an instruction within a parent component template to a child component's property/method:

<!--Invalid-->
<child-component v-show= "Somechildproperty" ></child-component>

Assuming that Somechildproperty is a property of a subassembly, the previous example does not work as expected. The parent component template should not know the state of the subassembly.

If you want to bind instructions within a subassembly to the root node of a component, you should do so in its template:

Vue.component (' Child-component ', {
 //valid, because it is within the correct scope
 Template: ' <div v-show= ' Somechildproperty ' > Child</div> ',
 data:function () {return
 {
  somechildproperty:true
 }}}
)

Similarly, the distribution content is compiled within the parent component scope.

Single Slot

The contents of the parent component will be discarded unless the subassembly template contains <slot>. If the subassembly template has only one slot that has no attributes, the entire contents of the parent component are inserted where the slot resides and replaced.

The contents of the <slot> label are treated as fallback content. The rollback content is compiled within the scope of the child component, and the fallback content is displayed when the host element is empty and there is no content for insertion.

Assume that the My-component component has the following template:

<div>
  
 

Parent Component Template:
<my-component>
<p>this is some original content</p>
<p>this is some more original content</p>
</my-component>
Render Result:

<div>
  
 

Named Slot

<slot> elements can be configured to distribute content with a special attribute, name. Multiple slot can have different names. A named slot will match elements in the content fragment that correspond to the slot attribute.

You can still have an anonymous slot, which is the default slot, as a fallback slot that cannot find a matching piece of content. If there is no default slot, the content fragments that cannot find a match are discarded.

For example, suppose we have a multi-insertion component whose template is:

<div>
 <slot name= "One" ></slot>
 <slot></slot>
 <slot name= "two" > </slot>
</div>

Parent Component Template:

<multi-insertion>
 <p slot= "One" >One</p>
 <p slot= "Two" >Two</p>
 <p >default a</p>
</multi-insertion>

The render result is:

<div>
 <p slot= "One" >One</p>
 <p>default a</p>
 <p slot= "two" >two </p>
</div>

The content distribution API is a useful mechanism for composing components.

Dynamic components

Multiple components can use the same mount point and then dynamically switch between them. Dynamically binds to its is attribute using a reserved <component> element:

New Vue ({
 el: ' Body ',
 data: {
 currentview: ' Home '
 },
 components: {Home
 : {*/* ... * * *},< C19/>posts: {/* ... */},
 archive: {/* ... *}}
)

<component:is= "CurrentView" >
 <! --Components Change--> </component> when Vm.currentview change


Keep-alive

If you leave a switch in memory, you can keep its state or avoid rendering it again. To do this you can add a keep-alive instruction parameter:

<component:is= "CurrentView" keep-alive>
<!--inactive components will be cached-->
</component>

Activate hook

When you switch components, you may need to do some asynchronous operations before you cut into the component. To control the length of a component switch, add a activate hook to the plunge component:

Vue.component (' Activate-example ', {
 activate:function (done) {
 var self = this
 Loaddataasync (function ( Data) {
  Self.somedata = Data Done ()})}
)

Note that the ' activate ' hook is used only in the process of dynamic component switching or static component initialization rendering, not for manual insertion using instance methods.
Transition-mode

The Transition-mode attribute is used to specify how two dynamic components transition between.

By default, a smooth transition is entered and left. This feature can specify two other modes:
In-out: The new component transitions first, and the current component transitions out after its transition is complete.

out-in: The current component transitions first, and the new component transitions into after its transition is complete.

Example:

<!--fade out and fade in-->
<component
 : is= "View"
 transition= "
 fade" transition-mode= "out-in" >
</component>

fade-transition {
 transition:opacity. 3s ease
}
. Fade-enter,. fade-leave {
 opacity:0;
}

Miscellaneous

Components and V-for

Custom components can use V-for as normal elements:

<my-component v-for= "Item in Items" ></my-component>

However, you cannot pass data to the component because the scope of the component is isolated. To pass data to a component, you should use props:

<my-component
V-for= "Item in Items"
: item= "Item"
: index= "$index" >
</my-component>

The reason that the item is not injected into the component automatically is that it causes the component to be tightly coupled to the current v-for. Explicitly declares where the data comes from so that the component can be reused elsewhere.

Write Reusable components

When writing components, it is good to remember whether you want to reuse components. It doesn't matter that a one-time component is tightly coupled to other components, but a reusable component should define a clear, open interface.

The Vue.js component API comes from three parts--prop, events, and slot:
prop allows the external environment to pass data to the component;

• Events allow the component to trigger an action on the external environment;

slot allows the external environment to insert content into the component's view structure.

Using the shorthand syntax for V-bind and v-on, the indentation of the template is clear and concise:

<my-component
: foo= "Baz"
: bar= "Qux"
@event-a= "Dothis"
@event-b= "Dothat" >
<!--content-->

<p slot= "Main-text" >Hello!</p>
</my-component>

Asynchronous components

In large applications, we may need to split the application into small chunks and download them from the server only when needed. To make things simpler, vue.js allows components to be defined as a factory function that dynamically parses the definition of a component. Vue.js only triggers the factory function when the component needs rendering, and caches the results for subsequent rendering. For example:

Vue.component (' Async-example ', function (resolve, reject) {
 settimeout (function () {
 resolve ({
  Template: ' <div>i am async!</div> '
 }}
 , 1000)
})

The factory function receives a resolve callback, which is invoked when a component definition is received from the server. You can also call reject (reason) to indicate that the load failed. Here settimeout is just for demonstration. How to get the component is entirely up to you. It is recommended to use the Webpack code partitioning function:

Vue.component (' Async-webpack-example ', function (resolve) {
 //This special require syntax tells Webpack
 //automatically splits the compiled code into different blocks,
 //These blocks will be automatically downloaded via AJAX requests.
 require (['./my-async-component '], resolve)
})

Resource Naming conventions

Some resources, such as components and directives, appear in the template in the form of HTML attributes or HTML custom elements. Because the name of the HTML attribute and the name of the label are not case-sensitive, the name of the resource usually needs to be in the form of kebab-case rather than CamelCase, which is not convenient.

Vue.js supports the names of resources in the form of CamelCase or pascalcase, and automatically converts them to kebab-case in the template (similar to the prop naming convention):

Components in the component definition
: {
 ///register with CamelCase form
 mycomponent: {///}

<!--use kebab-case form in template -->
<my-component></my-component>

ES6 object literal abbreviation also no problem:

//pascalcase
import TextBox From './components/text-box ';
Import Dropdownmenu from './components/dropdown-menu ';

Export Default {
 components: {
 //writing in Templates <text-box> and <dropdown-menu>
 TextBox,
 Dropdownmenu
 }
}

Recursive components

A component can recursively call itself within its template, but only if it has the name option:

var StackOverflow = vue.extend ({
 name: ' Stack-overflow ',
 Template:
 ' <div> ' +
  //recursively calls itself
  ' <stack-overflow></stack-overflow> ' +
 ' </div> '
})

The above component will cause an error "Max stack size exceeded", so make sure that the recursive call has a termination condition. When you use Vue.component () to globally register a component, the component ID is automatically set to the component's name option.

Fragment instance

When you use the template option, the contents of the template replace the mount elements of the instance. Thus, the top-level element of the recommended template is always a single element.

Don't write templates like this:

<div>root node 1</div>
<div>root node 2</div>

The recommended way to write:

<div>
I have a single root node!
<div>node 1</div>
<div>node 2</div>
</div>

The following situations make an instance a fragment instance:
1. The template contains multiple top-level elements.
2. The template contains only plain text.
3. The template contains only other components (other components may be a fragment instance).
4. The template contains only one element instruction, such as <partial> or Vue-router <router-view>.
5. The template root node has a process control instruction, such as v-if or v-for.

These situations give an instance an unknown number of top-level elements that will take its DOM content as a fragment. The fragment instance will still render the content correctly. However, it does not have a root node whose $el point to an anchor node, an empty text node (a comment node in development mode).

But more importantly, non-process Control directives on component elements, prop attributes, and transitions are ignored because there is no root element for binding:

<!--No, because there is no root element-->
<example v-show= "OK" transition= "Fade" ></example>

<!--props can-->
<example:p rop= "Somedata" ></example>

<!--Process Control can be, but no transition-->
<example v-if= "OK" ></example>

Of course the fragment instance has its usefulness, but it is usually better to give the component a root node. It ensures that the instructions and attributes on the component elements are converted correctly, while the performance is slightly better.

Inline templates

If the subassembly has a inline-template attribute, the component treats its contents as its template rather than as a distribution. This makes the template more flexible.

<my-component inline-template>
<p>these are compiled as the component ' s own template</p>
<p>not Parent ' s transclusion content.</p>
</my-component>

However, Inline-template makes the scope of the template difficult to understand and does not cache the template compilation results. A best practice is to use the template option to define a template within a component.

This article has been organized into the "Vue.js front-end component Learning course", welcome to learn to read.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.