2
Abstract: JSX is a syntax extension of Javascript, JSX = Javascript + XML, that means writing XML in Javascript. Because of this feature of JSX, it has the flexibility of Javascript and the semantics of html. And intuitiveness.

This article is shared from Huawei Cloud Community " , it's that simple!" [Recommended collection] ", author: paper airplane.

What is JSX

JSX is a grammatical extension of Javascript. JSX = Javascript + XML, which means that XML is written in Javascript. Because of this feature of JSX, it has the flexibility of Javascript and the semantics and intuitiveness of html. ( personally suggest that some components with strong flexibility can be replaced by JSX, the whole project JSX is unnecessary 1616fe1a32606c)

XML learning address (you can learn or not learn at will, understanding is ok): https://www.w3school.com.cn/xml/index.asp
Disadvantages of using template: https://www.mk2048.com/blog/blog_h1c2c22ihihaa.html

Why use JSX in Vue

Sometimes, we use the render function to abstract components. The render function is not very clear. Refer to the official documentation, and sometimes the rendering function is very painful to write, so you just need to understand it.

Rendering function: https://cn.vuejs.org/v2/guide/render-function.html#%E5%9F%BA%E7%A1%80

createElement(
 'anchored-heading', {
 props: {
  level: 1
 }
 }, [
 createElement('span', 'Hello'),
 ' world!'
 ]
)

The corresponding template is as follows:

<anchored-heading :level="1">
 <span>Hello</span> world!
</anchored-heading>

You see how strenuous it is to write, this time I sent JSX to play. To use JSX in Vue, you need to use the Babel plug-in , which allows us to return to the syntax that is closer to the template. Next, let's start writing JSX in Vue.

Create project and configure Babel

`vue create vue-jsx

Choose vue2`

Installation dependencies:

npm install @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
# or
yarn add @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props

Configure.babelrc(babel.config.js):

module.exports = {
 presets: [
 '@vue/cli-plugin-babel/preset',
 ['@vue/babel-preset-jsx',
  {
  'injectH': false
  }]
 ]
}

After configuration, we start the project:

yarn serve
Demo structure diagram:
image.png

After configuring babel.config.js, we changed the HelloWorld.vue introduced by App.vue to HelloWorld.js, and deleted the template, style, and script tags in HelloWorld.js.

export default {
  name: 'HelloWorld',
  props: {
    msg: String
  }
}

JSX basic usage

Here are some basic content written in Vue.

Plain text, dynamic content, label usage, custom components, styles and classes

import myComponent from './myComponent'
import './HelloWorld.css'

// 创建一个组件button
const ButtonCounter = {
  name: "button-counter",
  props: ["count"],
  methods: {
    onClick() {
      this.$emit("change", this.count + 1);
    }
  },
  render() {
    return (
      <button onClick={this.onClick}>数量 {this.count}+</button>
    );
  }
};
export default {
  name: 'HelloWorld',
  components: {
    myComponent 
  },
  data () {
    return {
      text:'hello 纸没了飞机',
      inputText:'我吃了',
      count: 0
    }
  },
  props: {
    msg: String
  },
  watch: {},
  methods: {
    onChange(val) {
      this.count = val;
      alert(this.count)
    }
  },
  render() {
  // const {text,inputText,count} = this //通过解构,下方return片段中就不需要this
    return (
    <div>
     <h3>内容</h3>
     {/* 纯文本 */}
     <p>hello, I am Gopal</p>
     {/* 动态内容 */}
     <p>{ this.text }</p>
     <p>hello { this.msg }</p>
     {/* 输入框 */}
     <input/>
     {/* 自定义组件 */}
     <myComponent/>
     <ButtonCounter
        style={{ marginTop: "10px" }}
        count={this.count}
        type="button"
        onChange={this.onChange}
      />
    </div>
    );
   }
}

Digression: where you create components, you can learn more about the way the ButtonCounter component is created by const. This is often created in React.
image.png

Looking at it this way, there is not much difference between writing in the template, and what the label should be or what has not changed. So if you think about it this way, what about style and class? Next is how to write style and class styles (including dynamic styles)

Let's first bind a class to h3 as colorRed:

<h3 class="colorRed">Content</h3>
Reviewing the elements found that it is possible to write the class binding directly:
image.png

So how to write the style of class? After all, it seems impossible to write <style></style> in the js file!

1. Global style

App.vue
<style>
.colorRed{
  color: red;
}
</style>

2. Introduce a css file or cooperate with style-loader to introduce a less, sass, stylus file

Note: You need to install and configure the corresponding loader. Since they are all JSX, let's use stylus to explain. I believe everyone will know less and sass. Stylus is a css compiler that omits {} and recognizes it by condensing. (If you don't want to use stylus, you can skip it, and the style can be free)

yarn add global stylus
yarn add --dev stylus stylus-loader

For various style installations, see: https://www.cnblogs.com/jimc/p/10265198.html

After the installation is complete, create a new HelloWorld.styl, and then import it.

Use of stylus: https://www.jianshu.com/p/5fb15984f22d
stylus official website: https://stylus.zcopy.site/
For console stylus error, see: 1616fe1a3262fb https://blog.csdn.net/csdn_zhoushengnan/article/details/109448369
Error during vscode editing period: install the editor stylus syntax plug-in, and restart
image.png

Effect:
image.png

style style:

<p style="color:blue">hello, I am Gopal</p>

image.png

dynamic binding of class and style
image.png

<p style={this.isGreen?'color:green':''}>{ this.text }</p>
<p class={this.isYellow?'colorYellow':''}>hello { this.msg }</p>
<p style={this.isRed?colorRed:''}>红色的文字</p>

image.png

same as ordinary HTML

After all, class and style are attributes of html. I believe everyone knows this.

<input placeholder="我是placeholder"  />
<input placeholder={placeholderText}  />
{/* 解构N个属性,要啥放啥 */}
<div {...attrObj}  />

image.png

Effect:
image.png

Common instructions

Template commands commonly used: v-html | v-text, v-if, v-for, v-modal, etc. The template command cannot be used in JSX, so some writing is required, please see below.

I created a new instruction.js to demonstrate the instruction. Introduced in App.vue.

v-html | v-text

In JSX, if you want to set the innerHTML of the dom element, you use domProps.

render() {
    const { htmlCode } = this
    return (
        <div>
            <div domPropsInnerHTML={htmlCode}></div>
        </div>
    );
   }

Although v-text has domPropsInnerText, it is not necessary.

v-if

Divided into simple and complex.

simple:

render() {
    let bool = false
    return (
        <div>
            { bool ? <button>按钮1</button> : <button>按钮2</button>}
        </div>
    );
   }

complex:

render() {
  let num = 3
  if(num === 1){ return( <button>按钮1</button> ) }
  if(num === 2){ return( <button>按钮2</button> ) }
  if(num === 3){ return( <button>按钮3</button> ) }
}

v-for

Just use the map method to achieve, also in React.

render(h) {
  var list = [1,2,3]
  return( 
    <div>
      { list.map(item => <button>按钮{item}</button>) }
    </div>
  )
}

v-modal

Note: In the new version of vue-cli4, JSX syntax support for v-model has been integrated by default and can be used directly
<input v-model={this.value}>

If your project is relatively old, you can also install the plug-in babel-plugin-jsx-v-model to support

I am cli4, let me verify:
image.png

Verification result: (passed)
image.png

Of course, you don't want to engage in the above two methods, you can also manually support it, which involves monitoring events, please look down.

Monitoring events and event modifiers

For listening events, think of using onChange, onClick, etc.

It should be noted that onClick={this.removePhone(params)} cannot be used to pass parameters, so that the method will be executed automatically every time you render

should use bind or arrow function to pass parameters

methods: {
    handleClick(val){
        alert(val)
    }
  },
<button type="button" onClick={this.handleClick.bind(this, 11)}>点击bind</button>
<button type="button" onClick={() => this.handleClick(11)}>点击箭头函数</button>

The above mentioned use of monitoring events to achieve v-modal

<input type="text" value={this.text} onInput={this.input}/>
methods: {
    input(e){
        this.text = e.target.value
    }
  },

In addition, you can also use objects to monitor events:

render() {
  return (
    <input
      value={this.content}
      on={{
        focus: this.$_handleFocus,
        input: this.$_handleInput
      }}
      nativeOn={{
        click: this.$_handleClick
      }}
    ></input>
  )
}

The use of other events is similar to adding on.

event modifier

Like instructions, most of the event modifiers cannot be used in JSX except for some. At this time, you must be used to it, and there must be alternatives.

.stop: To prevent events from bubbling, use event.stopPropagation() in JSX instead
.prevent: Prevent the default behavior, use event.preventDefault() in JSX instead
.self: The callback is triggered only when the event is triggered from the element itself bound to the listener, use the following conditional judgment instead

if (event.target !== event.currentTarget){
  return
}

.enter and keyCode: the callback is only triggered when a specific key is triggered

`if(event.keyCode === 13) {
// execute logic
}`
In addition to the above modifiers, especially in order to take care of our group of CV boys, a little optimization has been made. For .once, .capture, .passive, .capture.once, the prefix syntax is especially provided to help us simplify the code.

render() {
   return (
     <div
       on={{
         // 相当于 :click.capture
         '!click': this.$_handleClick,
         // 相当于 :input.once
         '~input': this.$_handleInput,
         // 相当于 :mousedown.passive
         '&mousedown': this.$_handleMouseDown,
         // 相当于 :mouseup.capture.once
         '~!mouseup': this.$_handleMouseUp
       }}
     ></div>
   )
 }

If there is a parameter passed to the method, it cannot be directly (parameter), it will be triggered immediately on the page, and I need to write it in the following way:

clickOnce(val) {
  alert(val);
},
<button
    type="button"
    on={{
       '~click': ()=>this.clickOnce('只能点一次'),
    }}
   >
    事件修饰符点击一次
</button>

Scope of use (combined with third-party ui components)

Not only use JSX in the render function, but also return JSX in the methods, and then call this method in the render function. And you can also directly use UI components such as elementui.

JSX can also be directly assigned to variables, such as using elementui's el-dialog. (Remember to install elemnt when you test the case)

methods: {
    $_renderFooter() {
      return (
        <div>
          <el-button>确定</el-button>
          <el-button onClick={ () =>this.closeDialog() }>取消</el-button>
        </div>
      );
    },
    openDialog(){
        this.visible = true
    },
    closeDialog(){
        this.visible = false  
    }
  },
render() {
    const buttons = this.$_renderFooter();
    return (
      <div>
        <Button onClick={ () =>this.openDialog() }>打开Dialog</Button>
        <el-dialog visible={this.visible}>
          <div>弹窗内容</div>
          <template slot="footer">{buttons}</template>
        </el-dialog>
      </div>
    );
  }

image.png

Slot

A slot is a placeholder for the parent component in the child component. The slot is divided into the default slot, the named slot and the scope slot. Below I will bring you each usage and how to in JSX in turn. Go to define the slot.

Default slot

uses the default slot

When using element-ui's Dialog, the content of the pop-up box uses the default slot. The usage of the default slot in JSX is basically the same as that of the ordinary slot, as shown in the following code:

render() {
    return (
      <ElDialog title="弹框标题" visible={true}>
        {/*这里就是默认插槽*/}
        <div>这里是弹框内容</div>
      </ElDialog>
    )
  }

custom default slot

On the Vue instance this, there is an attribute slots, and all the slots in this component are mounted on this. Use this.slots, and all the slots in this component are mounted on this.slots. .default can add the default slot to the inside of the component.

export default {
  props: {
    visible: {
      type: Boolean,
      default: false
    }
  },
  render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {/**通过this.$slots.default定义默认插槽*/}
        {this.$slots.default}
      </div>
    )
  }
}

use:

<myComponent visible={true} slot>我是自定义默认插槽</myComponent>

On the other hand, vShow is equivalent to v-show, which does not mean that other things can be the same!

Named slot

Use named slot

Sometimes we need multiple slots for a component. At this time, we need to give each slot a name. For example, the element-ui pop-up box can define the content of the bottom button area, that is, the slot named footer is used.

render() {
    return (
      <ElDialog title="弹框标题" visible={true}>
        <div>这里是弹框内容</div>
        {/** 具名插槽 */}
        <template slot="footer">
          <ElButton>确定</ElButton>
          <ElButton>取消</ElButton>
        </template>
      </ElDialog>
    )
  }

custom named slot

In the previous section to customize the default slot mentioned slots, for the default slot use this.slots, for the default slot use this.slots.default, and for the named slot, you can use this.$slots.footer to customize .

render() {
    return (
      <div class="custom-dialog" vShow={this.visible}>
        {this.$slots.default}
        {/**自定义具名插槽*/}
        <div class="custom-dialog__foolter">{this.$slots.footer}</div>
      </div>
    )
  }

use:

<myComponent visible={true}>
      <template slot="footer">
            <ElButton>确定</ElButton>
            <ElButton>取消</ElButton>
      </template>
</myComponent>

Scope slot

Use scope slot

Sometimes it is useful to allow the contents of the slot to access the data only in the subcomponent. At this time, you need to use the scope slot. In JSX, because there is no v-slot instruction, the use of the scope slot is It is different from the way in the template code. For example, in element-ui, when we use el-table, we can customize the content of table cells, and at this time we need to use the scope slot.

<myComponent1
      visible={this.visible}
      {...{
         scopedSlots: {
           test: ({ user }) => {
           // 这个user就是子组件传递来的数据,同理可这样拿到el-table的row,不过test得是default,不过案例还是我这样
              <div style="color:blue;">快来啊,{user.name},看看这个作用域插槽</div>
          },
         },
     }}
></myComponent1>

Custom scope slot

In the child component, the name of the slot specified by {this.$scopedSlots.test({ user: {name:'paper airplane'}})) is test, and the user is passed to the parent component. When the parent component writes the child component label, the inserted position is specified by the scopedSlots value as test, and the user value passed in by the child component is obtained in the callback function

Note: The scope slot is written in the sub-component tag, similar to attributes. Instead of putting it inside the label like a named slot

Create a new scope slot.js

// 一个为jsx的子组件(玩玩插槽)

export default {
    name: "myComponent",
    data() {
      return {
      };
    },
    props: {
      visible: {
        type: Boolean,
        default: false,
      },
      listData: {
        type: Array,
        default: function() {
          return [];
        },
      },
    },
    render() {
      return (
        <div vShow={this.visible}>
          {/**自定义作用域插槽*/}
          <div class="item">
           {this.$scopedSlots.test({
                user: {name:'纸飞机'}
            })}
          </div>
        </div>
      );
    },
  };

Effect:
image.png

Functional component

The functional component is a stateless, no instance component. For details, please refer to the official website description. Create a new FunctionalComponent.js file with the following content:

// export default ({ props }) => <p>hello {props.message}</p>;

// 或者推荐下方写法

export default {
  functional: true,
  name: "item",
  render(h, context) {
      console.log(context.props)
    return <div style="color:red;font-size:18px;font-weight:bold">{context.props.message}</div>;
  },
};

Used in HelloWorld.js:

<funComponent message="展示下函数式组件"></funComponent>

Effect:
image.png

Code address

https://codechina.csdn.net/qq_32442973/vue2-jsx-demo.git

postscript

Whether you want to use vue2's jsx or vue3's jsx, there is no essential difference. After all, vue3 is backward compatible with vue2; if you really want to learn vue3's JSX, I suggest you learn vue2 before you learn it; otherwise, I don’t It is recommended to use JSX for all components and pages in Vue. Both need to weigh the pros and cons. At the same time, there is no need to worry about the nesting of JSX and template, which can be nested with each other.

refer to:

https://www.cnblogs.com/ainyi/p/13324222.html
https://www.jb51.net/article/205764.htm
https://cn.vuejs.org/v2/guide/render-function.html#event-amp-key modifier
https://www.cnblogs.com/htoooth/p/6973238.html
https://www.jianshu.com/p/84b708c80598
https://cloud.tencent.com/developer/article/1704608

Click to follow to learn about Huawei Cloud's fresh technology for the first time~


华为云开发者联盟
1.4k 声望1.8k 粉丝

生于云,长于云,让开发者成为决定性力量