vue2.x study notes (twelve)

Then the previous content: https://www.cnblogs.com/yanggb/p/12592256.html .

Component basics

Componentization is an important feature of vue and a very important knowledge point in vue learning.

Basic example

Here is an example of a vue component:

// Define a new component named button-counter 
Vue.component ('button-counter' , { 
  data: function () {
     return { 
      count: 0 
    } 
  }, 
  template: '<button v-on: click = "count ++ "> You clicked me {{count}} times. </ Button> ' 
})

It can be seen from the above example that the component is created using the [Vue.component ()] method, and the content of the component is written in the template attribute. The component is a reusable vue instance with a name (in this example, <button-counter>). After creating the component, we can use this component as a custom element in a vue root instance created by new Vue.

<div id="components-demo">
  <button-counter></button-counter>
</div>
new Vue ({the: '# components-demo'})

Because components are reusable vue instances, they receive the same options as new Vue, such as data, computed, watch, methods, and lifecycle hook functions. The only exceptions are options specific to root instances like el.

Component reuse

After the component is created, the component can be reused any number of times.

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

Each time a component is used, a new instance of it is created, and each instance maintains its own properties independently, because each instance has its own private scope and does not share data.

data must be a function

In the above example, when defining the <button-counter> component, you may find that its data does not directly provide an object like this:

data: {
  count: 0
}

Instead, the data option of a component must be a function, so each instance can maintain an independent copy of the returned object:

data: function () {
  return {
    count: 0
  }
}

If vue does not have this rule, component instances will affect each other, because the data is shared at this time. The purpose of the return function is this, because the javascript function will create its own private scope when it is executed, so that the data in a single component instance is isolated from the data in other component instances. Students who are not sure can go to understand the relevant knowledge about closure in JavaScript, which is determined by the characteristics of JavaScript language design itself.

Component organization

Usually an application will be organized in the form of a nested component tree:

For example, you may have components such as page headers, sidebars, and content areas, and each component contains other components such as navigation links and blog posts. In order to be able to use in the template, these components must first be registered so that vue can recognize it. The registration types of components can be divided into two types: global registration and local registration. In all the previous content, components are only registered globally through the [Vue.component ()] method.

Vue.component('my-component-name', {
  // ... options ...
})

Globally registered components can be used in any newly created (through new Vue) vue root instance after it is registered, as well as in all child component templates in its component tree.

Partial registration methods and other knowledge of component registration will be learned later in the chapter of in-depth understanding of components. Here we will first understand here.

Pass props to subcomponents

The thing about creating a blog post component was mentioned above. One problem is that if you ca n’t pass the data such as the title or content of a blog post to this component, we ca n’t use it because it has no data source and does n’t know what the data is Where to come. Therefore, the prop attribute came into being.

The prop property is some custom properties that vue provides to developers to register on the component. When a value is passed to a prop property, it will automatically become a property of that component instance. For example, to pass a title to a blog post component, we can use a [props] option to include it in the list of props that the component can accept.

Vue.component('blog-post', {
  props: ['title'],
  template: '<h3>{{ title }}</h3>'
})

A component can have any number of props by default, and any value can be passed to any prop. In the above template, we can access this value in the component instance, just like accessing the value in data.

After a prop is registered, you can pass the data to the component as a custom property like this.

<blog-post title="i like yanggb"></blog-post>
<blog-post title="i do like yanggb"></blog-post>
<blog-post title="i really like yanggb"></blog-post>

However, in a typical application, you may have an array of blog posts in the data:

new Vue({
  el: '#blog-post-demo',
  data: {
    posts: [
      { id: 1, title: 'i like yanggb' },
      { id: 2, title: 'i do like yanggb' },
      { id: 3, title: 'i really like yanggb' }
    ]
  }
})

And want to render a component for each blog post:

<blog-post
  v-for="post in posts"
  v-bind:key="post.id"
  v-bind:title="post.title"></blog-post>

As shown above, you will find that we can use the [v-bind] command to dynamically pass props. This is very useful when you are not clear about the specific content to be rendered at the beginning, such as when obtaining a list of blog posts from an api.

Single root element

When building a <blog-post> component, your template will eventually contain more than one title, at least the body of this blog post:

<h3>{{ title }}</h3>
<div v-html="content"></div>

But if you try to write this in the template, vue will display an error and explain [every component must have a single root element], that is, each component must have only one root element. If this happens, you can fix the problem by wrapping the content of the template in a parent element.

<div class="blog-post">
  <h3>{{ title }}</h3>
  <div v-html="content"></div>
</div>

Listen to subcomponent events

When we develop the <blog-post> component, some of its functions may require us to communicate with the parent component. For example, we may introduce an auxiliary function to enlarge the font size of the blog post, while keeping the default font size for other parts of the page.

In the parent component, first support this feature by adding a postFontSize data attribute.

new Vue({
  el: '#blog-posts-events-demo',
  data: {
    posts: [/* ... */],
    postFontSize: 1
  }
})

Then you can use this data attribute to control the font size (package component) of all blog posts in the template.

<div id="blog-posts-events-demo">
  <div :style="{ fontSize: postFontSize + 'em' }">
    <blog-post
      v-for="post in posts"
      v-bind:key="post.id"
      v-bind:post="post"
    ></blog-post>
  </div>
</div>

Then we add a button in front of each blog post to enlarge the font size:

Vue.component('blog-post', {
  props: ['post'],
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <button>
        Enlarge text
      </button>
      <div v-html="post.content"></div>
    </div>
  `
})

The problem is that this button does nothing:

<button>
  Enlarge text
</button>

Therefore, when clicking this button, we need to tell the parent component to enlarge the text of all blog posts, and the vue instance provides a system of custom events to solve this problem.

The parent component can listen to any event of the child component instance through the [v-on] instruction as if it were a native dom event:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += 0.1"></blog-post>

At the same time, the subcomponent can trigger an event by calling the built-in [$ emit] method and passing in the event name:

<button v-on:click="$emit('enlarge-text')">
  Enlarge text
</button

With this listener, the parent component will receive the event and update the value of postFontSize.

The example given in the official documentation is not very clear, and the explanation is not in place. It may be difficult to understand. In fact, the simpler understanding is that the parent component defines a method on the page, and passes this method to the child component through the [v-on: method name] instruction, and then the child component uses the global attribute provided by vue [$ emit ] To get the method passed by the parent component and bind it to the click event through the [v-on] instruction. I will learn more about the relevant knowledge of [$ emit] later.

Use event to throw a value (pass parameter)

Sometimes it is very useful to use an event to throw a specific value (passing parameters). For example, we may let the <blog-post> component decide how much to enlarge its text. At this time, you can use [$ emit] The second parameter to provide this value:

<button v-on:click="$emit('enlarge-text', 0.1)">
  Enlarge text
</button>

Then when listening to this event in the parent component, we can access the value that was thrown through [$ event]:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"></blog-post>

Or, if this event handler function is a method:

<blog-post
  ...
  v-on:enlarge-text="onEnlargeText"></blog-post>

Then this value will be passed into the method as the first parameter:

methods: {
  onEnlargeText: function (enlargeAmount) {
    this.postFontSize += enlargeAmount
  }
}

[$ Event] here is also a global attribute provided by vue, which means the event itself, and the default is the first parameter of the handler function that triggers the event. In the above example, when the subcomponent passes the parameter through [$ emit], the first parameter is overwritten, so the value of the $ event variable becomes the passed value, which belongs to a special usage. You can try to execute the function in the subcomponent without passing parameters. You will find that the value of [$ event] at this time is the event itself.

Use the [v-model] command on the component

Custom events can also be used to create custom input components that support the [v-model] instruction.

The first thing to know is that when the [v-model] instruction is used on a form element, it is actually equivalent to the combination of the [v-bind: value] instruction and the [v-on: input] instruction.

<input v-model="searchText">
<!-- 等价于 -->
<input
  v-bind:value="searchText"
  v-on:input="searchText = $event.target.value">

When used in components, [v-model] is equivalent to:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"></custom-input>

Therefore, in order for the [v-model] instruction to work properly on a custom component, the <input> in this component must:

1. Bind its value attribute to a prop called value.

2. When the input event is triggered, the new value is thrown through the custom input event.

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)">
  `
})

In this way, the [v-model] instruction should work perfectly on this custom component:

<custom-input v-model="searchText"></custom-input>

The secret is to use [$ emit] to throw the parameter value.

Distribute content through slots

Like the html element, we often need to pass content to a component, like this:

<alert-box>
  Something bad happened.
</alert-box>

Therefore, vue provides a custom <slot> element to achieve this function.

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
      <slot></slot>
    </div>
  `
})

The slot is equivalent to a placeholder mechanism. When the child component is used, the parent component inserts the required html content into the element of the child component, and the child component automatically replaces the placeholder. The content of the slot is very important and will be studied in detail later.

Dynamic component

Sometimes, it is very useful to dynamically switch between different components. For example, in a multi-tab interface, you can switch between different components through the vue <component> element and add a special [is] attribute Show hidden purpose.

<!- Component will change when `currentTabComponent` changes- > 
< component v-bind: is =" currentTabComponent " > </ component >

In this example, the currentTabComponent attribute can include the name of the registered component or a component's options object.

It should be noted that this attribute can be used for regular HTML elements, but these elements will be treated as components, which means that all attributes will be bound as dom attributes. For object properties like value, if you want it to work as expected, you need to use the [.prop] modifier.

Considerations when parsing dom templates

Some HTML elements, such as <ul>, <ol>, <table>, and <select>, are strictly limited to which elements can appear inside them. Some elements, such as <li>, <tr>, and <option>, can only appear inside other specific elements. This will cause us to encounter some problems when using these constrained elements.

<table>
  <blog-post-row></blog-post-row>
</table>

In the above example, the custom component <blog-pos-row> will be promoted to the outside as invalid content and cause the final rendering result to be wrong. In order to solve such problems, vue provides a special [is] attribute as a workaround.

<table>
  <tr is="blog-post-row"></tr>
</table>

The attribute value is the component name, which is equivalent to putting a coat <tr> on the component, which avoids the problem of rendering errors.

Also note that when we use templates from the following sources, this restriction does not exist:

1. String (for example template: '...').

2. Single file component (.vue file).

3.<script type="text/x-template">。

At this point, vue's related basic knowledge has been learned in seven, seven or eight, and then it is time to learn some more in-depth knowledge.

 

"I still like you very much, like the ripples in the heart of Yuluo Lake, Liao is silent."

Guess you like

Origin www.cnblogs.com/yanggb/p/12595860.html