vue vue-jsx标签_将JSX与Vue一块儿使用以及为何要关心

vue vue-jsx标签javascript

Vue.js has an easy API and several options for defining HTML templates in our components.html

Vue.js具备简单的API和几个选项,可用于在组件中定义HTML模板。 vue

We can use the <template> tag option, define a template property on our root component instance, or use Single-File components.java

咱们可使用<template>标记选项,在咱们的根组件实例上定义template属性,或者使用Single-File组件node

The options above are awesome and work perfectly, but, there comes a time in the lifecycle of your application where they either feel clunky, over-engineered or very inflexible.react

上面的选项很棒,而且能够完美地工做,可是,在您的应用程序的生命周期中,有时会感到笨拙,设计过分或很是不灵活。 git

So, why would we want to JSX instead of any of the other template definitions?github

那么,为何咱们要使用JSX而不是其余任何模板定义? web

  • JSX is easy to read. <div>...</div> is subjectively better than this.$createElement('div', {}, [...])

    JSX易于阅读。 <div>...</div>在主观上要优于this.$createElement('div', {}, [...])
  • Seriously, It's just JavaScript.

    说真的,这只是JavaScript。
  • Vue has support for JSX.

    Vue支持JSX。
  • JSX makes custom Vue components easier to import and manage.

    JSX使自定义Vue组件更易于导入和管理。

快速介绍 ( A quick intro )

Let me give you an example of why JSX is good.vue-cli

让我举一个为何JSX很好的例子。

We want to build a <TextField/> component that can either be a normal single-line text input or a multiline input (textarea). Our template declaration might look like this.

咱们想要构建一个<TextField/>组件,该组件能够是普通的单行文本输入或多行输入(文本区域)。 咱们的模板声明可能看起来像这样。

<div> <textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> <input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> </div><div> <textarea v-if="multiline" v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> <input v-else v-model="content" :name="name" :placeholder="placeholder" :aria-invalid="false"> </div>

As you can see from the snippet above, we'll quickly run into a few problems like duplicate code and many more. Imagine having to support a variety of properties on the input. This little snippet above will grow and be a nightmare to maintain.

从上面的代码片断中您能够看到,咱们将很快遇到一些问题,例如重复代码等等。 想象一下必须在输入上支持各类属性。 上面的这个小片断将会增加,而且将成为噩梦。

To fix this, we need to go low-level with Vue. We need to get closer to Vue's internal API to fix this mess.

要解决此问题,咱们须要对Vue进行低级处理。 咱们须要更接近Vue的内部API来解决此问题。

render()方法 ( The render() method )

NOTE: I'm not saying that the there's not a simple way or ways to handle the above problem without JSX, all I'm saying is that moving this logic to the render() method with JSX in tow can make for a more intuitive component. Keep reading to find out why?

注意:我并非说没有JSX来解决上述问题不是简单的方法,我只是说,将这个逻辑转移到JSX拖曳到render()方法上可使操做更直观零件。 继续阅读以找出缘由?

Every component we create in Vue has a render method. This is where Vue chooses to render the component. Even if we don't define this method, Vue will do it for us.

咱们在Vue中建立的每一个组件都有一个render方法。 这是Vue选择渲染组件的地方。 即便咱们没有定义此方法,Vue也会为咱们作到这一点。

This means that when we define HTML templates in Vue — Vue's template compiler compiles it to a createElement function that takes a couple parameters and returns the result from the render function.

这意味着当咱们在Vue中定义HTML模板时,Vue的模板编译器将其编译为一个createElement函数,该函数带有几个参数并从render函数返回结果。

To fix the code in the previous section, we remove the template property or the template tag and define a render() method on the component. If the render method is defined on a component, Vue will ignore the template definition.

为了修复上一节中的代码,咱们删除了template属性或template标签,并在组件上定义了render()方法。 若是在组件上定义了render方法,则Vue将忽略模板定义

... export default { name: 'TextField', render (createElement) { const tag = this.multiline ? 'textarea' : 'input' return createElement(tag, { class: { 'text-input': true, 'is-disabled': false }, attrs: { name: this.name, placeholder: this.placeholder, 'aria-invalid': false } }) } } ...... export default { name: 'TextField', render (createElement) { const tag = this.multiline ? 'textarea' : 'input' return createElement(tag, { class: { 'text-input': true, 'is-disabled': false }, attrs: { name: this.name, placeholder: this.placeholder, 'aria-invalid': false } }) } } ...

The above code does a few things:

上面的代码作了几件事:

  1. The render method takes a createElement helper from Vue.

    render方法使用Vue的createElement帮助器。
  2. We programmatically define our tag.

    咱们以编程方式定义标签。
  3. Then we create the tag and pass its attributes, classes etc as an object. There are quite a few options we can pass to createElement.

    而后,咱们建立标签并将其属性,类等做为对象传递。 咱们能够传递给createElement 选项不少。
  4. We return the newly created element for rendering.

    咱们返回新建立的元素进行渲染。

Note: Every template we define for a Vue component will be converted into a render method that returns a createElement function. It's because of this reason the render method will take precedence over a template definition.

注意: 咱们为Vue组件定义的每一个模板都将转换为可返回createElement函数的render方法。 由于这个缘由, render方法将优先于模板定义。

Take this example:

举个例子:

<div> <p>Only you can stop forest fires</p> </div><div> <p>Only you can stop forest fires</p> </div>

The template compiler will convert the HTML above into:

模板编译器会将上面HTML转换为:

... render (createElement) { return createElement( 'div', {}, createElement( 'p', {}, 'Only you can stop forest fires' ) ) } ...... render (createElement) { return createElement( 'div', {}, createElement( 'p', {}, 'Only you can stop forest fires' ) ) } ...

Okay! now you might ask this question, "Isn't this bad for readability?" The answer is yes. Once you define a component with many levels of elements nesting or has several sibling elements — we run into a new problem. We just sacrificed readability. Like they say, "we've moved from the frying pan to fire."

好的! 如今您可能会问这个问题:“对可读性来讲这很差吗?” 答案是确定的。 一旦定义了具备许多元素嵌套级别或具备多个同级元素的组件,咱们就会遇到一个新问题。 咱们只是牺牲了可读性。 就像他们说的那样:“咱们已经从煎锅搬到了火上。”

Cue JSX. This is where we'll have JSX bring back the readability we lost.

提示JSX。 这是咱们让JSX恢复丢失的可读性的地方。

什么是JSX ( What is JSX )

If you already know about JSX, feel free to skip to the next section where I'll show you how to use JSX in Vue.

若是您已经了解JSX,请随时跳到下一节,我将向您展现如何在Vue中使用JSX。

JSX is a term coined by Facebook's engineering team.

JSX是Facebook工程团队创造的一个术语。

JSX is an XML-like syntax extension to JavaScript without any defined semantics.

JSX是JavaScript的相似XML的语法扩展,没有任何定义的语义。

JSX is NOT intended to be implemented by engines or browsers. Instead, we'll use transpilers like Babel to convert JSX to regular JavaScript.

JSX不能由引擎或浏览器实现。 相反,咱们将使用像transpilers 巴贝尔以JSX转化为常规JavaScript。

// this line below is an example of JSX
 const heading = <h1>Welcome to Scotch</h1>;

Basically, JSX lets us use an HTML-like syntax in JavaScript.

基本上,JSX容许咱们在JavaScript中使用相似HTML的语法。

Unfortunately, this article assumes you already know JSX, so teaching JSX is beyond the scope of this article. I'll still point you in the right direction. JSX is very easy to grok and can be done in a couple minutes.

不幸的是,本文假设您已经了解JSX,所以教授JSX不在本文讨论范围以内。 我仍然会指出正确的方向。 JSX很是容易掌握,能够在几分钟内完成。

Use these links to learn The basics of JSX, Learn JSX in-depth, finally, if you really want to know about the specification that is JSX, visit its official website.

使用这些连接来学习JSX的基础知识 ,最后, 深刻学习JSX ,若是您真的想了解JSX的规范,请访问其官方网站

配置Vue以使用JSX ( Configure Vue to use JSX )

If you use Vue-cli greater or equal to version 3.0 you are in luck as JSX is supported.

若是您使用大于或等于3.0版的Vue-cli ,那么您会很幸运,由于它支持JSX。

If you are using an older version of Vue-cli that doesn't support JSX, you can add it by installing babel-preset-vue-app and add it to your .babelrc file.

若是您使用的Vue-cli较旧版本不支持JSX,则能够经过安装babel-preset-vue-app添加它,并将其添加到您的.babelrc文件中。

To install:

安装:

# Using npm
 npm install --save-dev babel-preset-vue-app

# Using yarn
 yarn add --dev babel-preset-vue-app

In you .babelrc file, all you have to do is:

在您的.babelrc文件中,您要作的就是:

{
     "presets": ["vue-app"]
 }

There, we can now use JSX in our component's render function.

在那里,咱们如今能够在组件的render函数中使用JSX。

Vue的JSX语法陷阱 ( Vue's JSX syntax gotchas )

There are few gotchas to using JSX in Vue.

在Vue中使用JSX的陷阱不多。

First, you can no longer use the : and @ shortcuts for binding and listening to events. They are invalid JSX syntax and your code won't compile.

首先,您再也不可使用:@快捷方式来绑定和监听事件。 它们是无效的JSX语法,所以您的代码没法编译。

To listen for events in JSX, we need the "on" prefix. For example, use onClick for click events.

要监听JSX中的事件,咱们须要“ on ”前缀。 例如,将onClick用于单击事件。

render (createElement) { return ( <button onClick={this.handleClick}></button> ) }render (createElement) { return ( <button onClick={this.handleClick}></button> ) }

To modify events, use:

要修改事件,请使用:

render (createElement) { return ( <button onClick:prevent={this.handleClick}></button> ) }render (createElement) { return ( <button onClick:prevent={this.handleClick}></button> ) }

To bind a variable, instead of : use:

要绑定一个变量,而不是:使用:

render (createElement) { return ( <button content={this.generatedText}></button> ) }render (createElement) { return ( <button content={this.generatedText}></button> ) }

To set HTML string as the content of an element, instead of v-html use:

要将HTML字符串设置为元素的内容而不是v-html使用:

render (createElement) { return ( <button domPropsInnerHTML={htmlContent}></button> ) }render (createElement) { return ( <button domPropsInnerHTML={htmlContent}></button> ) }

We can also spread a large object.

咱们还能够散布一个大物体。

render (createElement) { return ( <button {...this.largeProps}></button> ) }render (createElement) { return ( <button {...this.largeProps}></button> ) }

在渲染中使用JSX ( Using JSX in render )

Going back to our initial "TextField" component. Now that we have JSX enabled in our Vue app, we can now do this.

回到咱们最初的“ TextField”组件。 如今,咱们在Vue应用程序中启用了JSX,咱们如今能够执行此操做。

render (createElement) { const inputAttributes = { class: 'input-field has-outline', // class definition onClick: this.handleClick // event handler backdrop: false // custom prop } const inputMarkup = this.multiline ? <textarea {...inputAttributes}></textarea> : <input {...inputAttributes}/> return inputMarkup }render (createElement) { const inputAttributes = { class: 'input-field has-outline', // class definition onClick: this.handleClick // event handler backdrop: false // custom prop } const inputMarkup = this.multiline ? <textarea {...inputAttributes}></textarea> : <input {...inputAttributes}/> return inputMarkup }

导入Vue JSX组件 ( Importing Vue JSX Components )

Another benefit to using JSX in Vue is that we no longer have to register every component we need. We just import and use.

在Vue中使用JSX的另外一个好处是,咱们再也不须要注册所需的每一个组件。 咱们只是导入和使用。

import {Button} from '../components' export default { render (createElement) { return <Button primary={true}>Edit</Button> } }import {Button} from '../components' export default { render (createElement) { return <Button primary={true}>Edit</Button> } }

如何使JSX与TypeScript一块儿使用 ( How to make JSX work with TypeScript )

TypeScript is used as a mechanism that adds type-checking to JavaScript. You can read more.

TypeScript用做一种向JavaScript添加类型检查的机制。 您能够阅读更多内容

To add JSX support to TypeScript all we need to do is modify our tsconfig.json.

要将JSX支持添加到TypeScript,咱们要作的就是修改tsconfig.json

To enable JSX in TypeScript, first save the file as a .tsx file and modify your tsconfig.json to include:

要在TypeScript中启用JSX,请先将该文件另存为.tsx文件,而后将tsconfig.json修改成包括:

{
   "compilerOptions": {
     ....
     "jsx": "preserve",
   }
 }

Setting the jsx option to "preserve" means that TypeScript should not process the JSX. Doing this lets Babel take control of everything JSX and TypeScript stick to types as it does not yet support Vue JSX. You can learn more.

jsx选项设置为“ preserve”意味着TypeScript不该处理JSX。 这样作使Babel能够控制全部JSX和TypeScript坚持使用类型,由于它尚不支持Vue JSX。 您能够了解更多

Then create a jsx.d.ts file in your project and add the TypeScript JSX declarations for Vue.

而后在您的项目中建立一个jsx.d.ts文件,并为Vue添加TypeScript JSX声明。

import Vue, {VNode} from 'vue'

declare global {
   namespace JSX {
     interface Element extends VNode {}
     interface ElementClass extends Vue {}
     interface ElementAttributesProperty {
       $props: {}
     }
     interface IntrinsicElements {
 [elemName: string]: any
     }
   }
 }

Make sure that TypeScript can load the declaration file. Or, you can add autoloading for it in tsconfig.json via:

确保TypeScript能够加载声明文件。 或者,您能够经过如下方式在tsconfig.jsontsconfig.json添加自动加载功能:

{
   "compilerOptions": {
     ...
     "typesRoot": ["./node_modules/@types", "./types"]
   }
 }

结论 ( Conclusion )

That's it for today. Enjoy having some or all of your Vue.js templates in JSX.

今天就这样。 享受在JSX中拥有部分或所有Vue.js模板。

And, please no complaints about JSX breaking SOC (separation of concerns), I can't take another one of those arguments. If you prefer using the createElement function with objects by all means enjoy!!

并且,请不要抱怨JSX破坏了SOC(关注点分离),我不能接受其中一个论点。 若是您更喜欢将createElement函数与对象一块儿使用,那就createElement了!!

Let me know your thoughts and suggestions in the comments.

在评论中让我知道您的想法和建议。

Cheers!

干杯!

翻译自: https://scotch.io/tutorials/using-jsx-with-vue-and-why-you-should-care

vue vue-jsx标签