1.概念
jsx 起源于react,其实就是在js中能够直接编写html标签。最终还是会被渲染生成虚拟dom,
浏览器默认是不支持直接解析,需要借助插件才能实现jsx的解析。
一般需要安装@vue/babel-helper-vue-jsx-merge-props
npm i @vue/babel-helper-vue-jsx-merge-props
2.优势
template只能实现简单逻辑的处理,当遇到复杂的判断与动态输出,则无法胜任。 这时自动写vue的render方法会变得灵活许多,再配合jsx,会让代码标签化更加明显。
例子对比
1.template写法
<tempalte>
<h1 v-if="level == 1">
<slot></slot>
</h1>
<h2 v-eseif="level == 2">
<slot></slot>
</h2>
<h3 v-eseif="level == 3">
<slot></slot>
</h3>
</tempalte>
纯js写法
export default {
props: {
level: {
type: Number,
default: 1
}
},
render: function (createElement) {
return createElement(
'h' + this.level,//标签名称
this.$flots.default // 子元素数组
}
}
jsx写法
export default {
props: {
level: {
type: Number,
default: 1
}
},
render: function (h) {
const tag = `<h${this.level}>`;
return <tag>{this.$slots.default}<tag/>;
}
}
3.render与createElement
vue中所有组件最终都会通过调用render方法生成vnode,如果定义的是tempalte则会先转化为render。每一个vnode都是通过createElement统一创建,也就是我们常说的h函数
export default {
name: 'xxx',
render: function(h) {//在render函数里 createElement会做参数传入
return (
<div>
<div>{this.msg}</div>
<div>{this.$slots.demo}</div>
<div>{this.$scopedSlots.data(this.detail)}</div>
</div>
);
},
}
h函数也可以通过全局的获得
const h = this.$createElement
4.例子
export default {
props: {
info: {
type: Object,
default() {
return {name:jason,age:18};
},
},
},
data() {
return {
title: "标题",
};
},
render() {
return (
<div>
<input type="text" v-model={this.title} />
<input type="text" v-model={this.info.name} />
<input type="text" v-model={this.info.age} />
</div>
);
},
};
当定义了render函数 组件就会优先以render创建组件,忽略template的代码。在render里我们可以使用this访问组件上下文的this内容。
5.template 到 jsx代码差异
5.1常用vue指令
#v-bind
<input :disabled="true" />
<input disabled={true} />
#v-if
<span v-if="item == 1">1</span>
<span v-else>2</span>
{item == 1 ? <span>1</span> : <span>2</span>}
#v-for
<ul>
<li v-for="item in arr" :key={item}>{{item}}</li>
</ul>
<ul>
{arr.map(item => <li key={item}>{item}</li>)}
</ul>
#v-show
<h1 v-show:isShow />标题<h1>
// jsx也支持
<h1 v-show:isShow />标题<h1>
#v-model
<h1 v-model:title />标题<h1>
jsx默认不支持 可以使用插件babel-plugin-jsx-v-model
#绑定自定义事件
<button @click="myClick">测试</button>
// on-click和onCLick都可以
<button on-click={myClick}>测试</button>
<button onClick={myClick}>测试</button>
#绑定原生事件
<my-component @click.native="testClick" />
// 驼峰写法
<my-component nativeOnClick={testClick} />
5.2element-table & 插槽
scopedSlots 是组件默认的插槽属性,可以直接调用访问
render() {
return ( <el-table border data={this.rows}>
<el-table-column align="center" label="id" width="50" prop="id" />
<el-table-column align="left" label="标题" width="500" prop="view_path" />
<el-table-column align="left" label="內容" width="200" prop="content" />
<el-table-column align="left" label="数据1" width="200" prop="data"
scopedSlots={{
default: (scoped) => {
return (<span>{JSON.stringify(scoped.row.data)}</span>)
},
}}
>
</el-table-column>
{this.renderColData()}
</el-table>)
}
method:{
renderColData() {
return this.$createElement('el-table-column', {
props: {
align:"left" ,
label:"数据2" ,
width:"200" ,
prop:"data" ,
},
scopedSlots: {
default: ({ row }) => {
return (
<span onClick={this.consoleInfo} >{JSON.stringify(row.data)}</span>
)
}
}
})
},
consoleInfo() {
console.log("方法被调用")
}
}
6.template与jsx 混编
<template>
<div>
<span>Message: {{ msg }}</span>
<VNodes :vnodes="getSpan()" />
<VNodes :vnodes="getMyH(2)" />
</div>
</template>
<script>
export default {
components: {
VNodes: { //这里在引入的组件直接定义组件为函数式组件
functional: true,
render: (h, ctx) => ctx.props.vnodes
}
},
data() {
return {
msg: "xxxx"
};
},
methods: {
getSpan() {
return <span>Message: {this.msg}</span>;
},
getMyH(level) {
const Tag = `h${level}`;
return <Tag>Hello world!</Tag>;
}
}
};
</script>