一文徹底教會你在vue中寫jsx
前言:
近幾年都比較流行vue3+tsx相信react開發(fā)應該還是很了解jsx語法的,但是很多vue初中級開發(fā)還是很多人不會使用jsx,不知道怎么寫。接下來慢慢教你哈(項目中使用的是vue2+jsx,因為主題是講在vue中使用jsx)!
一、用render函數(shù)寫一個頁面:
首先vue中有個render函數(shù),他只支持xml的形式返回dom結(jié)構(gòu)。但是寫頁面不能用.vue當文件后綴了,需要改成jsx,如果是ts就是tsx。
下面是一個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)是這樣的:
其實在vue中寫jsx并沒有多難,只是語法稍微有點不同而已。比如上面的例子,home.jsx文件后綴名從.vue變成了.jsx。內(nèi)部把 template 的結(jié)構(gòu)搬到了,render函數(shù)中。當然在render函數(shù)中寫 template模版 結(jié)構(gòu)和大致寫法都一樣,但是還是有些地方需要注意的。
上面的例子中.vue中變量是這樣寫的{{info.age}},jsx中雙花括號變成了單個,并且變量需要附帶this。
二、在render函數(shù)注冊事件
在render函數(shù)注冊事件和 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ù)中沒有指令這個東西了,比如v-if,v-show等這些都是自定義指令。在vue中寫v-if或者v-show是這樣的,如下:
1、v-if
v-if其實就是控制{}內(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> {/* 三元表達寫法 */} { this.info.gender ? <div>我是{this.info.gender}性</div> : '' } {/* 也可以用&&判斷寫 */} { this.info.gender && <div>我是{this.info.gender}性</div> } {/* 函數(shù)返回寫法 */} { this.genderDom() } {/* 錯誤寫法,在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大家都應該知道它只是控制樣式display的none||block,那知道這點其實就很簡單了:
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> {/* 控制性別這個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'},這樣是不是就理解了,里面只是一個對象,還是單個花括號放變量的!
3、v-for:
jsx中實現(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,這個你就要理解vue中v-model其實只是一個語法糖,它就是:value,@input 兩個方法組合起來的而已。那么在render中寫法如下:
index.jsx
import hobby from './component/hobby'; export default { name: 'home', components: { hobby }, props: {}, data() { return { info: { age: 18, gender: '', hobby: '我是一個沒有愛好的木頭人!' }, } }, 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> {/* 控制性別這個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: '我是一個沒有愛好的木頭人!' } }, 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> } }
好麻煩我就不每次截頁面的圖了。這個你們自己拷貝的代碼去試試看就知道了!
hobby.jsx中的input 其實就是一個v-model的實現(xiàn),然后在看一下index.jsx中在hobby組件上直接寫
v-model,其實就是hobby接受了個value,然后再用$emit一個input事件去修改v-model的值。當然你也可以用vue的model去改變v-model的value,和input。使用自定義名字(因為開發(fā)中可能存在value或者input被其它參數(shù)使用了),這里就不多介紹啦。
最后如果你覺得v-model寫起來好麻煩,想直接在render中使用v-model。那么也不是不行,
去安裝一個 babel-plugin-jsx-v-model 依賴。然后在項目根目錄找到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: '我是一個沒有愛好的木頭人!' }, 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> {/* 控制性別這個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> } }
簡單來說,有可能會有這種情況,就是你寫了個jsx的組件,但是你的同事他不會jsx。但是他要使用你寫的jsx組件,然后用.sync,那你同事是這樣寫的<child value.sync='value' />。然后你就不知道怎么接受了,并且去改變value.sync='value'中的value?其實.sycn和v-model一樣只是個語法糖而已,它是由.sycn前面的變量名,也就是bind一個value(名字自定義的)和 on一個‘update:value’名字的方法而已。
四、render中插槽的使用
1、默認插槽
在 template 中使用默認插槽:
// 父組件 <template> <child> 我是插入的內(nèi)容 </child> </template> // 子組件 child <template> <div> <slot /> </div> </template>
在 render 中使用默認插槽:
// 父組件 render(){ return <div> <child> 默認插槽 </child> </div> } // 父組件也可以這樣寫 render(){ return <div> <child { ...{ scopedSlots: { default:()=>'默認插槽' } } }/> </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對我說:{scope} </div> } } }/> </div> } // child 子組件 render(){ return <div> {this.$scopedSlots.soltName('我是child,我要告訴你我的真心話!')} </div> }
五、傳參、事件綁定、行內(nèi)屬性的對象寫法(深入數(shù)據(jù)對象):
相信很多人可能看不懂之前例子中
這種穿參數(shù)的方式,其實你需要了解dom節(jié)點的props、attrs、on...這些屬性的區(qū)別即可。這只是一個寫法的不同:
// template 中 你使用組件可能是這樣寫的 <child :value='value' @click="click" style="width=100px" calss='class'/> // 上面給 child組件傳了一個value,綁定了一個點擊事件,加了一個行內(nèi)樣式,綁定了一個樣式 // 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 對象中添加一個值key:value的形式,key是你的事件名稱、value是你綁定的function。
props:其實就是子組件接受的props,和on差不多也是key:value的形式。
attrs:就是需要綁定在當前dom上的行內(nèi)屬性,比如class、style、type、name、id等,可以在控制臺中看見。
借鑒了一下官方的介紹,可以看看:
{ // 與 `v-bind:class` 的 API 相同, // 接受一個字符串、對象或字符串和對象組成的數(shù)組 'class': { foo: true, bar: false }, // 與 `v-bind:style` 的 API 相同, // 接受一個字符串、對象,或?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ù)中手動檢查 keyCode。 on: { click: this.clickHandler }, // 僅用于組件,用于監(jiān)聽原生事件,而不是組件內(nèi)部使用 // `vm.$emit` 觸發(fā)的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定義指令。注意,你無法對 `binding` 中的 `oldValue` // 賦值,因為 Vue 已經(jīng)自動為你進行了同步。 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ù)中給多個元素都應用了相同的 ref 名, // 那么 `$refs.myRef` 會變成一個數(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>我是默認插槽,{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> 修改年紀: <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ā)中需要靈活運用,邏輯清晰。
其實官方介紹的就挺詳細的:渲染函數(shù) & JSX — Vue.js
總結(jié)
到此這篇關(guān)于在vue中寫jsx的文章就介紹到這了,更多相關(guān)vue中寫jsx內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解vue開發(fā)中調(diào)用微信jssdk的問題
這篇文章主要介紹了vue開發(fā)中調(diào)用微信jssdk的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04