Vue. Js components

Components are reusable Vue instances. Components are used to encapsulate some functions of a page, and encapsulate the structure, style, and logical code of a function as a whole. This improves the reusability and maintainability of functionality, allowing us to focus better on business logic.

The component is a custom HTML tag. The component name is used as the custom tag name.

<div id="app">
  <! -- Normal p tag -->
  <p>This is the P tag</p>
  <! -- Vue.js component -->
  <my-component></my-component>
</div>
Copy the code

The official documentation

The component registration

Component creation.

Global registration

Globally registered components can be used in any VUE instance or component.

// Global component registration must precede root instance creation
Vue.component('my-component', { 
  template: This is our globally registered component 
})

/ / root instance
new Vue({
  el: '#app'.data: {}})Copy the code

use

<! App2 vUE instance app2 vUE instance app2 vUE instance app2
<div id="app">
  <p>This is the P tag</p>
  <! -- Vue.js component -->
  <my-component></my-component>
</div>
Copy the code

Component based

Components are essentially reusable VUE instances, so they can receive the same options as new VUE, such as Data, methods, and lifecycle hooks. But options like EL are specific to the root instance, and components cannot receive el options.

Component naming rules

First (dash split), kebab-case: ‘my-component’

Second (uppercase, camel name), PascalCase: ‘MyComponent’

// kebab-case to register
Vue.component('my-com-a', {
  template: '
      
This is the content of a component
'
}); // PascalCase to register Vue.component('MyComB', { template: '
This is the content of the B component
'
}); Copy the code

But no matter which way you write it, only kebab-case can be used in the DOM.

<! -- Component usage -->
<my-com-a></my-com-a>
<my-com-b></my-com-b>
Copy the code

The template options

The template option is used to set the structure of the component, which is eventually introduced into the root instance or other components.

Vue.component('MyComA', {
  template: This is the content of component A: {{1 + 2 * 3}}  '
})
Copy the code

The data options

The data option is used to store the component’s data. Unlike the root instance, the component’s data option must be a function, and the data is set in the return value of the function. This is done to ensure that each component instance can maintain its own copy of the returned object without interfering with each other.

Vue.component('MyComA', {
  template: ` 
      

{{ title }}

{{ content }}

`
, data () { return { title: 'This is the component title'.content: 'This is component content'}}})Copy the code

Local registration

A partially registered component can only be used in the current instance.

new Vue({ el: '#app', data: { }, components: { 'my-com-a': { template: ` < div > < h3 > {{title}} < / h3 > < p > {{content}} < / p > < / div > `, data () {return {title: 'component A title, the content: 'Component A contents'}}},}});Copy the code

use

<div id="app">
  <my-com-a></my-com-a>
</div>
Copy the code

Configure the option object for the component separately

If there are too many local components, it is not very convenient to modify the content of component options. In this case, it is much easier to configure the component option object separately, which helps improve maintainability.

// The option object for component A
var MyComponentA = {
  template: ` 
      

{{ title }}

{{ content }}

`
, data () { return { title: 'Component A heading'.content: 'Component A contents'}}};// The option object for component B var MyComponentB = { template: `

{{ title }}

{{ content }}

`
, data () { return { title: 'component B'.content: 'Component B content'}}}new Vue({ el: '#app'.data: {},components: { 'my-component-a': MyComponentA, MyComponentB MyComponentB: MyComponentB}})Copy the code

Component communication

Component communication refers to the operation of transferring data between components.

Parent component passes value to child component

Receives a value from the parent component via the props option of the child component.

// Create a child component
Vue.component('my-component-a', {
  // The props option should not have the same attribute as the data option, otherwise there will be overwriting problems
  props: ['title'.'content'].template: ` 
      

{{ title }}

{{ content }}

`
}) new Vue({ el: '#app'.data: { item: { title: 'Here's the sample title'.content: 'Here's the sample content'}}})Copy the code

Receive data using the props option

<! -- Static property Settings -->
<my-component-a 
  title="This is a static title."
  content="This is static content."
></my-component-a>

<! -- Dynamic property binding -->
<my-component-a
  :title="item.title"
  :content="item.content"
></my-component-a>
Copy the code

Props naming rules: It is recommended to use camelCase for prop naming and kebab-case for parent component binding.

The official documentation

Unidirectional data flow

All prop between parent and child components are bound one-way down, which is called the one-way data flow feature of a component prop. That is, if the parent component value changes, the prop value of the child component changes; otherwise, the change of the prop value of the child component does not affect the parent component value.

If prop data is to be processed by a child component, it should be stored in data to avoid processing prop data directly.

Vue.component('my-component', {
  props: ['innerTitle'].template: ` 
      

{{ title }}

`
, data () { return { title: this.innerTitle } } }) Copy the code

Note: If prop is an array or an object, child operations on it affect the state of the parent. Because arrays or objects are passed addresses by the parent component, due to the prop one-way data flow feature, we cannot change the address reference of arrays or objects, but we can change their internal property values, which affects the parent component as well.

There are two ways to eliminate this effect:

  • When an array or object is passed in, a copy of it is stored in data and then manipulated
  • Instead of passing in arrays, pass in values that the child components need

Props type

When you declare props, you can also set the type of the value that can be received, and Vue will report an error if the value passed does not match the set type.

props: {
  parStr: String.parNum: Number.parArr: Array.parObj: Object.parAny: undefined.// null
  parData: [String.Boolean]},Copy the code

Props to verify

When multiple rules need to be set on prop, you can set the value of prop as an option object.

props: {
  // Basic type checking (' null 'and' undefined 'will pass any type verification)
  propA: Number.// Multiple possible types
  propB: [String.Number].// A mandatory string
  propC: {
    type: String.required: true
  },
  // A number with default values
  propD: {
    type: Number.default: 100
  },
  // Objects with default values
  propE: {
    type: Object.// Object or array defaults must be obtained from a factory function
    default: function () {
      return { message: 'hello'}}},// Customize the validation function
  propF: {
    validator: function (value) { 
      // Vue will prompt you with an error if the return value is false
      This value must match one of the following strings
      return ['success'.'warning'.'danger'].indexOf(value) ! = = -1}}},Copy the code

Note: Data, methods and other functions of the instance cannot be used in the verification function. Because the validation process is done before the instance is created.

The props attribute

When a parent component gives a property to a child component that does not exist in the props, it is automatically bound to the root element of the child component.

If the component root element already has an attribute, the value inside the component is replaced. The exception is the class and style attributes, which are automatically merged when both inside and outside are set.

If you don’t want to inherit properties set by the parent component, you can set inheritAttrs: False, but only for ordinary properties, leaving class and style unaffected.

Vue.component('MyComponent', {
  inheritAttrs: false.template: '
});
Copy the code

The value of

<div id="app">
  <my-component
    data-index="3"
    :title="' Sample header content '"
    style="height: 200px;"
    class="colorRed"
  ></my-component>
</div>
Copy the code

Child components pass values to parent components

When the parent passes a value, the child is processed and may need to return the processed result to the parent. For example, if an item is a child component and a shopping cart is a parent component, the parent component needs to obtain the number of items, so the child component needs to pass the value to the parent component when the number changes.

The child component sends a value to the parent component by firing a custom event via $emit(), and the parent component listens for the custom event to fetch the value. You are advised to use kebab-case (dash dash) to name user-defined events.

Child components

Vue.component('ProductItem', {
  props: ['title'].template: 
      
{{title}} {{ count }}
`
, data () { return { count: 0}},methods: { countIns1 () { // 1 is the value to be passed this.$emit('count-change'.1); this.count++; }, countIns5 () { // 5 is the value to be passed this.$emit('count-change'.5); this.count += 5; }}});Copy the code

The parent component

new Vue({
  el: '#app'.data: {
    products: [{id: 1.title: 'A catty of apples'
      },
      {
        id: 2.title: 'A banana'
      },
      {
        id: 3.title: 'One orange'}].totalCount: 0
  },
  methods: {
    onCountChange (productCount) {
      this.totalCount += productCount; }}});Copy the code

The value of

<div id="app">
  <h3>The shopping cart</h3>
  <product-item
    v-for="product in products"
    :key="product.id"
    :title="product.title"
    
    @count-change="onCountChange"
  ></product-item>
  <p>{{totalCount}}</p>
</div>
Copy the code

Components and v – model

When v-model is used for components, it needs to be implemented using props and custom functions.

Child components

/ / child component
var ComInput = {
  props: ['value'].template: `  `.// @input="$emit('input', $event.target.value)"
  methods: {
    onInput (event) {
      this.$emit('input', event.target.value)
    }
  }
}
Copy the code

The parent component

new Vue({
  el: '#app'.data: {
    iptValue: ' '
  },
  components: {
    ComInput
  }
});
Copy the code

The value of

<div id="app">
  <p>The input box contains the following contents: {{iptValue}}</p>
  <com-input v-model="iptValue"></com-input>
</div>
Copy the code

Non-parent components pass values

The first method is to relay data through the parent component:

Sibling component B-> parent component A-> sibling component C

However, when the nested relationship of components is complex, this way of transferring values is more complicated.

The second method, EventBus, is also called the EventBus

EventBus

The EventBus is an independent event center that manages the transfer of values between different components.

EventBus manages component-passing operations through a new Vue instance, where components register and invoke events to pass data to the instance. The component that sends data triggers a BUS event, and the component that receives data registers the corresponding event with the BUS.

Create the eventbus.js file

// Eventbus. js file contents
const bus = new Vue()
Copy the code

Introducing the EventBus. Js

<script src="lib/vue.js"></script>
<! -- Eventbus.js after vue.js -->
<script src="EventBus.js"></script>
Copy the code

Component A

// Commodity components
Vue.component('ProductItem', {
  template: {{count}}+1  ',
  data () {
    return {
      count: 0}},methods: {
    countIns () {
      // Trigger custom events for bus to pass data
      bus.$emit('countChange'.1);
      this.count++; }}});Copy the code

The component B

// Count components
Vue.component('ProductTotal', {
  template: '

total number: {{totalCount}}

'
, data () { return { totalCount: 0 } }, created () { // Register events with bus and receive data bus.$on('countChange'.(productCount) = > { // After the instance is created, you can use data and other functions this.totalCount += productCount; }); }})Copy the code

The root instance

/ / root instance
new Vue({
  el: '#app'.data: {}});Copy the code

EventBus can transfer values between any component. This is just an example of sibling components

<div id="app">
  <h3>The shopping cart</h3>
  <product-item></product-item>
  <product-total></product-total>
</div>
Copy the code

Other means of communication

There are two ways to manipulate other components directly:

  • $root

    Used to access the current component root instance and to pass values between components.

    It is not recommended to be used in small test components.

    The official documentation

    In addition, $parent, $children, and $root are similar for easy access to parent and child components. It is not recommended for ordinary use.

  • $refs

    The ref attribute assigns an ID reference to an HTML tag or component for direct access in JavaScript.

    $refs, used after the page is rendered to get the HTML tag or subcomponent with the ref attribute set.

    The official documentation

    component

    var ComA = {
      template: '
            
    Component A contents: {{value}}
    '
    , data () { return { value: 'Sample content'}}}var vm = new Vue({ el: '#app'.methods: { fn () { this.$refs.comA.value = 'New content'}},components: { ComA }, // execute after the page is rendered mounted () { console.log(this.$refs) this.$refs.comA.value = "Modified content"}})Copy the code

    HTML

    <div id="app">
      <! Set the ref attribute to the child component -->
      <com-a ref="comA"></com-a>
      <button @click="fn">button</button>
    </div>
    Copy the code

Component slot

Component slots allow you to easily set component contents.

<! Components without component slots cannot set content like normal HTML tags.
<com-a></com-a>

<! -- Components with component slots can be easily set component content -->
<com-b>This is a component with slots</com-b>
Copy the code

A single slot

Slot Settings are required using
.

Vue.component('ComA', {
  template: Components ` < div > < h3 > title < / h3 > < slot > this is the default content of slot < / slot > < / div > `,
  data () {
    return {
      value: 'Child component data'}}});Copy the code

Setting component content

<div id="app">
  <com-a>This is the content of the component</com-a>
  <com-a>This is the content of the second component:<span>This is span</span>
  </com-a>
  <com-a>Here is the parent component's view template, which can only use the parent's data: {{parValue}}</com-a>
  <com-a></com-a>
</div>
Copy the code

A named slot

If there are multiple locations in the build that require slots, give

a name as required. Such named slots are called named slots.

If

is not set to name, the default name is default.

/ / child component
Vue.component('ComA', {
  template: ` 
      
`
}); Copy the code

Setting component content

<div id="app">
  <com-a>
    <template v-slot:header>
      <h3>The header content of the component</h3>
    </template>
    <! -- <template v-slot:default> <p> The body of the component 1</p> <p> The body of the component 2</p> </template> -->
    <! -- equivalent to the comment section above -->
    <p>Body content of the component 1</p>
    <p>Body content of the component 2</p>
    <! -- slot: # -->
    <template #footer>
      <p>Component Bottom Content</p>
    </template>
  </com-a>
</div>
Copy the code

Scope slot

A normal slot can only use parent component data, whereas a scoped slot can use child component data.

The component uses V-bind to

the data that needs to be used by the slot. This property for passing data to the slot is called slot prop.

// Option object for child component B
var ComB = {
  template: ` < div > < p > the content of the component B: < / p > < slot: value = "value" : num = "num" > < / slot > < / div > `,
  data () {
    return {
      value: 'This is the data inside component B.'.num: 200}}}// The option object of child component A
var ComA = {
  template: 
      

Contents of component A:

`
, data () { return { value: 'This is the data inside component A.'.num: 100}}}Copy the code

Setting component content

<div id="app">
  <! -- Multiple slots with scope slot writing mode -->
  <com-a>
    <template v-slot:default="dataObj">
      {{ dataObj.value }}
      {{ dataObj.num }}
    </template>
    
    <template v-slot:footer="dataObj">
      {{ dataObj.value }}
    </template>
  </com-a>
  <! -- Slot writing with default slot scope only -->
  <! -- <com-b v-slot="dataObj"> -->
  <com-b #default="dataObj">
    {{ dataObj }}
  </com-b>
  <! Receive data from scope slot via ES6 destruct operation
  <com-b v-slot="{ value, num }">
    {{ value }}
    {{ num }}
  </com-b>
</div>
Copy the code

Built-in component

Dynamic components

Dynamic components are suitable for handling the frequent switching of multiple components. Such as TAB switching and so on.

< Component > is used to render a ‘meta-component’ as a dynamic component, with the IS attribute determining which component to render.

<! -- Component sets dynamic components -->
<component :is="currentCom"></component>
Copy the code

We can do this by dynamically changing the component currentCom points to.

<div id="app">
  <! -- The button represents the title function of the TAB -->
  <button
    v-for="title in titles"
    :key="title"
    @click="currentCom = title"
  >
    {{ title }}
  </button>
  <! -- Component sets dynamic components -->
  <component :is="currentCom"></component>
</div>
<script src="lib/vue.js"></script>
<script>Var ComA = {template: 'sets the subcomponent option object to switch<p>Here is the content of component A:<input type="text"></p>
  };  
  var ComB = {
    template: `<p>This is the content of component B:<input type="text"></p>
  };
  var ComC = {
    template: `<p>Here is the content of component C:<input type="text"></p>}; New Vue({el: '#app', data: {// All components titles: ['ComA', 'ComB', 'ComC'], { ComA, ComB, ComC } });</script>
Copy the code

Keep alive – components

The keep-alive component can be used if we want to avoid rerendering or preserving the component state during the dynamic component switch.

<! Set which components will be cached by include -->
<! -- No Spaces between string comma delimiters -->
<! -- <keep-alive include="ComA,ComB,ComC"> -->
<! -- <keep-alive :include="['ComA', 'ComB', 'ComC']"> -->
<! -- <keep-alive :include="/Com[ABC]/"> -->
<! Exclude specifies which components will not be cached.
<! -- <keep-alive exclude="ComD"> -->
<! -- <keep-alive :exclude="['ComD']"> -->
<! -- <keep-alive :exclude="/ComD/"> -->
   
<! -- Set the maximum number of cache components -->
<keep-alive max="2">
  <! -- Dynamic Component -->
  <component :is="currentCom"></component>
</keep-alive>
Copy the code

Transitional components

Provides a variety of transitions and animations for Vue when inserting, updating, or removing the DOM. Mainly include:

  • The transition component
  • Custom transition class name
  • The transition – group components

The transition component

Used to provide entry and exit transitions for elements and components:

  • Conditional Rendering (V-IF)
  • Conditional Display (V-show)
  • Dynamic components
  • Component root node
<transition>
  <p v-if="show">hello world</p>
</transition>
Copy the code

The component provides six classes for setting the concrete effects of transitions.

<style>
  /* Sets the final state of the appearance */
  .v-leave-to {
    opacity: 0;
  }
  /* Set the execution of the transition */
  .v-leave-active {
    transition: opacity 1s;
  }
  /* Sets the initial state of entry */
  .v-enter {
    opacity: 0;
  }
  /* Sets the final state of entry */
  .v-enter-to {
    opacity: 0.5;
  }
  /* Set up the entry process */
  .v-enter-active {
    transition: all 1s;
  }
</style>
Copy the code

Transition component related properties

  • The name attribute can be used to set different transition effects for multiple elements and components. In this case, you need to change the form of V – to the corresponding name-.

    Such as:

    The corresponding class name prefix is demo-Enter, etc.

  • By setting the Appear property, you can transition components during initial rendering.

Custom transition class name

Custom class names take precedence over regular class names and are useful when using third-party CSS animation libraries.

The attributes used to set the custom transition class name are as follows:

  • enter-class
  • enter-active-class
  • enter-to-class
  • leave-class
  • leave-active-class
  • leave-to-class

The properties used to set the initial transition class name are as follows:

  • appear-class
  • appear-to-class
  • appear-active-class
<transition
  enter-active-class="test"
  leave-active-class="test"
>
  <p v-if="show">This is the P tag</p>
</transition>
Copy the code

Animate.css

Animate. CSS is a third-party CSS animation library that uses class names to Animate elements.

The Animate. CSS website

CDN reference

<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css"
/>
<! -- Compatible version of the animate__ prefix is not required, but the full version is recommended.
<! - "https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.compat.css" -- >
Copy the code

use

<! -- Add a third party animation library class name effect to the component using custom transition class name Settings -->
<transition
  enter-active-class="animate__bounceInDown"
  leave-active-class="animate__bounceOutDown"
>
  <! Animate__animated --> Animate__animated --> Animate__animated
  <p 
    v-if="show"
    class="animate__animated"  
  >hello world</p>
</transition>
Copy the code

Matters needing attention:

  • Animate__ prefix version and compat version selection problem, recommend to choose prefix version
  • Remember the base class name animate__animated

The transition – group components

is used to animate a series of elements.

  • The tag attribute is used to set container elements, which default to<span>
  • Transitions are applied to inner elements, not containers
  • Child nodes must have independent keys for the animation to work properly
<transition-group
  tag="ul"
>
  <li
    v-for="item in items"
    :key="item.id"
  >
    {{ item.title }}
  </li>
</transition-group>
Copy the code

When a list element changes and the element moves, you can set the effect of the move by using the.v-move class name

.v-move {
  transition: all .5s;
}
Copy the code

The other transition styles are set the same as the Transition component.