一文徹底教會(huì)你在vue中寫jsx
前言:
近幾年都比較流行vue3+tsx相信react開發(fā)應(yīng)該還是很了解jsx語法的,但是很多vue初中級(jí)開發(fā)還是很多人不會(huì)使用jsx,不知道怎么寫。接下來慢慢教你哈(項(xiàng)目中使用的是vue2+jsx,因?yàn)橹黝}是講在vue中使用jsx)!
一、用render函數(shù)寫一個(gè)頁面:
首先vue中有個(gè)render函數(shù),他只支持xml的形式返回dom結(jié)構(gòu)。但是寫頁面不能用.vue當(dāng)文件后綴了,需要改成jsx,如果是ts就是tsx。
下面是一個(gè)home.jsx:
export default {
name:'home',
components:{},
props:{},
data(){
return {
info:{
age:18
}
}
},
computed:{},
watch:{},
mounted(){},
methods:{},
render() {
return <div>我是小明,我今年{this.info.age}歲</div>
}
}頁面呈現(xiàn)是這樣的:

其實(shí)在vue中寫jsx并沒有多難,只是語法稍微有點(diǎn)不同而已。比如上面的例子,home.jsx文件后綴名從.vue變成了.jsx。內(nèi)部把 template 的結(jié)構(gòu)搬到了,render函數(shù)中。當(dāng)然在render函數(shù)中寫 template模版 結(jié)構(gòu)和大致寫法都一樣,但是還是有些地方需要注意的。
上面的例子中.vue中變量是這樣寫的{{info.age}},jsx中雙花括號(hào)變成了單個(gè),并且變量需要附帶this。
二、在render函數(shù)注冊(cè)事件
在render函數(shù)注冊(cè)事件和 template 中的 v-on:click||@click不同,偏向原聲寫法如click事件onClick={tins.click}、input事件onInput={this.input},寫法如下:
export default {
name: 'home',
components: {},
props: {},
data() {
return {
info: {
age: 18,
gender: ''
},
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
Gender() {
this.info.gender = '男';
}
},
render() {
return <div className="home">
<div>我是小明,我今年{this.info.age}歲</div>
<div>我是{this.info.gender}性</div>
<button onClick={this.Gender}>查詢我的性別</button>
</div>
}
}頁面如下:

三、vue指令在render函數(shù)是怎么代替的:
在render函數(shù)中沒有指令這個(gè)東西了,比如v-if,v-show等這些都是自定義指令。在vue中寫v-if或者v-show是這樣的,如下:
1、v-if
v-if其實(shí)就是控制{}內(nèi)的代碼返回值。返回dom或者返回空
export default {
name: 'home',
components: {},
props: {},
data() {
return {
info: {
age: 18,
gender: ''
},
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
getGender() {
this.info.gender = '男';
},
genderDom() {
return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
}
},
render() {
return <div className="home">
<div>我是小明,我今年{this.info.age}歲</div>
{/* 三元表達(dá)寫法 */}
{
this.info.gender ? <div>我是{this.info.gender}性</div> : ''
}
{/* 也可以用&&判斷寫 */}
{
this.info.gender && <div>我是{this.info.gender}性</div>
}
{/* 函數(shù)返回寫法 */}
{
this.genderDom()
}
{/* 錯(cuò)誤寫法,在render不能直接使用if else */}
{/* {
if(this.info.gender){
return <div>我是{this.info.gender}性</div>
}else{
return ''
}
} */}
<button onClick={this.getGender}>查詢我的性別</button>
</div>
}
}2、v-show
vue中的v-show大家都應(yīng)該知道它只是控制樣式display的none||block,那知道這點(diǎn)其實(shí)就很簡單了:
export default {
name: 'home',
components: {},
props: {},
data() {
return {
info: {
age: 18,
gender: ''
},
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
getGender() {
this.info.gender = '男';
},
genderDom() {
return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
}
},
render() {
return <div className="home">
<div>我是小明,我今年{this.info.age}歲</div>
{/* 控制性別這個(gè)div的樣式即可 */}
<div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
{this.info.gender}性</div>
<button onClick={this.getGender}>查詢我的性別</button>
</div>
}
}注:上面代碼中style={{ display: this.info.gender ? 'block' : 'none' }} 可以這樣寫?style={obj};obj={display: this.info.gender ? 'block' : 'none'},這樣是不是就理解了,里面只是一個(gè)對(duì)象,還是單個(gè)花括號(hào)放變量的!
3、v-for:
jsx中實(shí)現(xiàn)v-for,只是用.map代替了而已:
// this.arr = [1,2,3,4,5];
<div>
{this.arr.map((item,index)=><div key={index}>{item}</div>)}
</div>4、v-model:
說到v-model,這個(gè)你就要理解vue中v-model其實(shí)只是一個(gè)語法糖,它就是:value,@input 兩個(gè)方法組合起來的而已。那么在render中寫法如下:
index.jsx
import hobby from './component/hobby';
export default {
name: 'home',
components: { hobby },
props: {},
data() {
return {
info: {
age: 18,
gender: '',
hobby: '我是一個(gè)沒有愛好的木頭人!'
},
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
getGender() {
this.info.gender = '男';
},
genderDom() {
return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
}
},
render() {
return <div className="home">
<div>我是小明,我今年{this.info.age}歲</div>
{/* 控制性別這個(gè)div的樣式即可 */}
<div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
{this.info.gender}性</div>
<button onClick={this.getGender}>查詢我的性別</button>
<hobby value={this.info.hobby} onInput={(value) => { this.info.hobby =
value }} />
</div>
}
}index.jsx中引入的子組件,hobby.jsx :
export default {
name: 'hobby',
components: {},
props: {
value: {
type: String,
debugger: '我是一個(gè)沒有愛好的木頭人!'
}
},
data() {
return {
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
},
render() {
return <div className="hobby">
我的愛好是:{this.value}
<input value={this.value} onInput={(e) => { this.$emit('input',
e.target.value); }} />
</div>
}
}好麻煩我就不每次截頁面的圖了。這個(gè)你們自己拷貝的代碼去試試看就知道了!
hobby.jsx中的input 其實(shí)就是一個(gè)v-model的實(shí)現(xiàn),然后在看一下index.jsx中在hobby組件上直接寫
v-model,其實(shí)就是hobby接受了個(gè)value,然后再用$emit一個(gè)input事件去修改v-model的值。當(dāng)然你也可以用vue的model去改變v-model的value,和input。使用自定義名字(因?yàn)殚_發(fā)中可能存在value或者input被其它參數(shù)使用了),這里就不多介紹啦。
最后如果你覺得v-model寫起來好麻煩,想直接在render中使用v-model。那么也不是不行,
去安裝一個(gè) babel-plugin-jsx-v-model 依賴。然后在項(xiàng)目根目錄找到babel.config.js,加入

就可以直接使用了!

5、.sync
在template中使用.sync是這樣的:visible.sync="dialogVisible",但是在render中使用.sync是如下這樣的
父組件index.jsx:
import hobby from './component/hobby';
import child from './component/child';
export default {
name: 'home',
components: { hobby, child },
props: {},
data() {
return {
info: {
age: 18,
gender: '',
hobby: '我是一個(gè)沒有愛好的木頭人!'
},
childData: "父親傳給child的數(shù)據(jù)",
}
},
computed: {},
watch: {},
mounted() {
},
methods: {
getGender() {
this.info.gender = '男';
},
genderDom() {
return this.info.gender ? <div>我是{this.info.gender}性</div> : ''
}
},
render() {
return <div className="home">
<div>我是小明,我今年{this.info.age}歲</div>
{/* 控制性別這個(gè)div的樣式即可 */}
<div style={{ display: this.info.gender ? 'block' : 'none' }}>我是
{this.info.gender}性</div>
<button onClick={this.getGender}>查詢我的性別</button>
{/* <hobby value={this.info.hobby} onInput={(value) => {
this.info.hobby = value }} /> */}
<hobby value={this.info.hobby} onInput={(value) => { this.info.hobby =
value }} />
<div>模擬.sycn</div>
{this.childData}
<child
{...{
props: {
value: this.childData
},
on: {
'update:value': (val) => {
console.log(val)
this.childData = val;
},
}
}}
/>
</div>
}
}簡單來說,有可能會(huì)有這種情況,就是你寫了個(gè)jsx的組件,但是你的同事他不會(huì)jsx。但是他要使用你寫的jsx組件,然后用.sync,那你同事是這樣寫的<child value.sync='value' />。然后你就不知道怎么接受了,并且去改變value.sync='value'中的value?其實(shí).sycn和v-model一樣只是個(gè)語法糖而已,它是由.sycn前面的變量名,也就是bind一個(gè)value(名字自定義的)和 on一個(gè)‘update:value’名字的方法而已。
四、render中插槽的使用
1、默認(rèn)插槽
在 template 中使用默認(rèn)插槽:
// 父組件
<template>
<child>
我是插入的內(nèi)容
</child>
</template>
// 子組件 child
<template>
<div>
<slot />
</div>
</template>
在 render 中使用默認(rèn)插槽:
// 父組件
render(){
return <div>
<child>
默認(rèn)插槽
</child>
</div>
}
// 父組件也可以這樣寫
render(){
return <div>
<child {
...{
scopedSlots: {
default:()=>'默認(rèn)插槽'
}
}
}/>
</div>
}
// child 子組件
render(){
return <div>
{this.$scopedSlots.default()}
</div>
}2、具名插槽
render(){
return <div>
<child {
...{
scopedSlots: {
soltName:()=>'具名插槽'
}
}
}/>
</div>
}
// child 子組件
render(){
return <div>
{this.$scopedSlots.soltName()}
</div>
}3、作用域插槽
// 父組件
render(){
return <div>
<child {
...{
scopedSlots: {
soltName:(scope)=><div>
child對(duì)我說:{scope}
</div>
}
}
}/>
</div>
}
// child 子組件
render(){
return <div>
{this.$scopedSlots.soltName('我是child,我要告訴你我的真心話!')}
</div>
}五、傳參、事件綁定、行內(nèi)屬性的對(duì)象寫法(深入數(shù)據(jù)對(duì)象):
相信很多人可能看不懂之前例子中

這種穿參數(shù)的方式,其實(shí)你需要了解dom節(jié)點(diǎn)的props、attrs、on...這些屬性的區(qū)別即可。這只是一個(gè)寫法的不同:
// template 中 你使用組件可能是這樣寫的
<child :value='value' @click="click" style="width=100px" calss='class'/>
// 上面給 child組件傳了一個(gè)value,綁定了一個(gè)點(diǎn)擊事件,加了一個(gè)行內(nèi)樣式,綁定了一個(gè)樣式
// jsx中可以這樣寫
<child {...{
props:{
value:value,
},
on:{
click:click
},
attrs:{
style="width=100px",
class="class"
}
}}/>
// 這樣寫是不是看的更明白了?
const obj = {
props:{
value:value,
},
on:{
click:click
},
attrs:{
style="width=100px",
class="class"
}
}
<child {...obj}/>注:
on:就是綁定的事件,比如你需要綁定input事件只需要在on 對(duì)象中添加一個(gè)值key:value的形式,key是你的事件名稱、value是你綁定的function。
props:其實(shí)就是子組件接受的props,和on差不多也是key:value的形式。
attrs:就是需要綁定在當(dāng)前dom上的行內(nèi)屬性,比如class、style、type、name、id等,可以在控制臺(tái)中看見。

借鑒了一下官方的介紹,可以看看:
{
// 與 `v-bind:class` 的 API 相同,
// 接受一個(gè)字符串、對(duì)象或字符串和對(duì)象組成的數(shù)組
'class': {
foo: true,
bar: false
},
// 與 `v-bind:style` 的 API 相同,
// 接受一個(gè)字符串、對(duì)象,或?qū)ο蠼M成的數(shù)組
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML attribute
attrs: {
id: 'foo'
},
// 組件 prop
props: {
myProp: 'bar'
},
// DOM property
domProps: {
innerHTML: 'baz'
},
// 事件監(jiān)聽器在 `on` 內(nèi),
// 但不再支持如 `v-on:keyup.enter` 這樣的修飾器。
// 需要在處理函數(shù)中手動(dòng)檢查 keyCode。
on: {
click: this.clickHandler
},
// 僅用于組件,用于監(jiān)聽原生事件,而不是組件內(nèi)部使用
// `vm.$emit` 觸發(fā)的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定義指令。注意,你無法對(duì) `binding` 中的 `oldValue`
// 賦值,因?yàn)?Vue 已經(jīng)自動(dòng)為你進(jìn)行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽的格式為
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果組件是其它組件的子組件,需為插槽指定名稱
slot: 'name-of-slot',
// 其它特殊頂層 property
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函數(shù)中給多個(gè)元素都應(yīng)用了相同的 ref 名,
// 那么 `$refs.myRef` 會(huì)變成一個(gè)數(shù)組。
refInFor: true
}六、最后結(jié)合之前的例子試一下:
index.jsx
import child from './component/child';
export default {
name: 'Test',
components: { child },
props: {},
data() {
return {
age: 17,
arr: [{ name: '小明', age: 16 }, { name: '小明媽媽', age: 40 }, { name: '小明爸爸', age: 46 }]
}
},
computed: {
setOptions() {
return {
//插槽屬性
scopedSlots: {
default: (scope) => <div>我是默認(rèn)插槽,{this.showScope(scope)}
</div>,
slotsName: (scope) => <div>我是具名插槽,我的名字叫slotsName,
{this.showScope(scope)}</div>,
},
props: {
age: this.age,
},
attrs: {
style: 'width:100%;height:200px;background-color:red'
},
on: {
ageAdd: () => { this.age++ },
input: (count) => { this.age = count }
}
}
}
},
watch: {},
mounted() {
},
methods: {
showScope(scope) {
return `子組件傳給我的參數(shù)是:${scope}`
}
},
render() {
return <div class="Test">
<div>父組件</div>
我的年齡是:{this.age}
<div>子組建</div>
<child {...this.setOptions} />
<div>小明全家</div>
<ul>
{
this.arr.map((item, index) => <div key={index}>
{item.name}:{item.age}
</div>)
}
</ul>
{/* <child {...this.setOptions} v-model={this.age}/> */}
</div>
}
}child.jsx
export default {
name: 'child',
components: {},
// model: {
// prop: "inputValue",
// event: "up",
// },
props: ['age'],
data() {
return {
}
},
computed: {},
watch: {},
mounted() {
console.log(this.$attrs, this.$listeners)
},
methods: {
},
render() {
return <div class="child">
<button onClick={() => { this.$emit('ageAdd') }}>老一歲</button>
<div>
修改年紀(jì):
<input value={this.age} onInput={(e) => { this.$emit('input',
e.target.value) }} />
{/* <input value={this.$attrs.inputValue} onInput={(e) => {
this.$emit('up', e.target.value) }} /> */}
</div>
<div>插槽</div>
{this.$scopedSlots.default&&this.$scopedSlots.default(666)}
{this.$scopedSlots.slotsName&&this.$scopedSlots.slotsName(789)}
</div>
}
}可以去試試看,方法了解開發(fā)中需要靈活運(yùn)用,邏輯清晰。
其實(shí)官方介紹的就挺詳細(xì)的:渲染函數(shù) & JSX — Vue.js
總結(jié)
到此這篇關(guān)于在vue中寫jsx的文章就介紹到這了,更多相關(guān)vue中寫jsx內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue簡單練習(xí) 桌面時(shí)鐘的實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了vue簡單練習(xí) 桌面時(shí)鐘的實(shí)現(xiàn)代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值的相關(guān)資料,需要的朋友可以參考下2019-09-09
vue實(shí)現(xiàn)websocket客服聊天功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)websocket客服聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10
詳解vue開發(fā)中調(diào)用微信jssdk的問題
這篇文章主要介紹了vue開發(fā)中調(diào)用微信jssdk的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
深入學(xué)習(xí)Vue nextTick的用法及原理
這篇文章主要介紹了深入學(xué)習(xí)Vue nextTick的用法及原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10

