14

使用 JSX/TSX 开发 Vue3 组件

 4 years ago
source link: https://zhuanlan.zhihu.com/p/153387704
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

使用 JSX/TSX 开发 Vue3 组件

写完下面这篇文章之后

就想着要不就着手开发一个完全为 Vue3 设计的 JSX 插件吧,于是就有了:

https://github.com/HcySunYang/vue-next-jsx​github.com

这个插件已经是可使用的状态了,我正在使用该插件在另外一个项目中,说说这个插件的设计原则和基本用法

直接使用 TSX

Vue3 的确可以直接使用 tsx 开发,唯一需要处理的就是 children,而且处理起来还是比较不爽的,例如你不能这么写:

<div>
    <p>1</p>
    <p>1</p>
</div> 
<div>
    {
      [
        <p>1</p>,
        <p>1</p>
      ]
    }
</div> 

这还是挺恶心的,不过也不是没有办法,可以封装一个工具函数:

function JSXFactory(tag: any, props: any, ...children: any) {
  if (
    typeof tag !== 'string' &&
    typeof tag !== 'symbol' &&
    !tag.__isTeleport &&
    !tag.__isKeepAlive
  ) {
    // Component
    children = children[0]
  }
  return createVNode(tag, props, children)
}

然后在 tsconfig.json 中配置 jsxFactory 为我们封装的这个函数就可以了。但是这个函数限制了我们在为组件传递 slots 时只能:

const App = {
    setup() {
        const slots = {
            foo: () => <p>foo</p>,
            bar: () => <p>bar</p>,
        }
        return () => <Hello>{ slots }</Hello>
    }
}

但是这也没啥问题嘛。

有了 JSXFactory 工具函数之后其实我们可以很开心的用 tsx 写了,那为啥还要 jsx 插件呢?这是因为使用了 jsx 语法后我们丢失了很多模板中提供的便利能力,例如事件修饰符、v-model 之类的, 因此 jsx 插件还是有必要的,但是不是必须的。

下面说说 https://github.com/HcySunYang/vue-next-jsx 的设计原则和功能。

既支持 JSX 又支持 TSX

tsx 中不支持 amespaced attribute,详见:https://github.com/microsoft/TypeScript/issues/7411 ,但 babel 中是支持,这就意味着你在 jsx 中可以这么写:

<p v-on:click={ handler } ></p>

但是 tsx 中则不行,为了语法统一,我决定不允许在属性名中使用 :,而是使用 - 替代 :

<p v-on-click={ handler } ></p>

统一语法的好处是:降低不同项目差异带来的额外负担/困扰(有的人使用 : 有的人使用 -)。

无论是 jsx 还是 tsx,修饰符都不允许使用 .,而是使用 _ 代替:

 <p v-on-click_stop={ handler } ></p>

对于事件,vue-next-jsx 支持全部的模板中可用语法,例如:

<div v-on-click_middle={ handler }></div>
<div v-on-click_stop={ handler }></div>
<div v-on-click_right={ handler }></div>
<div v-on-keyup_esc={ handler }></div>

<div v-on={ obj }></div>

v-model

Vue2 中的 .syncv-model:foo 代替了,例如:

<!-- Vue2 -->
<Comp :foo.sync="val" />
<!-- Vue3 -->
<Comp v-model:foo="val" />

在 jsx 中,把 : 换成 -

<Comp v-model-foo={ refVal.value }/> 

也可以带修饰符,用 _ 分割:

<Comp v-model-foo_a_b={ refVal.value }/> 

v-bind

j/tsx 中不需要 v-bind,直接使用 jsxExpressionContainerjsxSpreadAttribute 代替:

<Comp foo={ refVal.value } { ...props } bar="bar" />

slots

我不准备支持 v-slot ,这是因为它会导致类型丢失,例如:

<Comp>
    <template v-slot-foo="props">
    </template>
</Comp> 

这里的 props 没有类型,它就是一个字符串,而且我始终推荐像如下这样为组件传递插槽:

<Comp>{ mySlots }</Comp> 

至于插槽 mySlots 我们可以自行构建它:

const mySlots = {
    default: () => [<p>默认插槽</p>]
} 

KeepAlive 和 Teleport

这两个组件比较特殊,他们的子节点不会作为 slots 存在,而是当做正常的 children,不过你不用担心,vue-next-jsx 帮你处理了。

Optimization mode

优化模式,正如 https://zhuanlan.zhihu.com/p/150732926 这篇文章中讲述的,我们可以在 jsx 插件中利用这些信息,尽可能的提升性能。

babel.config.json 中打开优化模式:

{
  "presets": [
    "@babel/env"
  ],
  "plugins": [
    ["@hcysunyang/vue-next-jsx", {
      // 开启优化模式
      "optimizate": true
    }]
  ]
}

实际上,你可以查看 vue-next-jsx 的测试用例生成的 ,并与 Vue3 Compiler 对比,他们的行为是一致的,包括及其复杂的情况。

指定 source

source 指的是 ImportDeclaration 语句的 source,例如:

import { createApp } from 'vue'

这里的 source 就是 vue ,但是你可能安装的不是 vue 而是 @vue/runtime-dom ,这时你需要指定 source

{
  "presets": [
    "@babel/env"
  ],
  "plugins": [
    ["@hcysunyang/vue-next-jsx", {
      // 指定 source
      "source": "@vue/runtime-dom"
    }]
  ]
} 

v-html / v-text

jsx 中支持这两个指令意义不大,全当顺手,它们的使用与在模板中相同:

<p v-html={ refHtml.value }></p>
<p v-text={ refText.value }></p>

Recommend

  • 22
    • zhuanlan.zhihu.com 4 years ago
    • Cache

    使用 tsx + vue3

    使用 tsx + vue3陶文problem solvervue3 的组件能不能在 tsx 中带类型提示的使用,就...

  • 12
    • www.trustnodes.com 4 years ago
    • Cache

    New Bitcoin Fund Starts Trading on TSX

    New Bitcoin Fund Starts Trading on TSX – TrustnodesThe Toronto Stock Exchange (TMX/TSX) has listed the CI Galaxy Bitcoin Fund by CI Global Asset Management and Galaxy Digital Capital Management. The fund has just began trading yeste...

  • 12

    在 vue 中使用 jsx 与 class component 的各种姿势发表于2019-09-17更新于2020-03-12字数统计992阅读时长8分 在之前我们分享过一次 ...

  • 9
    • innei.ren 4 years ago
    • Cache

    ⚠️ Vue 3 TSX

    ⚠️ Vue 3 TSX本篇基于 Vue 3.0.7, vite 2.1.2 编写,由于 Vue 与 vite 改动较大,以最新版本为准,本文仅供参考。写本篇文章主要是为了记录在正式使用 Vue 3 + vite 2 投入开发中遇到的一些问题,不适合没有任何 Vue 开...

  • 6

  • 2

    V2EX  ›  程序员 求一个针对 React+TSX 的 ESLint+Prettier 的 Boilerplate   xlsepip...

  • 6
    • gist.github.com 3 years ago
    • Cache

    tile_source.tsx

    tile_source.tsx · GitHub Instantly share code, notes, and snippets.

  • 5

    组件不能作为JSX组件使用,出现该错误有多个原因:null 返回单个JSX元素下面是一个错误如何发生的示例。// App.tsx // :no_entry:️ 'App' cannot be used as a JSX component. // Its return type 'Element...

  • 5
    • www.v2ex.com 3 years ago
    • Cache

    vue3 jsx 和 template 哪个性能好

    V2EX  ›  Vue.js vue3 jsx 和 template 哪个性能好  

  • 13

    大家好,我是蔓越莓曲奇,今天我想给大家分享的是我最近开源的中后台管理系统模板,Vue TSX Admin 。 正如项目名称所表述的,该项目是完全通过 Vue3 + TSX 开发的。 为什么使用 JSX 写中后台管理 在讲为什么使用 JSX 前,我想先说些在中后台业务开发...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK