JSX是React出的一種對JavaScript的語法擴展。javascript
在Vue中大多數狀況推薦使用模板語法,經過template中的Vue指令進行快速開發。可是template也是存在一些缺陷的,擴展難度大,形成邏輯冗餘。這時候咱們就須要JavaScript
的徹底編程能力,結合render函數
與JSX
進行功能擴展。html
在JSX中,咱們能夠在大括號中使用任何有效的JS表達式vue
// 動態渲染內容
let name = "Josh Perez"
let element = <h1>Hello {name}</h1>
// 動態綁定屬性
let imgUrl = 'http://xxx.jpg'
let img = <img src={imgUrl} /> 複製代碼
在
<>
中寫HTML標籤,在{}
中寫js代碼java
JSX代碼自己也是js表達式,它表示的是一個js對象。react
// 在vue的render函數中,如下兩種寫法是等價的
render: function(createElement) {
let name = "Josh Perez"
let element = <h1 class="title">Hello {name}</h1>
return element
}
// ===》》
render: function(createElement) {
let name = "Josh Perez"
let element = createElement(
'h1',
{class: title},
`Hello ${name}`
)
return element
}
複製代碼
事實上, Babel會把JSX語法轉義成JS對象,也就是上述代碼的後一種寫法。git
在JSX中事件的命名採用小駝峯式(camelCase),而不是純小寫。github
methods: {
deleteRow(id) {
// todo
}
},
render: (h) => {
return <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
}
複製代碼
在JSX中沒法使用Vue中的v-if-else
指令,可使用Javascript中的運算符if
或者三元運算符
代替編程
// if運算符
let isEnable = props.isEnable
render(h) {
if(isEnable) {
return <button>禁用</button>
} else {
return <button>啓用</button>
}
}
複製代碼
// 三元運算符
let isEnable = props.isEnable
render(h) {
return <button>{isEnable ? '禁用' : '啓用'}</button>
}
複製代碼
在JSX中能夠經過map
實現v-for
bash
render: (h) => {
const numbers = [1, 2, 3, 4, 5]
let listItems = numbers.map(number =>
<li>{number}</li>
)
return (
<ul>{listItems}</ul>
)
}
複製代碼
實現key
屬性的綁定iview
render: (h) => {
const numbers = [1, 2, 3, 4, 5]
let listItems = numbers.map(number =>
<li key={number.toString()}>{number}</li>
)
return (
<ul>{listItems}</ul>
)
}
複製代碼
在JSX中嵌入map
render: (h) => {
const numbers = [1, 2, 3, 4, 5]
let listItems =
return (
<ul> { numbers.map(number => <li key={number.toString()}>{number}</li> ) } </ul>
)
}
複製代碼
Vue 推薦在絕大多數狀況下使用模板來建立你的 HTML。可是在開發過程當中template
並不能知足咱們的全部需求,在一些組件開發中比較常見
下面是我在工做中根據業務場景對Element UI中的table組件進行的擴展,或許能夠加深一些對JSX的理解.
在開發後臺管理系統時,不可避免的要進行大量數據列表的展現。目前比較流行的第三方組件庫 Element UI,其列表渲染的代碼以下:
<el-table :data="list">
<el-table-column prop="name" lable="姓名" width="150" align="center"></el-table-column>
<el-table-column prop="age" lable="年齡" width="150" align="center"></el-table-column>
.
.
.
</el-table>
複製代碼
每一列都須要寫一次el-table-column
標籤,尤爲在處理財務報表這種展現大批量類似數據時,是很是痛苦的。
咱們期待的效果是這樣的:
<table :data="list" :columns="columns">
複製代碼
data() {
return {
list: []
columns: []
}
}
複製代碼
將列的描述信息放到js中,這樣能夠省去很多代碼,代碼結構也會清晰不少。具體實現過程以下:
基於Element UI 對table組件進行二次封裝
<template>
<el-table :data="data" v-bind="$attrs">
<template v-for="(column, index) of columns">
<!-- render -->
<el-table-column v-if="column.render" v-bind="Object.assign({}, defaultColumnConfig, column)" :key="index">
<template slot-scope="scope">
<extend :render="column.render" :params="scope"></extend>
</template>
</el-table-column>
<!-- no render -->
<el-table-column v-else v-bind="Object.assign({}, defaultColumnConfig, column)" :key="index"></el-table-column>
</template>
</el-table>
</template>
<script> import extend from './extend.js' export default { components: { extend }, props: { data: { type: Array }, columns: { type: Array }, defaultColumnConfig: { type: Object } } } </script>
複製代碼
經過extend
組件實現render
函數
export default {
props: {
params: {
type: Object
},
render: {
type: Function
}
},
render(h) {
return this.render(h, this.params)
}
}
複製代碼
<template>
<y-table :data="list" :columns="columns" :defaultColumnConfig="defaultColumnConfig" border></y-table>
</template>
<script>
import YTable from "./index"
export default {
components: {
YTable
},
data() {
return {
list: [
{name: 1, age: 2, sex: 0}
],
defaultColumnConfig: {
width: 100,
align: 'center'
},
columns:[
{
prop: 'name',
label: '姓名',
age: 0,
width: 200
},
{
prop: 'age',
label: '年齡',
age: 1
},
{
label: '性別',
render(h,scope) {
return h(
'span',
{
style: {color: 'red'}
},
scope.row.sex === 0 ? '男' : '女'
)
}
},
{
label: '性別',
render(h,scope) {
return (
<span style="color: red">{scope.row.sex === 0 ? '男' : '女'}</span>
)
}
}
]
}
}
}
</script>
複製代碼
渲染效果: