Skip to content

Commit

Permalink
Automatically add const h = this.$createElement in methods. (#58)
Browse files Browse the repository at this point in the history
* Automatically add const h = this.$createElement in methods

* Fix the transform-2015-classes compatibility.

* Add information to README.md

* More details in README.md
  • Loading branch information
nickmessing authored and yyx990803 committed Mar 8, 2017
1 parent dcd3897 commit ec63259
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,23 @@ Vue.component('jsx-example', {
})
```

### `h` auto-injection

Starting with version 3.4.0 we automatically inject `const h = this.$createElement` in any method and getter declared in ES2015 syntax that has JSX so you can drop the `(h)` parameter.

``` js
Vue.component('jsx-example', {
render () { // h will be injected
return <div id="foo">bar</div>
},
myMethod: function () { // h will not be injected
return <div id="foo">bar</div>
}
})
```

**Important** `h` does not inject into functions or arrow functions, it works only in ES2015 Method Properties declaration.

### Difference from React JSX

First, 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:
Expand Down
32 changes: 32 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,38 @@ module.exports = function (babel) {
}
path.replaceWith(t.inherits(callExpr, path.node))
}
},
'ObjectExpression|ClassDeclaration' (path) {
path.traverse({
'ObjectMethod|ClassMethod' (path) {
// do nothing if there is (h) param
if (path.get('params').length) {
return
}
// do nothing if there is no JSX inside
const jsxChecker = {
hasJsx: false
}
path.traverse({
JSXElement () {
this.hasJsx = true
}
}, jsxChecker)
if (!jsxChecker.hasJsx) {
return
}
// prepend const h = this.$createElement otherwise
path.get('body').unshiftContainer('body', t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('h'),
t.memberExpression(
t.thisExpression(),
t.identifier('$createElement')
)
)
]))
}
})
}
}
}
Expand Down
53 changes: 53 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,59 @@ describe('babel-plugin-transform-vue-jsx', () => {

expect(vnode.data.class).to.deep.equal({ a: true, b: true })
})

it('h self-defining in object methods', () => {
const obj = {
render () {
return <div>test</div>
}
}
const vnode = render(h => obj.render.call({ $createElement: h }))
expect(vnode.tag).to.equal('div')
expect(vnode.children[0].text).to.equal('test')
})

it('h self-defining in object getters', () => {
const obj = {
get render () {
return <div>test</div>
}
}
const vnode = render(h => {
obj.$createElement = h
return obj.render
})
expect(vnode.tag).to.equal('div')
expect(vnode.children[0].text).to.equal('test')
})

it('h self-defining in class methods', () => {
class Test {
constructor (h) {
this.$createElement = h
}
render () {
return <div>test</div>
}
}
const vnode = render(h => (new Test(h)).render())
expect(vnode.tag).to.equal('div')
expect(vnode.children[0].text).to.equal('test')
})

it('h self-defining in class getters', () => {
class Test {
constructor (h) {
this.$createElement = h
}
get render () {
return <div>test</div>
}
}
const vnode = render(h => (new Test(h)).render)
expect(vnode.tag).to.equal('div')
expect(vnode.children[0].text).to.equal('test')
})
})

// helpers
Expand Down

0 comments on commit ec63259

Please sign in to comment.