共计 3458 个字符,预计需要花费 9 分钟才能阅读完成。
一.JSX 简介
const element = <h1>Hello, world!</h1>;
JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能。
Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
以下两种示例代码完全等效:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
二. 模板缺陷
模板的最大特点是扩展难度大,不易扩展。可能会造成逻辑冗余:
<Level :type="1"> 哈哈 </Level>
<Level :type="2"> 哈哈 </Level>
<Level :type="3"> 哈哈 </Level>
Level 组件需要对不同的 type 产生不同的标签
<template>
<h1 v-if="type==1">
<slot></slot>
</h1>
<h2 v-else-if="type==2">
<slot></slot>
</h2>
<h3 v-else-if="type==3">
<slot></slot>
</h3>
</template>
<script>
export default {
props: {
type: {type: Number}
}
};
</script>
三. 函数式组件
函数式组件没有模板,只允许提供 render 函数
export default {render(h) {return h("h" + this.type, {}, this.$slots.default);
},
props: {
type: {type: Number}
}
};
复杂的逻辑变得非常简单
四.JSX 应用
使用 jsx 会让代码看起来更加简洁、易于读取
export default {render(h) {
const tag = "h" + this.type;
return <tag>{this.$slots.default}</tag>;
},
props: {
type: {type: Number}
}
};
五.render 方法定制组件
编写 List 组件,可以根据用户传入的数据自动循环列表
<List :data="data"></List>
<script>
import List from "./components/List";
export default {data() {
return {data: ["苹果", "香蕉", "橘子"]
};
},
components: {List}
};
</script>
<!-- List 组件渲染列表 -->
<template>
<div class="list">
<ul v-for="(item,index) in data" :key="index">
<li>{{item}}</li>
</ul>
</div>
</template>
<script>
export default {
props: {
data: Array,
default: () => []
}
};
</script>
通过 render 方法来定制组件,在父组件中传入 render 方法
<List :data="data" :render="render"></List>
render(h, name) {return <span>{name}</span>;
}
我们需要 createElement 方法,就会想到可以编写个函数组件,将 createElement 方法传递出来
<template>
<div class="list">
<div v-for="(item,index) in data" :key="index">
<li v-if="!render">{{item}}</li>
<!-- 将 render 方法传到函数组件中,将渲染项传入到组件中,在内部回调这个 render 方法 -->
<ListItem v-else :item="item" :render="render"></ListItem>
</div>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
components: {ListItem},
props: {
render: {type: Function},
data: Array,
default: () => []
}
};
</script>
ListItem.vue 调用最外层的 render 方法,将 createElement 和当前项传递出来
<script>
export default {
props: {
render: {type: Function},
item: {}},
render(h) {return this.render(h, this.item);
}
};
</script>
六.scope-slot
使用 v -slot 将内部值传入即可
<List :arr="arr">
<template v-slot="{item}">
{{item}}
</template>
</List>
<div v-for="(item,key) in arr" :key="key">
<slot :item="item"></slot>
</div>
七. 编写可编辑表格
基于 iview 使用 jsx 扩展成可编辑的表格
<template>
<div>
<Table :columns="columns" :data="data"></Table>
</div>
</template>
<script>
import Vue from 'vue';
export default {
methods:{render(h,{column,index,row}){let value = row[column.key];
return <div on-click={(e)=>this.changeIndex(e,index)} >
{this.index === index ?
<i-input type="text" value={value} on-input={(value)=>{this.handleChange(value,column,row)
}} onOn-enter={()=>this.enter(row,index)}/>:
<span>{value}</span>
}
</div>
},
enter(row,index){this.data.splice(index,1,row);
this.index = -1;
},
handleChange(value,column,row){row[column['key']]= value;
},
changeIndex(e,index){
this.index = index;
this.$nextTick(()=>{e.currentTarget.getElementsByTagName("input")[0].focus();})
}
},
data() {
return {
index:-1,
columns: [
{
title: 'Name',
key: 'name',
render:this.render
},
{
title: 'Age',
key: 'age',
},
{
title: 'Address',
key: 'address',
},
],
data: [
{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03',
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01',
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02',
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04',
},
],
};
},
};
</script>
想要了解更多关于 JSX 的内容,欢迎关注【前端优选】
正文完
发表至: javascript
2019-09-04