The VueJSX

A, JSX

JSX is also written in the Render function, but is easier to understand than the Render function.

import AnchoredHeading from './AnchoredHeading.vue'

new Vue({
  el: '#demo'.render: function (h) {
    return (
      <AnchoredHeading level={1}>
        <span>Hello</span> world!
      </AnchoredHeading>)}})Copy the code

That’s why there’s a Babel plug-in for using JSX syntax in Vue, which brings us back to a more template-like syntax.

1.1 the Attributes

render () {
  <input name="id" />
}
Copy the code

1.2 Props

export default {
  name: 'Test'.components: {
    MyComponent
  },
  data () {
    return {
      name: 'Jesse'
    }
  },
  render () {

    const text = 'JSX'
    const props = {
      attrs: {
        name: 'Jesse'.age: 1.sex: 'man'}}return (
      <div>
        <h3>Hello World</h3>{/ * hello * /}<p>Wellcome to {text}</p>
        <my-component {. props} alias={this.name}></my-component>
      </div>)}}Copy the code

Pass dynamic values with {}, {… Props} can be extended, like v-bind

receive

const MyComponent = {
  name: 'MyComponent'.functional: true,
  render (h, ctx) {
    console.log(ctx.props)
    return (
      <div>
        Hi~ {ctx.props.name}
        <p>Alias: {ctx.props.alias}</p>
      </div>)}}Copy the code

Here we receive as a functional component, see functional component

1.3 the Methods

const onClick = () = > {
  console.log(111111)}const listeners = {
  on: {
    go () {
      console.log('go')
    },
    to () {
      console.log('to')}}}return (
  <div>
    <h3 onClick={onClick} {. listeners} >Hello World</h3>
  </div>
)
Copy the code

Event passing is similar to Props passing, except that the function prefix is on. The binding can also be expanded, similar to V-ON

In order to differentiate, Vue has made a series of convenient operations on JSX

  • v-on——> vOn
  • v-model——>vModel
  • v-on:click.stop.prevent——>vOn:click_stop_prevent
  • v-html——>domPropsInnerHTML

1.4 Interaction between Parent and Child Components

const MyComponent = {
  name: 'MyComponent'.functional: true,
  render (h, ctx) {
    ctx.listeners.back()
    ctx.listeners.go()
    return (
      <div></div>)}}export default {
  name: 'Test'.components: {
    MyComponent
  },
  render () {

    const onClick = () = > {
      console.log(111111)}const listeners = {
      on: {
        go () {
          console.log('go')
        },
        to () {
          console.log('to')}}}return (
      <div>
        <h3 onClick={onClick}>Hello World</h3>
        <my-component onBack={onClick} {. listeners} ></my-component>
      </div>)}}Copy the code

Note: In functional components, the this.$emit trigger cannot be used; instead, events are passed in the Listeners property

1.5 cycle

{/* similar to v-if */}
{this.withTitle && <Title />}

{/* similar to v-if + v-else */}
{this.isSubTitle ? <SubTitle /> : <Title />}

{/* similar to v-for */}
{this.options.map(option= > {
  <div>{option.title}</div>
})}
Copy the code

Functional components

We can mark the component as functional, which means it is stateless (no responsive data) and has no instance (no this context). A functional component would look like this:

export default {
  functional: true.render: function (createElement, context) {
    // Fully pass through any attribute, event listener, child node, etc.
    return createElement("button", context.data, context.children); }};Copy the code

Note: Prior to 2.3.0, if a functional component wanted to receive a prop, the props option was required. In versions 2.3.0 and above, you can omit the props option, and attributes on all components are automatically resolved implicitly to prop.

When using functional components, the reference will be htmlElements because they are stateless and instance-free.

In version 2.5.0 and above, if you use single-file components, template-based functional components can be declared as follows:

<template functional>
</template>
Copy the code

Everything a component needs is passed through the context parameter, which is an object containing the following fields:

  • props: Provides objects for all prop
  • children: An array of VNode children
  • slots: a function that returns an object containing all slots
  • scopedSlots(2.6.0+) an object that exposes the incoming scope slot. Normal slots are also exposed as functions.
  • data: passes to the entire componentThe data objectAs acreateElementThe second parameter is passed to the component
  • parent: a reference to the parent component
  • listeners(2.3.0+) An object containing all event listeners registered by the parent component for the current component. This is adata.onAn alias for “.
  • injections(2.3.0+) If usedinjectOption, the object contains the property that should be injected.

Adding functional: After true, we need to update our anchor title component’s render function to add context and update this.$slot.default to context.children, Then update this.level to context.props. Level.

Because functional components are just functions, rendering overhead is also much lower.

They are also useful as packaging components. For example, when you need to do this:

  • Programmatically select one of several components to render for you;
  • In thechildren,props,dataManipulate children before passing them to them.

2.1 Pass attributes and events to child elements or components

In normal components, attributes that are not defined as prop are automatically added to the root element of the component, replacing or intelligently merging existing attributes with the same name.

Functional components, however, require you to explicitly define the behavior:

Vue.component('my-functional-button', {
  functional: true.render: function (createElement, context) {
    // Fully pass through any attribute, event listener, child node, etc.
    return createElement('button', context.data, context.children)
  }
})
Copy the code

By passing context.data as the second parameter to createElement, we pass all the attributes and event listeners on the my-functional-button. In fact, it’s so transparent that those events don’t even require the.native modifier.

If you use template-based functional components, you also need to manually add attributes and listeners. Because we have access to its context-independent content, we can use data.attrs to pass any HTML attribute, as well as listeners (aliases of data.on) to pass any event listener.

<template functional>
  <button
    class="btn btn-primary"
    v-bind="data.attrs"
    v-on="listeners"
  >
    <slot/>
  </button>
</template>
Copy the code

2.2 slots()childrencontrast

You may be wondering why you need both slots() and children. Slot.default is similar to children. In some scenarios, this is true — but what about the following functional component with child nodes?

<my-functional-component>
  <p v-slot:foo>
    first
  </p>
  <p>second</p>
</my-functional-component>
Copy the code

For this component, children will give you two paragraph tags, slot.default will only pass the second anonymous paragraph tag, and slot.foo will pass the first named paragraph tag. You have both Children and slots(), so you can choose to make the component aware of a slot mechanism or simply pass children to the other component to handle.