vue中正確使用jsx語法的姿勢分享
前言
又到了愉快的摸魚時間,我覺得不能荒廢,H5頁面我一直用的vant,出于對源碼的好奇,我從git上拉了一份vant源碼,里面竟然都是jsx寫的組件,于是我開始了對在vue中使用jsx的探索
虛擬DOM
什么是虛擬DOM
在這之前,先了解下虛擬DOM,vue和react框架都在內(nèi)部使用了虛擬DOM,這樣做的原因是通過js操作DOM的計算成本很高,雖然js更新速度很快,但是查找dom并更新的成本很高。那么有什么方法可以優(yōu)化呢,vue等框架使用js對象,通過改變js對象,最后進行批量處理,一次更新DOM,所以虛擬DOM本質(zhì)上就是一個js對象
虛擬DOM的優(yōu)點
- 從原先的操作真實DOM到操作虛擬DOM,降低查找成本
- 通過diff比對,我們可以更快的定位數(shù)據(jù)的變化,從而更新DOM
- 更好的ui更新
- 抽象渲染過程,帶來了實現(xiàn)跨平臺的能力,如vue3中的createRenderer API
渲染函數(shù)是什么
渲染函數(shù)是用來生成虛擬DOM的。我們在vue單文件中編寫模板語法,最終會在底層實現(xiàn)中被編譯成渲染函數(shù)
Vue 推薦在絕大多數(shù)情況下使用模板來創(chuàng)建你的 HTML。然而在一些場景中,你真的需要 JavaScript 的完全編程的能力。這時你可以用渲染函數(shù),它比模板更接近編譯器。
當(dāng)出現(xiàn)以下場景,雖然下列寫法也能實現(xiàn)想要的效果,但是他不僅冗長,而且我們?yōu)槊總€級別標(biāo)題重復(fù)書寫了 。當(dāng)我們添加錨元素時,我們必須在每個 v-if/v-else-if 分支中再次重復(fù)它
const { createApp } = Vue
const app = createApp({})
app.component('anchored-heading', {
template: `
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
`,
props: {
level: {
type: Number,
required: true
}
}
})
雖然模板在大多數(shù)組件中都非常好用,但是顯然在這里它就不合適了。那么,我們來嘗試使用 render 函數(shù)重寫上面的例子:
const { createApp, h } = Vue
const app = createApp({})
app.component('anchored-heading', {
render() {
return h(
'h' + this.level, // tag name
{}, // props/attributes
this.$slots.default() // array of children
)
},
props: {
level: {
type: Number,
required: true
}
}
})
jsx
這樣寫渲染函數(shù)有點痛苦,有沒有更接近模板的寫法呢,vue提供了一個babel-plugin-jsx babel插件來讓vue支持jsx寫法
我這邊使用的vuecli創(chuàng)建的vue3 + ts項目,腳手架已經(jīng)集成了jsx和ts的相關(guān)依賴
在vue3中編寫jsx的兩種方式
直接將文件后綴名從vue改成tsx或者jsx
在vue3中,可以直接使用render選項編寫
import { defineComponent } from "vue";
export default defineComponent({
name: "Jsx",
render() {
return <div>我是一個div</div>;
},
});
也可以在setup中返回
import { defineComponent } from "vue";
export default defineComponent({
name: "Jsx",
setup() {
return () => <div>我是div</div>;
},
});
兩種方式都可以,具體看個人習(xí)慣,setup中訪問不到this,但是render中可以通過this訪問當(dāng)前vue實例
用法
class綁定,和react的jsx綁定的有區(qū)別,react中使用className,vue中使用class
setup() {
return () => <div class="test">我是div</div>;
},
style綁定
setup() {
return () => <div style={{ color: "red" }}>我是div</div>;
},
props綁定
// 父組件
setup() {
return () => (
<div style={{ color: "red" }}>
<span>我是父組件</span>
<Mycom msg={"我是父組件傳的值"} />
</div>
);
// 子組件,setup的第一個參數(shù),可以獲取props里的值
setup(props) {
return () => <div>我是子組件{props.msg}</div>;
},
事件綁定
setup() {
function eventClick() {
console.log("點擊");
}
return () => <button onClick={eventClick}>按鈕</button>;
},
組件自定義事件
// 子組件
import { defineComponent } from "vue";
export default defineComponent({
name: "Mycom",
emits: ["event"],
setup(props, { emit }) {
function sendData() {
emit("event", "子組件傳遞的數(shù)據(jù)");
}
return () => (
<div>
<span>自定義事件</span>
<button onClick={sendData}>傳遞數(shù)據(jù)</button>
</div>
);
},
});
// 父組件
// @ts-nocheck
// 這樣寫在jsx中沒問題,但是在tsx中會報ts類型錯誤,所以我在上面忽略了當(dāng)前文件ts監(jiān)測@ts-nocheck
import { defineComponent } from "vue";
import Mycom from "./mycom";
export default defineComponent({
name: "Jsx",
setup() {
function getSon(msg: string) {
console.log(msg);
}
return () => (
<div>
<Mycom onEvent={getSon} />
</div>
);
},
});
也可以這樣解決ts類型報錯
setup() {
function getSon(msg: string) {
console.log(msg);
}
return () => (
<div>
<Mycom {...{ onEvent: getSon }} />
</div>
);
},
插槽
// 父組件
setup() {
const slots = {
test: () => <div>具名插槽</div>,
default: () => <div>默認(rèn)插槽</div>,
};
return () => (
<div>
<Mycom v-slots={slots}></Mycom>
</div>
);
},
setup(props, { slots }) {
// 子組件
return () => (
<div>
<span>插槽</span>
{slots.default?.()}
{slots.test?.()}
</div>
);
},
指令,v-if,v-for等指令在jsx中無法使用,jsx只支持v-model和v-show指令
setup() {
const inputData = ref("");
return () => (
<div>
<span v-show={true}>顯示</span>
<span v-show={false}>隱藏</span>
<input type="text" v-model={inputData.value} />
<span>{inputData.value}</span>
</div>
);
},
最后
話不多說,我先打開vant源碼,準(zhǔn)備開啟我的第一個組件源碼閱讀 src =>button=>button.tsx
到此這篇關(guān)于vue中正確使用jsx的文章就介紹到這了,更多相關(guān)vue中使用jsx內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考
相關(guān)文章
vue2 中使用 render 函數(shù)編寫組件的方式
vue提供了聲明式編寫UI的方式,即vue提供了對DOM進行描述的方式,有兩種描述DOM的方式即模板和render 函數(shù),本文通過示例代碼介紹vue2 中使用 render 函數(shù)編寫組件的方式,感興趣的朋友跟隨小編一起看看吧2024-06-06
vue-router中關(guān)于children的使用方法
這篇文章主要介紹了vue-router中關(guān)于children的使用方法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
Ant Design Vue如何生成動態(tài)菜單a-menu
這篇文章主要介紹了Ant Design Vue如何生成動態(tài)菜單a-menu問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
jeecgboot-vue3查詢區(qū)label文字居左實現(xiàn)過程解析
這篇文章主要為大家介紹了jeecgboot-vue3查詢區(qū)label文字居左實現(xiàn)過程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪<BR>2023-08-08
el-date-picker設(shè)置日期默認(rèn)值兩種方法(當(dāng)月月初至月末)
這篇文章主要給大家介紹了關(guān)于el-date-picker設(shè)置日期默認(rèn)值(當(dāng)月月初至月末)的相關(guān)資料,文中通過代碼示例將解決的辦法介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08

