Vue2使用JSX编写组件探索
tiodot opened this issue · 0 comments
在开发vue项目时,需要动态渲染组件,从vue2开始,提供使用jsx编写组件的能力。想着都是jsx,按照之前使用React的jsx开发组件思路来开发vue组件,果然还是有坑。
环境设置
使用jsx开发组件时,需要使用babel-plugin-transform-vue-jsx
这个babel插件进行编译,根据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中却有些不一样。
有两个组件,父组件传递数据到子组件
// 父组件
import C from './c'
export default {
name: 'test',
render() {
return <C a="foo" b ="bar"/>
},
components: {C}
}
然后需要在子组件中打印出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模板组件时可以直接使用:
<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
}
}
这还没有完,在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('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-对象