如何在Vue项目中使用JSX?
作者:ManStruggling
来源:SegmentFault 思否社区
什么是 JSX?
JSX是一种JavaScript和XML的结合,即JavaScript + XML = JSX,JSX源于Facebook,可以在JavaScript里写XML,因为这个特性,所以具备了JavaScript的灵活性,同时又兼具html的语义化和直观性
为什么使用 JSX?
jsx对比createElement函数可读性更强;<div></div> VS this.$createElement('div', {...}, [...])
vue-cli3.0及以上默认支持jsx语法
jsx可以使vue组件更容易导入和管理
栗子一
template模板语法
使用最多,不做解释
<div id="vnode">
一些文本
<p class="bar" style="color: red; font-weight: bold;">Only you can stop forest fires</p>
<span>span text</span>
<b>b tag</b>
</div>
createElement
createElement函数实际上创建的是Virtual Node,创建VNode树,一旦Dom树的结构复杂,dom节点属性太多,势必会造成可读性差的问题。。。
render(h) {
return h(
"div",
{
attrs: {
id: "vnode",
},
},
[
"一些文本",
h(
"p",
{
class: {
bar: true,
},
style: {
color: "red",
fontWeight: "bold",
},
},
"Only you can stop forest fires"
),
h("span", {}, "span text"),
h("b", { domProps: { innerText: "b tag" } }),
]
);
}
JSX
然后jsx就闪亮登场
render() {
return (
<div id="vnode">
一些文本
<p class="bar" style="color: red; font-weight: bold;">
Only you can stop forest fires
</p>
<span>span text</span>
<b>b tag</b>
</div>
);
}
栗子二
template
<div>
<!-- 模块A -->
<div class="module-a" v-if="type === 0">
<div>
...模块A的代码
</div>
<div>
...公共代码
</div>
</div>
<!-- 模块B -->
<div class="module-b" v-else-if="type === 1">
<div>
...模块B的代码
</div>
<div>
...公共代码
</div>
</div>
<!-- 模块C -->
<div class="module-c" v-else>
<div>
...模块C的代码
</div>
<div>
...公共代码
</div>
</div>
</div>
JSX
render() {
// 提取公共模块代码
const renderCommon = () => <div>...公共代码</div>;
const renderA = () => (
<div class="module-a">
<div>...模块A的代码</div>
{renderCommon()}
</div>
);
const renderB = () => (
<div class="module-b">
<div>...模块B的代码</div>
{renderCommon()}
</div>
);
const renderC = () => (
<div class="module-c">
<div>...模块C的代码</div>
{renderCommon()}
</div>
);
return (
<div>
{this.type === 0 ? renderA() : this.type === 1 ? renderB() : renderC()}
</div>
);
}
Usage
<script>
export default {
render() {
// 条件渲染
const vIfRender = () => {
let show = false;
return (
<div
id={"test"}
class={{ "test-wrapper": true }}
style={{ fontWeight: "bold" }}
>
{show ? <div>display</div> : "hidden"}
</div>
);
};
// v-html渲染
const vHtmlRender = () => <div domPropsInnerHTML={`<i>i text</i>`}></div>;
const listRencer = () => (
<ol>
{[1, 2, 3, 4, 5].map((item) => (
<li>{item}</li>
))}
</ol>
);
// 事件绑定
const handleParentClick = () => {
console.log("trigger parent click");
};
const handleClick = (e) => {
e.stopPropagation();
console.log("trigger click");
};
const eventBindingRender = () => (
<div onClick={handleParentClick}>
parent text
<button domPropsInnerHTML={"点一下试试"} onClick={handleClick}></button>
</div>
);
// 属性绑定
const inputAttrs = {
type: "number",
placeholder: "请输入数字",
};
const attrBindingRender = () => <input {...{ attrs: inputAttrs }} />;
// 指令
const directiveBindingRender = () => (
<button
{...{
directives: [
{
name: "permission",
value: 666,
modifiers: { foo: true },
},
],
}}
>
权限管理
</button>
);
return (
<div>
{
// v-if 三目运算符
vIfRender()
}
{
// v-html
vHtmlRender()
}
{
// 列表渲染
listRencer()
}
{
// 事件绑定
eventBindingRender()
}
{
// 属性绑定
attrBindingRender()
}
{
// 指令
directiveBindingRender()
}
</div>
);
},
};
</script>
插槽和作用域插槽
// child.vue
<script>
export default {
props: {
config: {
type: Object,
required: true
}
},
render() {
return (
<div>
<h3>{this.config.text}</h3>
{this.$scopedSlots.content({
data: this.config.childConfig
})}
</div>
)
}
}
</script>
<script>
import Child from "./child";
export default {
render() {
const config = {
text: "parent text jsx",
childConfig: {
test: "children text jsx",
},
};
return (
<div>
<Child
config={config}
{...{
scopedSlots: {
content: ({data}) => {
return <div>{data.test}</div>;
},
},
}}
></Child>
</div>
);
},
};
</script>
评论