Hello audience gentlemen, if you have read the last article, you will know that this series is to introduce some skills in the practice of vue.js, and reasonable use can improve some development efficiency. Today we introduce the special uses of JSX and the new functionality of vue.js — $props.

Tip 1: JSX can be written anywhere

As anyone who has written Vue JSX knows, we usually need to write JSX in render(h) {}. But there are cases where we want to write JSX in other methods, such as the Element component example from the previous article.

const h = this.$createElement this.$notify({ title: 'GitHub', message: H ('div', [h('p', '[GitHub] Subscribed to ElemeFE/ Element notifications'), h('el-button', {}, 'read ')])})Copy the code

Call the Notification service to display a custom piece of content. This code is not written in render, but we could have written JSX, for example:

{ methods: { showNotify() { const h = this.$createElement this.$notify({ title: 'GitHub', message: (<div> <p>[GitHub] Subscribed to ElemeFE/ Element notification</p> <el-button> <div>)})}}Copy the code

Using the babel-plugin-transform-vue-jsx plug-in, this code works fine. $createElement = this.$createElement = this.$createElement = this.$createElement = this. // eslint-disable-line ignores the message if it is useful for eslint:

const h = this.$createElement // eslint-disable-line
Copy the code

In fact, in the latest release babel-plugin-transform-vue-jsx 3.4.0, you no longer need to manually declare the H variable and can now happily write JSX anywhere in the component.

Tip 2: The use posture of $props

A new feature was added in vue.js 2.2 – $props. The documentation is very succinct about what it is but it doesn’t explain what it does, so I’m going to share with you some of the situations where you might need it.

1. Inherit native attributes

When developing a form component, you have to solve the problem of inheriting various properties from the native component. For example, to encapsulate an input component with a native placeholder property, our code might look like this:

<template>
  <div>
    <label>{{ label }}</label>
​
    <input
      @input="$emit('input', $event.target.value)"
      :value="value"
      :placeholder="placeholder">
  </div>
</template>
​
<script>
  export default {
    props: ['value', 'placeholder', 'label']
  }
</script>
Copy the code

But if you want to support other native attributes, you need to continue writing template content:

<template>
  <div>
    <label>{{ label }}</label>
​
    <input
      @input="$emit('input', $event.target.value)"
      :value="value"
      :placeholder="placeholder"
      :maxlength="maxlength"
      :minlength="minlength"
      :name="name"
      :form="form"
      :value="value"
      :disabled="disabled"
      :readonly="readonly"
      :autofocus="autofocus">
  </div>
</template>
​
<script>
  export default {
    props: ['label', 'placeholder', 'maxlength', 'minlength', 'name', 'form', 'value', 'disabled', 'readonly', 'autofocus']
  }
</script>
Copy the code

If you want to set type, or if you want to support textarea as well, the amount of repetitive code can be scary. But it might be easier to write in JSX instead:

export default { props: ['label', 'type', 'placeholder', 'maxlength', 'minlength', 'name', 'form', 'value', 'disabled', 'readonly', 'autofocus'], render(h) { const attrs = { placeholder: this.placeholder, type: this.type // ... } return ( <div> <label>{ this.label }</label> <input { ... { attrs } } /> </div> ) } }Copy the code

In Vue’s vNode, the native attributes are defined in data.attrs, so the input section above is compiled to:

h('input', {
  attrs: attrs
})
Copy the code

This completes the passing of the native attribute. Similarly, if you want to set the textarea by type, you just need to add a judgment setting tag.

h(this.type === 'textarea' ? 'textarea' : 'input', { attrs })
Copy the code

So far we still need to define an attrs object, but all the attributes we need are defined in props. Wouldn’t it be nice to get the values directly from props? We can simply write a polyfill to do this. (Actually Vue 2.2 does not require you to introduce polyfill, it is supported by default)

import Vue from 'vue'
​
Object.defineProperty(Vue.prototype, '$props', {
  get () {
    var result = {}
    for (var key in this.$options.props) {
      result[key] = this[key]
    }
    return result
  }
})
Copy the code

$options. Props = vm.$options. Props = vm. Then our code could look like this:

render(h) { return ( <div> <label>{ this.label }</label> <input { ... { attrs: this.$props } } /> </div> ) }Copy the code

If you’ve noticed the Vue documentation that v-bind can pass objects, our code is easier to write using a Vue template:

<template>
  <div>
    <label>{{ label }}</label>
    <input v-bind="$props">
  </div>
</template>
Copy the code

2. Inherit attributes of user-defined components

$props does much more than that. If you need to wrap another component based on the input component above, how do we inherit its properties?

For example, wrapping an input component with validation might look like this:

<template> <div> <XInput /> <div v-show="message && show-hit" class="hit">{{ message }}</div> </div> </template> <script> import XInput from './input.vue' export default { components: { XInput }, props: { showHit: Boolean}, data () {return {message: 'error'}}} </script>Copy the code

The key is how to pass the props of XInput. To do this, duplicate the props of Xinput in the props of the current component with v-bind.

<template> <div> <XInput v-bind="$props" /> <div v-show="message && show-hit" class="hit">{{ message }}</div> </div> </template> <script> import XInput from './input.vue' export default { components: { XInput }, props: { showHit: Boolean, ... XInput. Props}, data () {return {message: 'error'}}} </script>Copy the code

You can also implement this with object. assign:

{
  props: Object.assign({ showHit: Boolean }, XInput.props)
}
Copy the code

That’s the basic use of $props. If you have any other ideas or uses, feel free to share in the comments. Now that we’re done sharing this series, I’ve put the code for all the examples in the Vue-Tricks repository. See you next time!

Refer to the link

  • vuejs/babel-plugin-transform-vue-jsx

  • Vue.js

  • $props · Issue #4571 · vuejs/vue

  • vuejs/babel-plugin-transform-vue-jsx

  • QingWei-Li/vue-tricks