使用Vue2.x 书写JSX 的几种方式

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的详细的定义模式可参考:

Vue < 2.7.x 使用组合式API 指南

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/

Vue3: cn.vuejs.org/guide/reusa...

相关推荐
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
落魄小二2 小时前
el-table 表格索引不展示问题
javascript·vue.js·elementui
neter.asia2 小时前
vue中如何关闭eslint检测?
前端·javascript·vue.js
十一吖i2 小时前
前端将后端返回的文件下载到本地
vue.js·elementplus
光影少年2 小时前
vue2与vue3的全局通信插件,如何实现自定义的插件
前端·javascript·vue.js
熊的猫3 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
mosen8684 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
别拿曾经看以后~5 小时前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
Gavin_9156 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
Devil枫11 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试