JSX 是什么?
jsx 是javascript的语法拓展,最初由React框架发明了这种书写方式,在javascript 代码中灵活的书写xml语法,即兼容了JavaScript的语法的灵活性,同时也可以更好的书写我们的模版xml代码。
为什么要在Vue中用JSX语法编写代码?
由于当前的Vue2.x 已经长期性的停止维护了,在公司的许多的项目当中还是可以看到Vue2的Options 的组织的项目,在后续的项目升级改造当中,想要直接使用React的代码从而节省我们实际开发的时间,所以就想到了使用JSX的语法来直接改造Vue2的相关项目。
主要有以下的几种方式实现改造我们的Vue2项目的代码
1 使用vue2 Options API 加上render function的方式。
在Vue2.x 的源码当中可以看到其实是支持render写法的
.../types/options.d.ts 类型文件中:
js
data?: Data;
props?: PropsDef;
propsData?: object;
computed?: Accessors<Computed>;
methods?: Methods;
watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any> | string>;
el?: Element | string;
// 这里可以看到其实是支持我们的 自定义template的模版的写法的
template?: string;
// hack is for functional component type inference, should not be used in user code
// 这里可以看到可以用render 方法实现我们的模版的功能
render?(createElement: CreateElement, hack: RenderContext<Props>): VNode;
renderError?(createElement: CreateElement, err: Error): VNode;
staticRenderFns?: ((createElement: CreateElement) => VNode)[];
beforeCreate?(this: V): void;
created?(): void;
beforeDestroy?(): void;
destroyed?(): void;
beforeMount?(): void;
mounted?(): void;
beforeUpdate?(): void;
updated?(): void;
activated?(): void;
deactivated?(): void;
errorCaptured?(err: Error, vm: Vue, info: string): boolean | void;
serverPrefetch?(this: V): Promise<void>;
directives?: { [key: string]: DirectiveFunction | DirectiveOptions };
components?: { [key: string]: Component<any, any, any, any> | AsyncComponent<any, any, any, any> };
transitions?: { [key: string]: object };
filters?: { [key: string]: Function };
provide?: object | (() => object);
inject?: InjectOptions;
model?: {
prop?: string;
event?: string;
};
parent?: Vue;
mixins?: (ComponentOptions<Vue> | typeof Vue)[];
name?: string;
// TODO: support properly inferred 'extends'
extends?: ComponentOptions<Vue> | typeof Vue;
delimiters?: [string, string];
comments?: boolean;
inheritAttrs?: boolean;
eg:render 的默认写法 注意: 需要删除我们的单文件组件中的template块 ,默认应该是template的优先级要高于render方式定义的JSX。
js
render(h) {
return h('span', 'hello world')
}
或者直接return一个VNode
js
render(h) {
// return h('span', 'hello world')
return (
<div>
这是render VNode
</div>
)
}
class 与 style 的样式绑定,当我们使用h函数 来实现我们的模版时,通过TS的类型定义可以知道主要是VNodeData的这个类型。
js
export interface VNodeData {
key?: string | number;
slot?: string;
scopedSlots?: { [key: string]: ScopedSlot | undefined };
ref?: string;
refInFor?: boolean;
tag?: string;
staticClass?: string;
class?: any;
staticStyle?: { [key: string]: any };
style?: string | object[] | object;
props?: { [key: string]: any };
attrs?: { [key: string]: any };
domProps?: { [key: string]: any };
hook?: { [key: string]: Function };
on?: { [key: string]: Function | Function[] };
nativeOn?: { [key: string]: Function | Function[] };
transition?: object;
show?: boolean;
inlineTemplate?: {
render: Function;
staticRenderFns: Function[];
};
directives?: VNodeDirective[];
keepAlive?: boolean;
}
class 的绑定一般推荐使用 string 或者 string[] 类型, style 行内样式一般推荐使用 object 类型。 eg:
js
let classList = ['aaa','ccc']
return h('span', {
class: ['xxx', classList],
{
fontSize:'20px',
height: '10px',
}
});
当我们直接使用返回VNode 的方式时,class 绑定使用string的方式, style绑定和React JSX 的使用方式一致。 eg:
js
return (
<div class={'aaa'} style={{ lineHeight: '10px' }}>
xxxxxx
</div>
)
在Vue2.7版本之下,如果想要体验Vue3的CompositionAPI 的组合式API的函数功能,我们可以安装 @vue/composition-api
包,然后全局使用插件。
js
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
之后便可以全局使用API
js
// 使用 API
import { ref, reactive } from '@vue/composition-api'
包括支持 TSX | JSX的详细的定义模式可参考:
2 升级Vue2.7 的同时,使用Composition API 和 setup function来实现改造我们的Vue项目。
首先,更新我们的项目Vue版本为Vue2.7.x ,Vue2.7.x 以上版本内置了组合式API 的功能,因此我们可以直接使用 import { defineComponent } from 'vue'
导入我们的组件定义方式:
js
// demo.tsx
import { defineComponent } from 'vue'
export default defineComponent({
// type inference enabled
})
当我们升级到Vue2.7.x 版本的时候 可以使用setup 函数
来实现我们组件的基本功能,同时也是支持TypeScript的类型检查的功能的。 组件组织方式:
js
setup?: (
this: void,
props: Props,
ctx: SetupContext
) => Promise<RawBindings> | RawBindings | ((h: CreateElement) => VNode) | void
可以看到我们也是可以通过template
模版和setup 函数
返回VNode来实现我们的组件的。
1 xxx.vue 方式的单文件组件:
js
<template>
xxxxx
</template>
<script>
import { defineComponent,ref,reactive } from 'vue'
export default defineComponent({
// type inference enabled
})
</script>
<style lang='scss' scoped>
xxx
</style>
2 jsx | tsx 方式的组件组织形式: 返回一个VNode
js
// demo.(j|t)sx
import style from './HelloWorld.module.css';
import { defineComponent, PropType } from 'vue';
export default defineComponent({
name: 'HelloWorld',
props: {
msg: {
type: String,
required: true,
},
eventClick: {
type: (null as unknown) as PropType<(event: MouseEvent) => void>,
}
},
setup(props) {
return (h) => (
<div>
<h1 onClick={props.eventClick}>{props.msg}</h1>
<h3 class={style.listTitle}>Installed CLI Plugins</h3>
</div>
);
},
});
根据类型文件可知,我们在setup函数中返回的Vnode 也可以使用h函数
来定义即:
js
setup(props){
return (h)=>{
return h('span', { class: ['xxx', classList], { fontSize:'20px', height: '10px', } });
}
}
当我们升级到Vue2.7之后,便可以去掉Options 的方式的组织代码的形式,同时直接使用 import { ref,reactive,defineComponent } from 'vue'
等方式引入我们的ComponsitionAPI,例如ref,reactive
等api。onMounted,onUpdated
等生命周期hooks。 能够有效的梳理我们的代码和组织逻辑。复用组件以及自定义和复用hooks
。安装 @vueuse/core
包等。
支持SSR
当我们升级到 Vue2.7.x 上时,也是可以使用ComponsitionAPI 来构建一个SSR代码的。
js
import { onServerPrefetch } from 'vue'
export default {
setup(props, { ssrContext }) {
const result = ref()
onServerPrefetch(async () => {
result.value = await callApi(ssrContext.someId)
})
return {
result,
}
}
}
总结
本文详细的介绍了我们如何使用Vue2.x的项目,来改造升级成JSX|TSX代码格式的组件格式。方便我们迁移React jsx| tsx 的相关代码。同时也对一些组件格式和Vue组件编写的方式做了一定的探讨。 相关链接
Vue2.x升级: v2.cn.vuejs.org/v2/guide/mi...
VueUse: www.vueusejs.com/guide/