UNPKG

5.41 kBMarkdownView Raw
1# babel-plugin-transform-vue-jsx [![CircleCI](https://img.shields.io/circleci/project/vuejs/babel-plugin-transform-vue-jsx.svg?maxAge=2592000)](https://circleci.com/gh/vuejs/babel-plugin-transform-vue-jsx)
2
3> Babel plugin for Vue 2.0 JSX
4
5### Requirements
6
7- Assumes you are using Babel with a module bundler e.g. Webpack, because the spread merge helper is imported as a module to avoid duplication.
8
9- This is mutually exclusive with `babel-plugin-transform-react-jsx`.
10
11### Usage
12
13``` bash
14npm install\
15 babel-plugin-syntax-jsx\
16 babel-plugin-transform-vue-jsx\
17 babel-helper-vue-jsx-merge-props\
18 babel-preset-env\
19 --save-dev
20```
21
22In your `.babelrc`:
23
24``` json
25{
26 "presets": ["env"],
27 "plugins": ["transform-vue-jsx"]
28}
29```
30
31The plugin transpiles the following JSX:
32
33``` jsx
34<div id="foo">{this.text}</div>
35```
36
37To the following JavaScript:
38
39``` js
40h('div', {
41 attrs: {
42 id: 'foo'
43 }
44}, [this.text])
45```
46
47Note the `h` function, which is a shorthand for a Vue instance's `$createElement` method, must be in the scope where the JSX is. Since this method is passed to component render functions as the first argument, in most cases you'd do this:
48
49``` js
50Vue.component('jsx-example', {
51 render (h) { // <-- h must be in scope
52 return <div id="foo">bar</div>
53 }
54})
55```
56
57### `h` auto-injection
58
59Starting with version 3.4.0 we automatically inject `const h = this.$createElement` in any method and getter (not functions or arrow functions) declared in ES2015 syntax that has JSX so you can drop the `(h)` parameter.
60
61``` js
62
63Vue.component('jsx-example', {
64 render () { // h will be injected
65 return <div id="foo">bar</div>
66 },
67 myMethod: function () { // h will not be injected
68 return <div id="foo">bar</div>
69 },
70 someOtherMethod: () => { // h will not be injected
71 return <div id="foo">bar</div>
72 }
73})
74
75@Component
76class App extends Vue {
77 get computed () { // h will be injected
78 return <div id="foo">bar</div>
79 }
80}
81```
82
83### Difference from React JSX
84
85First, Vue 2.0's vnode format is different from React's. The second argument to the `createElement` call is a "data object" that accepts nested objects. Each nested object will be then processed by corresponding modules:
86
87``` js
88render (h) {
89 return h('div', {
90 // Component props
91 props: {
92 msg: 'hi'
93 },
94 // normal HTML attributes
95 attrs: {
96 id: 'foo'
97 },
98 // DOM props
99 domProps: {
100 innerHTML: 'bar'
101 },
102 // Event handlers are nested under "on", though
103 // modifiers such as in v-on:keyup.enter are not
104 // supported. You'll have to manually check the
105 // keyCode in the handler instead.
106 on: {
107 click: this.clickHandler
108 },
109 // For components only. Allows you to listen to
110 // native events, rather than events emitted from
111 // the component using vm.$emit.
112 nativeOn: {
113 click: this.nativeClickHandler
114 },
115 // class is a special module, same API as `v-bind:class`
116 class: {
117 foo: true,
118 bar: false
119 },
120 // style is also same as `v-bind:style`
121 style: {
122 color: 'red',
123 fontSize: '14px'
124 },
125 // other special top-level properties
126 key: 'key',
127 ref: 'ref',
128 // assign the `ref` is used on elements/components with v-for
129 refInFor: true,
130 slot: 'slot'
131 })
132}
133```
134
135The equivalent of the above in Vue 2.0 JSX is:
136
137``` jsx
138render (h) {
139 return (
140 <div
141 // normal attributes or component props.
142 id="foo"
143 // DOM properties are prefixed with `domProps`
144 domPropsInnerHTML="bar"
145 // event listeners are prefixed with `on` or `nativeOn`
146 onClick={this.clickHandler}
147 nativeOnClick={this.nativeClickHandler}
148 // other special top-level properties
149 class={{ foo: true, bar: false }}
150 style={{ color: 'red', fontSize: '14px' }}
151 key="key"
152 ref="ref"
153 // assign the `ref` is used on elements/components with v-for
154 refInFor
155 slot="slot">
156 </div>
157 )
158}
159```
160
161### Component Tip
162
163If a custom element starts with lowercase, it will be treated as a string id and used to lookup a registered component. If it starts with uppercase, it will be treated as an identifier, which allows you to do:
164
165``` js
166import Todo from './Todo.js'
167
168export default {
169 render (h) {
170 return <Todo/> // no need to register Todo via components option
171 }
172}
173```
174
175### JSX Spread
176
177JSX spread is supported, and this plugin will intelligently merge nested data properties. For example:
178
179``` jsx
180const data = {
181 class: ['b', 'c']
182}
183const vnode = <div class="a" {...data}/>
184```
185
186The merged data will be:
187
188``` js
189{ class: ['a', 'b', 'c'] }
190```
191
192### Vue directives
193
194Note that almost all built-in Vue directives are not supported when using JSX, the sole exception being `v-show`, which can be used with the `v-show={value}` syntax. In most cases there are obvious programmatic equivalents, for example `v-if` is just a ternary expression, and `v-for` is just an `array.map()` expression, etc.
195
196For custom directives, you can use the `v-name={value}` syntax. However, note that directive arguments and modifiers are not supported using this syntax. There are two workarounds:
197
1981. Pass everything as an object via `value`, e.g. `v-name={{ value, modifier: true }}`
199
2002. Use the raw vnode directive data format:
201
202``` js
203const directives = [
204 { name: 'my-dir', value: 123, modifiers: { abc: true } }
205]
206
207return <div {...{ directives }}/>
208```