Components are used to encapsulate some functions of a page, and encapsulate the structure, style, and logical code of a function as a whole.

Improved functionality reusability and maintainability, and better focus on business logic.

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

The component registration

Global registration

Globally registered components can be used after registrationAny instance or componentIn the.

Note: Global registration must be set before the root Vue instance is created.

<body>
  <div id="app">
    <p>This is the P tag</p>
    <my-component></my-component>
  </div>
  
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('my-component', { 
      template: This is our globally registered component 
    });

    / / root instance
    new Vue({
      el: '#app'.data: {}})</script>
</body>
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.

Note that the only exceptions are root instance-specific options like EL. There is no EL because the root instance needs to be mounted to an element on the page, while the component is used by the root instance or by other components and does not need to be mounted to the page.

Component naming rules

Components have two naming conventions:

  • Kebab – case:'my-component'
  • PascalCase:'MyComponent'

Note: No matter which naming is used, only kebab-case is available in the DOM.

<body>
  <div id="app">
    <my-com-a></my-com-a>
    <! </MyComA> </MyComA>
    <my-com-b></my-com-b>
    <! -- <MyComB></MyComB>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // kebab-case to register
    Vue.component('my-com-a', {template: 
       
A component content
}) // PascalCase to register Vue.component('MyComB', { template: '
Contents of b component
'
}); new Vue({ el: '#app'.data: {}})
</script> </body> 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.

Note: The component must have only one root element. That is, no other element can be set at the level of

.
<body>
  <div id="app">
    <my-com-a></my-com-a>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('MyComA', {
      template: `
        <div>Here is the content of component A:{{ 1 + 2 * 3 }}
        </div>`}); new Vue({ el: '#app', data: { } });</script>
</body>
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 object.

This is implemented to ensure that each component instance can maintain a separate copy of the returned object without affecting each other. Because the scope of a function is only valid inside it.

ES6 abbreviations:

<body>
  <div id="app">
    <my-com-a></my-com-a>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('MyComA', {
      template: `
        <div>
          <h3>{{ title }}</h3>
          <p>{{ content }}</p>
        </div>', data () {return {title: 'This is the component title ', Content:' This is the component content '}}}); new Vue({ el: '#app', data: { } });</script>
</body>
Copy the code

Local registration

Locally registered components can only be used in the current instance or component. There are two ways to register:

1. Directly add it to the Vue instance

<body>
  <div id="app">
    <my-com-a></my-com-a>
    <my-com-b></my-com-b>
  </div>

  <div id="app2">
    <my-com-a></my-com-a>
    <my-com-b></my-com-b>
  </div>
  <script src="lib/vue.js"></script>
  <script>New Vue({el: '#app', data: {}, components: {// first name, must be quoted, otherwise not supported - link 'my-com-a': {template: '<div>
              <h3>{{ title }}</h3>
              <p>{{ content }}</p>
            </div>', data () {return {title: 'component A title ', content:' component A content '}}}, // The second naming method MyComB: {template: '<div>
              <h3>{{ title }}</h3>
              <p>{{ content }}</p>
            </div>', data () {return {title: 'component B', content:' component B content '}}}}}); new Vue({ el:"#app2" })</script>
</body>
Copy the code

2. Configure the option object of the component separately

Easier to maintain

ES6 short: (Less compatible than the above method)

<body>
  <div id="app">
    <my-component-a></my-component-a>
    <my-component-b></my-component-b>
  </div>
  <script src="lib/vue.js"></script>
  <script>Var MyComponentA = {template: '<div>
          <h3>{{ title }}</h3>
          <p>{{ content }}</p>
        </div>', data () {return {title: 'component A title ', content:' component A content '}}}; Var MyComponentB = {template: '<div>
          <h3>{{ title }}</h3>
          <p>{{ content }}</p>
        </div>', data () {return {title: 'component B', content:' component B content '}}} new Vue({el: '#app', data: {}, components: { 'my-component-a': MyComponentA, MyComponentB } });</script>
</body>
Copy the code

Component communication

The operation of passing data between components is called component communication. The delivery mode varies depending on the participating components.

Parent component passes value to child component

Receives a value from the parent component via the props option of the child component. Once accepted, you can use it directly in the template.

Pay attention to:propsDon’t withdataThere is an attribute with the same name, otherwise there will be an overwrite problem.

The parent component is set as follows:

  • A title without a colon is passed statically and cannot be changed.

  • The colon title is passed dynamically, and the text is quoted

<body>
    <div id="app">
        <my-component-a title="This is a static title." content="This is static content."></my-component-a>
        <! -- Bind dynamic content, common -->
        <my-component-a :title="item.title" :contnet="item.content"></my-component-a>
    </div>
    <script src="lib/vue.js"></script>
    <script>
        Vue.component("my-component-a",{
            props: ['title','content'],
            template:`
                <div>
                    <h3>{{ title }}</h3>
                    <p> {{ content }}</p>
                </div>`}) new Vue ({el: "# app," data: {item: {title: "title", content: "content"}}})</script>
</body>
Copy the code

Props naming rule

CamelCase is recommended for prop naming and kebab-case for parent component binding

<body>
  <div id="app">
    <! Create a component and generate content by iterating through data items with v-for -->
    <demo-item v-for="item in items" :key="item.title"
    :item-title="item.title" :item-content="item.content"></demo-item>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component("demoItem", {props: ["itemTitle"."itemContent"].template: ` 
       

{{ itemTitle }}

{{ itemContent }}

`
}) new Vue({ el: '#app'.data: { // Prepare data for use by child components items: [{title: 'Example Title 1'.content: 'Sample Content 1' }, { title: 'Example Title 2'.content: 'Sample Content 2' }, { title: 'Example Heading 3'.content: 'Sample Content 3'},]}})
</script> </body> Copy the code

Unidirectional data flow

All prop bindings between parent and child components are one-way downlink. Data changes in the parent component affect the child component, but data changes in the child component do not affect the parent.

If prop data is to be processed by a child component, it should be stored in data (or operated using computed properties).

Note: If prop is an array or object, child component operations will affect the state of the parent component. Because it’s a reference, it gets the address.

Solutions:

  1. Store data in data before performing operations
  2. Instead of passing an entire array or object, pass only the value of an attribute of the object.
<body>
  <div id="app">
    <my-component
      :initial-title="title"
      :obj="obj"
    ></my-component>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    Vue.component('my-component', {
      props: ['initialTitle'.'obj'].template: ` < div > {{title}} < button @ click = "fn" > button < / button > < / div > `,
      data () {
        return {
          title: this.initialTitle
          // title: this.initialTitle = "This is the new title"}},methods: {
        fn () {
          // this.title = 'This is the new title ';
          // this.initialTitle = 'This is the new title '; // Does not affect the parent component
          this.obj.name = 'jack'; // Causes the root name to change to Jack as well}}});new Vue({
      el: '#app'.data: {
        title: 'Here's the sample title'.obj: {
          name: 'william'.age: 18}}});</script>
</body>
Copy the code

Props type

Prop can set type checking, in which case you need to change props to an object with validation requirements and specify the corresponding type.

  • The corresponding constructor on the later Settings will do the trick. String and Array are constructors.

  • If the type is not limited, it can be null or undefined

Prop can also specify multiple types at the same time and can be stored as an array.

<body>
  <div id="app">
    <my-component
      :par-str="str"
      :par-num="num"
      :par-arr="arr"
      :par-obj="obj"
      :par-any="any"
      :par-data="str"
    ></my-component>
  </div>
  <script src="lib/vue.js"></script>
  <script>Vue.component('MyComponent', {// If you want to set the props rule, change it to object: {parStr: String, parNum: Number, parArr: Array, parObj: Object, parAny: undefined, // null parData: [String, Boolean] }, template: `<div>
          {{ parStr }}
          {{ parNum }}
          {{ parArr }}
          {{ parObj }}
          {{ parAny }}
          {{ parData }}
        </div>}) new Vue({el: '#app', data: {num: 100, STR: 'ABC ', arr: [1, 2, 3], obj: {content1: '#app', content2: '#app', data: {num: 100, STR:' ABC ', arr: [1, 2, 3], obj: {content1: '#app', content2: 'Example content 2'}, any: [1, 2, 3]}});</script>
</body>
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.

  • The previous type detection function passedtypeOption Settings.

Other options:

  • Required Sets the data to mandatory. (eg. required: true)

  • Default specifies the default value for the option, which takes effect when no data is passed by the parent component. (eg.default: 100)

  • Required and default cannot work on a prop at the same time, because required requires values to be passed.

Note: When the default value is an array or object, it must be in the form returned by the factory function.

Or:

  • validatorUsed to set the verification function to the prop passed in. Return isfalseVue. Js will issue a warning.Specific content rulesDetection.

Note: Data, methods and other functions of the instance cannot be used in the validation function. Props does validation before the instance is created, so it can’t use data, methods or anything like that. This refers to the Window, not the Vue instance.

The Props attribute

When a parent component sets an attribute to a child component, but the attribute is not received in props, it is automatically bound to the root element of the child component. Custom directives are also bound to the root element.

For example, if the parent element is bound to these values:

If these values are not accepted inside the child elements, they are bound to<div>On.

A special case

  1. If the component root element already has an attribute, the new attribute replaces the original value.

  2. The exception is class and style, where properties are automatically merged when both inside and outside are set.

  3. 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.

Case 1

  <div id="app">
    <my-component
      data-index="3"
      :title="' New heading content '"
      style="height: 200px;"
      class="colorRed"
    ></my-component>
  </div>

    Vue.component('MyComponent', {
      template: `
      <div data-index="Seven"
           title="The title of the old"
           class="abc" 
           style="width: 200px;">
        <p>This is the content of the component</p>
      </div>`});Copy the code

Case 2

  <div id="app">
    <my-component
      data-index="3"
      :title="' New heading content '"
      style="height: 200px;"
      class="colorRed"
    ></my-component>
  </div>
  
    Vue.component('MyComponent', {
      inheritAttrs: false,
      template: `
      <div data-index="Seven"
           title="The title of the old"
           class="abc" 
           style="width: 200px;">
        <p>This is the content of the component</p>
      </div>`});Copy the code

Child components pass values to parent components

The child passes the value to the parent through a custom event. When a child component makes a data change, it raises an event that the parent listens for.

For example, the item is a child component, and the shopping cart is the parent component. The parent component needs to count the number of goods, so it needs to transfer the value to the parent component when the number of child components changes.

A custom event is emitted via $emit() when the child component data changes. $emit() is a method on an instance of vue that can be passed a name internally to fire a custom event for that name. No manual trigger is required.

  • You are advised to use kebab-case to customize the event name. I’ll write it in the parent element@count-change

The parent listens for the child’s custom events and sets up handlers.

  • The parent component listenscount-changeWhen the event is triggered, thetotalCountSince the 1

Custom event pass values

It would be inconvenient to just tell the parent component that the event was triggered each time. Such as +5 each time, so you can pass values to the parent component.

A child component can pass a value to its parent when it fires an event.

  • $emit()The first argument is the name of the event to fire, and the second argument is the value passed (object, variable, etc.).

Method 1: Directly set the code for custom events

The parent component needs to receive the data passed by the child component when it listens for events.

Method two: by processing functions

  • Here,productCountis$emit()The value passed.

Components and v – model

When a V-model is used for a component, it needs to be implemented through props and custom events. Because components are independent of each other.

  • v-modelThere are built-in functions for incoming and receiving data, so there is no need to write:value="...", so the child component only needs to usepropsJust receive it.

  • Value is the value of the V-Model binding

  • $emit() can emit custom events as well as built-in events by making the input field emit $emit() events at @input (input event is monitored in real time and is called every time input is entered)

  • $event is the event object, target is the current input field, and value is the input data.

Method one:

<body>
  <div id="app">
    <p>The input box contains the following contents: {{iptValue}}</p>
    <com-input v-model="iptValue"></com-input>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    var comInput = {
      props: ["value"].template: `  `
    }

    / / root instance
    new Vue({
      el: '#app'.data: {
        iptValue: ' '
      },
      components: {
        comInput
      }
    });
  </script>
</body>
Copy the code

Method 2:

<body>
  <div id="app">
    <p>The input box contains the following contents: {{iptValue}}</p>
    <com-input v-model="iptValue"></com-input>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    var comInput = {
      props: ["value"].template: `  `.methods: {
        onInpt(event){
          this.$emit('input', $event.target.value)
        }
      }
    }

    / / root instance
    new Vue({
      el: '#app'.data: {
        iptValue: ' '
      },
      components: {
        comInput
      }
    });
  </script>
</body>
Copy the code

Non-parent components pass values

A non-parent component is a sibling component or two components that are completely unrelated.

Sibling components pass values

Sibling components can transfer data through parent components.

<body>
  <div id="app">
    <! -- Parent receives data from child A -->
    <com-a
      @value-change="value = $event"
    ></com-a>
    <! Parent component passes data to child component B -->
    <com-b
      :value="value"
    ></com-b>
  </div>
  <script src="lib/vue.js"></script>
  <script>
    // Subcomponent A: sends data
    Vue.component('ComA', {
      template: {{value}} < button@click ="$emit('value-change', value)" > send  ,
      data () {
        return {
          value: 'This is the data in component A'}}});// Subcomponent B: receives data
    Vue.component('ComB', {
      props: ['value'].template: '
       
Component B receives: {{value}}
'
}); // Root instance (parent component) new Vue({ el: '#app'.data: { // For data transfer value: ' '}})
</script> </body> Copy the code

EventBus (Any component passes values)

The EventBus is an independent event center that manages the transfer of values between different components. It is only responsible for transferring values, and does not store data itself.

EventBus manages component-passing operations through a new Vue instance, where components register and invoke events to pass data to the instance. It is usually stored in a separate file.

Advantages:

  1. There is not a lot of data in data that is irrelevant to the functionality of the current component.
  2. There is no need to find relationships between components.

Practice:

The component that sends data triggers a BUS event, and the component that receives data registers the corresponding event with the BUS.

  1. The component that sends data fires a BUS event

  • I used to clean it upthis.$emit(), referring to the VUE instance of the current component. Used herebus.$emit()Is to use thebusVue instance of the component, andbusCan be accessed by any component.
  1. The received event passes the bus registration corresponding event$on()Operation.

  • Created () is a lifecycle function, and because totalCount is used, it is processed after the instance is created.

  • Parameter 1: indicates the event name

  • Parameter two: event handler. The this in the arrow function refers to the current product-total component. Since the arrow function doesn’t modify this, because it doesn’t have this itself, the this it uses is the this inside the current environment (creat()), which is the instance of the current function. If you use a normal function here, you need to make a store externally.

<body>
  <div id="app">
    <h3>The shopping cart</h3>
    <product-item v-for="product in products" :key="product.id" :title="product.title"></product-item>
    <product-total></product-total>
  </div>
  <script src="lib/vue.js"></script>
  <script src="EventBus.js"></script>
  <script>
    Vue.component("productItem", {props: ['title'].template: ` < div > < span > name of commodity: {{title}}, commodity number: {{count}} < / span > < button @ click = "onChange" > + 1 < / button > < / div > `.data: function(){
        return {
          count: 0}},methods: {
        onChange(){
          // Trigger custom events for bus to pass data
          bus.$emit("countChange".1);
          this.count++;
        }
      }
    })

    Vue.component("productTotal", {template:{{totalCount}} '.data: function(){
        return {
          totalCount: 0}},created(){
        // Register events with bus and receive data
        bus.$on("countChange".(productCount) = > {
          this.totalCount += productCount; })}})var bus = new Vue();

    / / root instance
    new Vue({
      el: '#app'.data: {
        products: [{id: 1.title:The word "apple"
          },
          {
            id:2.title:"Banana"
          },
          {
            id: 3.title:"Orange"}}}]);</script>
</body>
Copy the code

Other value transmission methods

It is not recommended if there are no special requirements. It’s harder to fix mistakes when they go wrong.

$root

$root is used to access the current component root instance, which can be used to pass component values when setting up simple Vue applications.

In addition to $root, vue. js provides $parent and $children for easy access to parent and child components.

  • Both A and B components access the vUE root instance directlycount.
<body>
  <div id="app">
    <com-a></com-a>
  </div>
  <script src="lib/vue.js"></script>
  <script>Var ComB = {template: '<div>The component B:{{ $root.count }}
          <button @click="clickFn">button</button>
        </div>`, methods: { clickFn () { this.$root.count = 200; }}}; Var ComA = {template: '<div>A component is A:{{ $root.count }}
          <button @click="clickFn">button</button>
          <com-b></com-b>
        </div>`, methods: { clickFn () { this.$root.count = 100; } }, components: { ComB } }; New Vue({el: '#app', data: {count: 0}, components: {ComA}});</script>
</body>
Copy the code

Click the A button to change count to 100; Click the B button and the count changes to 200.

$refs

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

By setting the ref attribute to a normal HTML tag, $refs retrieves the DOM object.

  • throughthis.$refs.inpAccess to<input>Tag, set itfocus()You can make<input>Automatically get focus.

Component slot

Subsequent complement

Built-in component

Subsequent complement