??背景
公司高級表單組件ProForm高階組件都建立在jsx的運用配置上,專案在實踐落地程序中積累了豐富的經驗,也充分感受到了jsx語法的靈活便捷和可維護性強大,享受到了用其開發的樂趣,獨樂樂不如眾樂樂,為了幫助大家更好的運用jsx,開發提效,特此總結分享,
??效果對比
以前
以往我們開發一個串列的增加、編輯、查看詳情三個操作要準備3個form表單檔案,表單中ui元素共性部分我們要復制三次,例如:
// addForm.vue
<template>
<el-form :model="form" >
<el-form-item label="活動名稱">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="活動區域">
<el-input v-model="form.region" />
</el-form-item>
<el-form-item label="活動形式">
<el-input v-model="form.type" />
</el-form-item>
</el-form>
<el-form-item>
<el-button >新增</el-button>
</el-form-item>
</template>
<script setup>
import { reactive } from 'vue'
const form = reactive({
name: '',
region: '',
type: '',
})
...
</script>
// editForm.vue
<template>
<el-form :model="form" >
<el-form-item label="活動名稱">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="活動區域">
<el-input v-model="form.region" />
</el-form-item>
<el-form-item label="活動形式">
<el-input v-model="form.type" />
</el-form-item>
<el-form-item>
<el-button >編輯</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive,inject } from 'vue'
const form = reactive({})
form=inject('detailData')
...
</script>
// detailForm.vue
<template>
<el-form :model="form" :disabled="true" >
<el-form-item label="活動名稱">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="活動區域">
<el-input v-model="form.region" />
</el-form-item>
<el-form-item label="活動形式">
<el-input v-model="form.type" />
</el-form-item>
<el-form-item>
<el-button >關閉詳情</el-button>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive,inject } from 'vue'
const form = reactive({})
form=inject('detailData')
...
</script>
如果遇到改欄位名的情況,如把活動名稱的name改成activityName,對應的3個檔案都得去修改,表單改動多的話還有可能存在有得檔案改漏的情況,
現在
現在使用ProForm結合jsx配置,如下
// add.vue
<template>
<activity-form
ref="formRef"
mode="Add"
/>
<el-button >新增</el-button>
</template>
<script setup>
Import ActivityForm from './form.vue'
...
</script>
// edit.vue
<template>
<activity-form
ref="formRef"
mode="Edit"
/>
<el-button >編輯</el-button>
</template>
<script setup>
Import ActivityForm from './form.vue'
...
</script>
// detail.vue
<template>
<activity-form
ref="formRef"
mode="detail"
/>
<el-button >關閉詳情</el-button>
</template>
<script setup>
Import ActivityForm from './form.vue'
...
</script>
Form.vue
<template>
<yun-pro-form
ref="formRef"
:form="form"
:columns="columns"
:form-props="{ labelPosition: 'top',disabled:mode==='detail' }"
/>
</template>
<script lang="jsx" setup>
import { reactive, ref, computed } from 'vue'
...
const formRef = ref()
const form = reactive({
name: '',
region: '',
type: '',
})
const props = defineProps({
mode: {
type: String,
default: 'Add',
},
});
const columns = [
{
prop: 'name',
label: '活動名稱',
type: 'input',
},
{
prop: 'region',
label: '活動區域',
// jsx部分
render: (form) => (
<el-input clearable v-model={form.region} />
),
},
{
prop: 'type',
label: '活動形式',
// jsx部分
render: (form) => (
<el-input clearable v-model={form.type} />
),
},
]
...
</script>
改成上面的形式后,一處改動,3處對應生效,開發的重點也轉移到form表單中對columns的配置上,columns配置則建立在對jsx的運用,當然舉的這個例子只是一個簡單案例,復雜的例子在專案中,下面我們正式開啟jsx之旅吧
??JSX是什么
JSX(JavaScript 和 XML),是一個 HTML-in-JavaScript 的語法擴展,首先在 React 中被進入,它允許我們在JavaScript中撰寫類似HTML的代碼,并將其轉換為JavaScript物件,Vue3中引入了對JSX的支持,使得我們可以更加靈活地撰寫組件模板,不再局限于Vue2.x中的模板語法,JSX 可以很好地描述 UI 應該呈現出它應有互動的本質形式,
形如:
const element = <div id="root">Hello World</div>
或
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>;
}
return <h1>Hello, Stranger.</h1>;
}
??JSX 和 template 的區別
--語法上有很大區別:
?JSX 本質就是 js 代碼,可以使用 js 的任何能力 ?template 只能嵌入簡單的 js 運算式,其他需要指令,如 v-if ?插值不同,jsx 使用單括號 { },template 使用雙括號 {{ }} ?JSX 已經成為 ES 規范,template 還是 Vue 自家規范 ?--本質是相同的: ?都會被編譯為 js 代碼(render 函式) ???基本用法
安裝使用
vite 官方提供了官方的插件來支持在 vue3 中使用 jsx
yarn add @vitejs/plugin-vue-jsx
安裝完之后在 vite.config.js 檔案中的 plugins 欄位中添加 jsx 支持:
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
plugins: [
vueJsx(),
]
})
插值運算式
// template
<template>
<span>{{ a + b }}</span>
</template>
// jsx
render: () => {
return (
<span>{ a + b }</span>
)
}
條件渲染
?jsx只保留了 v-show指令,沒有 v-if指令 ?使用 if/else和三目運算式來實作判斷// template v-if v-show
<template>
<div v-if="show">是</div>
<div v-else>否</div>
<div v-show="show">我是v-show</div>
</template>
// jsx
render: () => {
const show = ref(true);
return (
<div>
<div>{show.value ? <div>是</div> : <div>否</div>}</div>
<div v-show={!show.value}>我是v-show</div>
</div>
)
}
// jsx if-else
render: () => {
const isShow = false
const element = () => {
if (isShow) {
return <div>是</div>
} else {
return <div>否</div>
}
}
return (
<div>
{
element()
}
<div v-show={!show.value}>我是v-show</div>
</div>
)
}
樣式系結
?class類名系結有兩種方式,使用模板字串或者使用陣列, ?style系結需要使用 雙大括號// template
<template>
<div :></div>
<div :></div>
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
</template>
// jsx
// jsx 模板字串
<div className={`static ${ isActive ? 'active' : '' }`}>header</div>
//jsx 陣列
<div class={ [ 'static', isActive && 'active' ] } >header</div>
// jsx 樣式系結需要使用雙大括號,
render: () => {
const width = '100px'
return (
<button style={{ width, fontSize: '16px' }}></button>
)
}
串列回圈
// template v-for
<template>
<ul>
<li v-for="item in list" :key="item">{{ item }}</li>
</ul>
</template>
// jsx 陣列 .map 函式
render: () => {
return <>
<ul>
{ list.map(item => <li>{item}</li>)}
</ul>
</>
}
事件處理
?jsx系結事件使用的是 單大括號 {},事件系結不是以 @為前綴了,而是改成了 on,例如:click 事件是 onClick ?如果需要使用事件修飾符,就需要借助withModifiers方法啦,withModifiers 方法接收兩個引數,第一個引數是系結的事件,第二個引數是需要使用的事件修飾符,或者在有些修飾符不生效的情況下采用鏈式駝峰的形式進行設定,如@click.once變為 onClickOnce// template
<template>
<button @click="clickButton('button1')"> 點擊</button>
<!-- 單擊事件將停止傳遞 -->
<a @click.stop="doThis"></a>
<!-- 點擊事件最多被觸發一次 -->
<a @click.once="doThis"></a>
</template>
// jsx 陣列 .map 函式
render: () => {
const clickButton = val => {
console.log(val)
}
return (
<div>
<button onClick={() =>clickButton('button1')}>點擊</button>
<a onClick={withModifiers(() => doThis(), ['stop'])}></a>
<a onClickOnce={doThis}></a>
</div>
)
}
標簽屬性系結
// template
<template>
<div v-bind="properties"></div>
</template>
//jsx
render: () => {
return (
<div {...properties}></div>
)
}
V-model
// 一般用法
<input v-model="value" /> // template
<input v-model={value} /> // jsx
// 指定系結值寫法
<input v-model:modelValue="https://www.cnblogs.com/mrwh/archive/2023/06/09/value" /> // template
<input v-model={[value,'modelValue']} /> // jsx
// 修飾符寫法
<input v-model:modelValue.trim="value" /> // template
<input v-model={[value,'modelValue',['trim']]} /> // jsx
插槽
定義插槽
jsx/tsx中是沒有 slot 標簽的,定義插槽需要使用{}或者使用renderSlot函式
setup 函式默認接收兩個引數 1. props 2. ctx 背景關系 其中包含 slots、attrs、emit 等
// template
<template>
<div>
<slot></slot>
<slot name="title"></slot>
</div>
</template>
// jsx
import { renderSlot } from "vue"
export default defineComponent({
// 從ctx中解構出來 slots
setup(props, { slots }) {
return () => (
<div>
{ renderSlot(slots, 'default') } // 等價于 { slots.default?.() }
{ slots.title?.() }
</div>
)
}
})
使用插槽
通過 v-slots 來使用插槽
// template
<template>
<yun-table
>
<template #action="{ row }">
<el-button type="action" @click="handleDel(row)">
洗掉
</el-button>
</template>
</yun-table>
</template>
// jsx
render: (form) => {
const slots = {
action: ({ row }) => <el-button type="action" onClick={() => handleDel(row)}>
洗掉
</el-button>,
};
return (
<yun-table
v-slots={slots}
>
</yun-table>
);
},
jsx基礎模板
import { defineComponent, onMounted, ref } from 'vue';
export default defineComponent({
// props: ['xx'],
setup(props,{ emit }) {
onMounted(() => {
// ...
})
return () => (
<div></div>
)
}
})
組件運用
在 .vue 檔案中使用 jsx組件
// 父
<template>
<div >
<JSXDemo />
</div>
</template>
<script setup lang="jsx">
import JSXDemo from '@/components/JSXDemo.vue'
</script>
// JSXDemo.vue
<script>
import { ref } from 'vue'
export default {
setup () {
const countRef = ref(200)
const render = () => {
return <p>DEMO1--{countRef.value}</p>
}
return render
}
}
</script>
在.jsx檔案格式中父子組件屬性傳遞
// 父組件
import { defineComponent, ref } from 'vue'
import JSXChild from './JSXChild.jsx'
export default defineComponent(() => { // 傳入 setup 函式
const countRef = ref(360)
const render = () => {
return <>
<p>數量--{countRef.value}</p>
<JSXChild a={countRef.value + 100}></JSXChild> // vue3的template會自動決議ref的.value,在jsx中ref的.value是不會被自動決議的
</>
}
return render
})
// 子組件 JSXChild.jsx
import { defineComponent } from 'vue'
export default defineComponent({ // 傳入組件配置
props: ['a'],
setup (props) {
const render = () => {
return <>
<p>child {props.a}</p>
</>
}
return render
}
})
??經驗總結
我們該怎么選擇 JSX 和 template ?
template優勢:template 的語法是固定的,有 v-if、v-for 等等語法,按照這種固定格式的語法書寫的代碼, Vue3 在編譯層面就可以很方便地去做靜態標記的優化,減少Diff程序,比如靜態提升,型別標記,樹結構打平等來提高虛擬 DOM 運行時性能,這也是 Vue 3 的虛擬 DOM 能夠比 Vue 2 快的一個重要原因,
JSX優勢:template 因為語法限制原因,不能夠像 JSX 那樣可以支持更動態的需求,每一個 .vue 檔案結尾的檔案都是一個組件,而且只能 export default 出一個組件,JSX 則不同 ,是可以在一個檔案內回傳多個組件的,比如我們寫一個頁面的時候其實可能會需要把一些小的節點片段拆分到小組件里面進行復用,這些小組件在jsx里面,寫個簡單的函陣列件就能搞定,例如:
那如何選擇呢?
在實作業務需求的時候,優先使用 template,盡可能地利用 Vue 本身的性能優化,如串列、彈窗和抽屜,而對于動態性要求較高的組件可以使用 JSX 來實作,比如動態表單,封裝動態遞回組件,而對于公司專案來說,大多數業務需求都是表單類的,那就趕緊用上jsx吧,用久了你就會發現,哎,真香,
如果你覺得不錯的話,右下角,隨手點個推薦,鼓勵支持hhh^_^轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/554820.html
標籤:其他
下一篇:返回列表
