Open tiodot opened 7 years ago
在开发vue项目时,需要动态渲染组件,从vue2开始,提供使用jsx编写组件的能力。想着都是jsx,按照之前使用React的jsx开发组件思路来开发vue组件,果然还是有坑。
使用jsx开发组件时,需要使用babel-plugin-transform-vue-jsx这个babel插件进行编译,根据babel-plugin-transform-vue-jsx中所说:
babel-plugin-transform-vue-jsx
npm install babel-plugin-syntax-jsx --save-dev // babel对jsx语法支持 npm install babel-plugin-transform-vue-jsx --save-dev // 将jsx装换成vue的函数调用 npm install babel-helper-vue-jsx-merge-props --save-dev // 对jsx属性进行merge npm install babel-preset-es2015 --save-dev // es6语法支持
.babelrc
{ "presets": ["es2015"], "plugins": ["transform-vue-jsx"] }
形式上和React基本一致,用render函数替代template:
new Vue({ el: '#app', render() { return <div>hello</div> } });
如果同时存在template,render函数优先:
new Vue({ el: '#app', template: '<div>word</div>', render() { return <div>hello</div> } });
其结果都是:
在React中,所有jsx中元素属性都被被放到props属性中,然而在vue中却有些不一样。 有两个组件,父组件传递数据到子组件
props
// 父组件 import C from './c' export default { name: 'test', render() { return <C a="foo" b ="bar"/> }, components: {C} }
然后需要在子组件中打印出a和b的值:
a
b
// 子组件 export default { name: 'c', render() { console.log(this); return <p>{this.$attrs.a}: {this.$attrs.b}</p>; } }
打印出this: 可以发现a和b都在$attrs中,这个和我们正常写vue组件好像不太一致啊,写vue模板组件时可以直接使用:
$attrs
<template> <p>{{a}}:{{b}}</p> </template> <script> export default { name: 'c', props: { a: String, b: String } } </script>
可以发现这里定义了一个props属性,里面包含需要从父组件获取的属性。于是改造一下jsx,发现加上props也是好使的。
// 添加了props的jsx export default { name: 'c', render() { console.log(this); return <p>{this.a}: {this.b}</p>; }, props: { a: String, b: String } }
打印的this其实也是有变化的:
这还没有完,在React中,一般props都会使用...展开一个对象赋值,在vue中使用这个却有些问题:
...
// 父组件中使用 ... 展开对象形式 import C from './c' export default { name: 'test', render() { const props = {a: 'foo', b: 'bar'}; return <C {...props}/> // === <C a="foo" b="bar" /> ? }, components: {C} }
正常理解这种应该等价于之前的写法,然而结果却是 如果用React中的jsx来看这个问题,就觉得很难理解,然而这毕竟是vue。为了解决这个问题,可以先看一下编译之后的render的代码:
function render(createElement) { var props = {a: 'foo', b: 'bar'}; return createElement(C, props, [],); }
而
<C a="foo" b="bar" />
编译之后的是:
function render(createElement) { var props = {a: 'foo', b: 'bar'}; return createElement(C, {attrs: { a: 'foo', b: 'bar' }}, [],); }
createElement的参数形式为:
createElement
createElement('div', data, [children]);
区别就是使用...是相当于直接扩展到data中,而jsx元素属性在babel编译阶段会被收集到data.attrs属性中,所以:
<C {...{attrs: {a: 'foo', b: 'bar'}}}/> === <C a="foo" b="bar" />
当然对应属性也可以使用props,也就是说:
import C from './c.js' export default { name: 'test', render() { const props = {props: {a: 'foo', b: 'bar'}}; // === {attrs: {a: 'foo', b: 'bar'}} return <C {...props}/> }, components: {C} }
效果也是同样的。
vue的jsx和React的jsx在对对象使用...有些区别,vue需要里面再包一层props或者attrs才能正常被子组件获取,其他的可以参考深入-data-对象
attrs
babel-plugin-transform-vue-jsx 渲染函数&JSX
在开发vue项目时,需要动态渲染组件,从vue2开始,提供使用jsx编写组件的能力。想着都是jsx,按照之前使用React的jsx开发组件思路来开发vue组件,果然还是有坑。
环境设置
使用jsx开发组件时,需要使用
babel-plugin-transform-vue-jsx
这个babel插件进行编译,根据babel-plugin-transform-vue-jsx中所说:.babelrc
配置基本使用
形式上和React基本一致,用render函数替代template:
如果同时存在template,render函数优先:
其结果都是:
属性传递
在React中,所有jsx中元素属性都被被放到
props
属性中,然而在vue中却有些不一样。 有两个组件,父组件传递数据到子组件然后需要在子组件中打印出
a
和b
的值:打印出this: 可以发现
a
和b
都在$attrs
中,这个和我们正常写vue组件好像不太一致啊,写vue模板组件时可以直接使用:可以发现这里定义了一个
props
属性,里面包含需要从父组件获取的属性。于是改造一下jsx,发现加上props
也是好使的。打印的this其实也是有变化的:
这还没有完,在React中,一般props都会使用
...
展开一个对象赋值,在vue中使用这个却有些问题:正常理解这种应该等价于之前的写法,然而结果却是 如果用React中的jsx来看这个问题,就觉得很难理解,然而这毕竟是vue。为了解决这个问题,可以先看一下编译之后的render的代码:
而
编译之后的是:
createElement
的参数形式为:区别就是使用
...
是相当于直接扩展到data中,而jsx元素属性在babel编译阶段会被收集到data.attrs属性中,所以:当然对应属性也可以使用
props
,也就是说:效果也是同样的。
总结
vue的jsx和React的jsx在对对象使用
...
有些区别,vue需要里面再包一层props
或者attrs
才能正常被子组件获取,其他的可以参考深入-data-对象参考
babel-plugin-transform-vue-jsx 渲染函数&JSX