Component_non-prop features

A non-prop feature is a feature that is not registered by a component. When a component receives a non-prop feature, that feature is added to the root element of the component.

Replace/merge existing features

Imagine the template for < my-cMP > looks like this:

<input type="date" class="b">
Copy the code

To customize a theme for our date picker plug-in, we might need to add a special class name like this:

<my-cmp
  class="my-cmp"
></my-cmp>
Copy the code

In this case, we define two different class values:

  • My-cmp, which is set up in the component’s template
  • B, this is passed in from the component’s parent

For most features, the value provided externally to the component replaces the value set internally by the component. So if you pass type=”text” it will replace type=”date” and break it! Fortunately, the class and style features are a little smarter, as the values on both sides are merged to get the final value: my-cmp B.

Disable feature inheritance

If you don’t want the root element of a component to inherit features, you can set inheritAttrs: false in the component options. Such as:

Vue.component('my-cmp', {
  inheritAttrs: false.// ... 
})
Copy the code

In this case, it is appropriate to use the instance’s $attrs attribute, which is an object with the key name of the passed attribute and the key value of the passed attribute.

{
  required: true.placeholder: 'Enter your username'
}
Copy the code

Using inheritAttrs: false and $attrs, we can manually determine which element these attributes will be assigned to. Such as:

Vue.component('base-input', {
  inheritAttrs: false.props: ['label'.'value'].template: `  `,})Copy the code

Note that the inheritAttrs: false option does not affect the style and class bindings.

Component_ Listens for component events

First, let’s write a blog component such as:

Vue.component('blog-post', {
  props: {
    post: {
      type: Object,}},template: ` < div class = "blog post -" > < h3 > {{post. The title}} < / h3 > < button > amplification size < / button > < div > {{post. The content}} < / div > < / div > `,})Copy the code
<div id="app">
  <div :style="{fontSize: postFontSize + 'em'}">
    <blog-post
      v-for="post in posts"
      :key="post.id"
      :post="post"
    >
    </blog-post>
  </div>
</div>
Copy the code
const vm = new Vue({
  el: '#app'.data: {
    posts: [{title: 'heading 1'.content: 'Body content'.id: 0}, {title: 'title 2'.content: 'Body content'.id: 1}, {title: 'title'.content: 'Body content'.id: 2],},postFontSize: 1}})Copy the code

As you can see in each blog component, there is a button to enlarge the size of the font on the page. That is, when clicking this button, we tell the parent component to change the postFontSize data to enlarge the text of all the blog posts. What should you do in such a situation?

The Vue instance provides a custom event to solve this problem. The parent component can listen for any event of the child component instance through the V-ON directive, as if it were a native DOM element, such as:

<div id="app">
  <div :style="{fontSize: postFontSize + 'em'}">
    <blog-post
      .
      @enlarge-text="PostFontSize + = 0.1"
    >
    </blog-post>
  </div>
</div>
Copy the code

So how can we monitor such a strange event? This requires actively firing a custom event within the component.

How to trigger? An event is emitted by calling the $emit method and passing in the event name, such as:

Vue.component('blog-post', {
  props: {... },template: `
    <div class="blog-post">
      ...
      <button @click="$emit('enlarge-text')">放大字号</button>
      ...
    </div>
  `,})Copy the code

The parent component can then receive the event and update the value of the data pageFontSize.

Throw a value using an event

In some cases, we might want to let the

component decide how much larger its text should be. This is the second argument you can use to provide this value, such as:

Vue.component('blog-post', {
  props: {... },template: ` 
      
... < button @ click = "$emit (' enlarge - text, 0.2)" > amplification size < / button >...
`
,})Copy the code

When the parent component listens for this event, the value thrown can be accessed via $event:

<div id="app">
  <div :style="{fontSize: postFontSize + 'em'}">
    <blog-post
      .
      @enlarge-text="postFontSize += $event"
    >
    </blog-post>
  </div>
</div>
Copy the code

Alternatively, write the event handler as a method:

<div id="app">
  <div :style="{fontSize: postFontSize + 'em'}">
    <blog-post
      .
      @enlarge-text="onEnlargeText"
    >
    </blog-post>
  </div>
</div>
Copy the code

This value will be passed to the method as the first argument:

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

The event name

Unlike components and Prop, event names do not have any automated capitalization conversion. Instead, the name of the event that fires needs to match exactly all the names that are listening for that event. If an event with the camelCase name is triggered:

this.$emit('myEvent')
Copy the code

Listening on the kabab-case version of this name has no effect.

 <! -- No effect --> 
<my-component v-on:my-event="doSomething"></my-component>
Copy the code

Unlike components and prop, event names are not treated as JS variable names or property names, so there is no reason to use camelCase or PascalCase.

The V-ON event listener is automatically converted to all lowercase in the DOM template, so @myevent will become @myevent, making it impossible to listen on myEvent.

Therefore, it is recommended to always use the event name of kebab-case.

Bind native events to components

When a component listens for events, we listen for custom events that are automatically triggered by the component, but in some cases we may want to listen for a native event directly on the root element of a component. This is a. Native modifier that can be used with the V-ON instruction, such as:

<base-input @focus.native="onFocus" @blur.native="onBlur"></base-input>
Copy the code
Vue.component('base-input', {
  template: `  `
})
Copy the code

This is useful in some cases, but not a good idea when trying to listen for an element like , such as a

component that might have been refactored, such as:

<label>Name:<input type="text">
</label>
Copy the code

As you can see, the root element of the component is actually an element, and the parent. Native listener will silently fail. It does not generate any errors, but the onFocus handler will not be called as expected.

To solve this problem, Vue provides a $Listeners property, which is an object that contains all listeners working on the component. Such as:

{
  focus: function (event) {  / *... * /  }
  blur: function (event) {  / *... * /}},Copy the code

Listeners can also use the v−on=”listeners” attribute to direct all event listeners to a particular child of the component, such as:

Vue.component('base-input', {
  template: Name:  
})
Copy the code

Use v-Models on components

V-model directives can also be used on components due to custom events.

Using the V-mode directive on an input element binds the value feature and listens for input events:

<input v-model="searchText" />
Copy the code

Is equivalent to:

<input
  :value="searchText"
  @input="searchText = $event.target.value"
>
Copy the code

When applying the V-model directive to a component:

<base-input v-model="searchText" /> 
Copy the code

Is equivalent to:

<base-input
  :value="searchText"
  @input="searchText = $event"
/>
Copy the code

As with the input element, using the V-model directive on the component binds the value property and listens for the input event.

So, in order for the V-Model directive to work properly, the in this component must:

  • Bind its value feature to a prop called Value
  • Throw a new value via a custom input event when its input event is raised as follows:
Vue.component('base-input', {
  props: ['value'].template: `  `
}) 
Copy the code

Once this is done, the V-Model is ready to work on this component.

As we learned above, a V-Model on a component makes use of a prop named Value and an event named input by default, but input controls like checkboxes, checkboxes, and so on May use the value feature for different purposes. In such cases, we can use the Model option to avoid collisions:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked'.event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `  `
})
Copy the code

Using components:

<base-checkbox v-model="lovingVue"></base-checkbox>
Copy the code

The value of lovingVue here will be passed to the prop named Checked. The lovingVue property is updated when a change event is fired with a new value.

The sync modifier

In addition to using the V-model directive for bidirectional binding of components to external data, we can also use the modifier.sync of the V-bind directive.

So how do you do that? Recall that the v-model directive is not used to implement bidirectional data binding for components:

<base-input :value="searchText" @input="searchText = $event"></base-input>
Copy the code
Vue.component('base-input', {
  props: ['value'].template: `  `
}) 
Copy the code

Then, we can also try to change the name of the listening event, such as:

<base-input :value="searchText" @update:value="searchText = $event"></base-input>
Copy the code
Vue.component('base-input', {
  props: ['value'].template: `  `
}) 
Copy the code

This also allows for bidirectional data binding, so what does it have to do with the.sync modifier? At this point, we modify the code:

<base-input :value.sync="searchText"></base-input>
Copy the code
Vue.component('base-input', {
  props: ['value'].template: `  `
}) 
Copy the code

So, the.sync modifier is essentially a syntactic sugar, used on components:

<base-input :value.sync="searchText"></base-input>
Copy the code

Is equivalent to:

<base-input
  :value="searchText"
  @update:value="searchText = $event"
/>
Copy the code

We can also use the sync modifier with v-bind when setting multiple prop objects simultaneously:

<base-input v-bind.sync="obj"></base-input>
Copy the code

Note:

  • The V-bind directive, with the.sync modifier, can only provide the name of the property you want to bind,Can’tUsed with expressions such as::title.sync="1+1", this operation is invalid
  • willv-bind.syncUsed on a literal object, as inv-bind.sync="{ title: 'haha' }", will not work because there are many edge cases to consider when parsing a complex expression like this.

v-model VS .sync

To be clear, the.sync syntax was already supported in Vue 1.x, but.sync could change the state of the parent component entirely in the child component, making the entire state change difficult to trace, so this feature was removed in 2.0. Then, with Vue2.3,.sync came back, but now, sync is completely a syntactic sugar. It is implemented in the same way as V-Model, and it is not easy to break the existing data model, so it is safer and more convenient to use.

  • Both are used to implement two-way data transfer, implemented by syntax sugar, and finally passedprop + The eventTo get the job done.
  • Vue 1.x’s.sync and V-model are two completely different things. After Vue 2.3, it can be understood as a single feature with slightly different usage scenarios
  • When a component exposes only one controlled state to the outside world, and all conform to uniform standards, we will use the V-Model to deal with it. .sync is more flexible and can be used whenever two-way data transfer is required.

The last

If it is helpful to you, I hope to give you a 👍 comment/collection/three even!

Bloggers are honest and answer questions for free ❤

  • Welcome to discuss in the comments section, the excavation officials will draw 100 nuggets in the comments section after the end of the Excavation project activity, see the details of the lucky draw in the event article, friends to discuss!!