框架-Vue Class Component tsx 支持(vue-tsx-support V2.2.0)


總結

  • 這個庫幫助我們在 tsx 中實現 props 等的提醒
  • 在 TS 中組件能夠傳遞 props 建議都要定義好類型

class component

import * as tsx from "vue-tsx-support";
 
 
interface MyComponentProps {
    text: string;
    important?: boolean;
}
 
interface Events {
    onOk: void;
    onError: { code: number, detail: string }; // 參數只有一個,類型為接口 { code: number, detail: string }
}
 
interface ScopedSlots {
    default: { text: string }; // 參數只有一個,類型為接口 { text: string }
}
 
@component // 不是該庫提供
class MyComponent extends tsx.Component<MyComponentProps, Events, ScopedSlots> {
    @Props({required:true}) text!:string; // 不是該庫提供
    @Props() important!:boolean; // 不是該庫提供
    /* snip */
}

modifiers 事件修飾符

  • esc, tab, enter, space, up, down, del, left, right 鍵盤事件
    • del 會被 DELETE 或 BACKSPACE 觸發
    • m.enter.esc 的方式組合修飾符,並不能夠成功
  • left, right, middle 鼠標事件
  • ctrl, shift, alt, meta 系統修飾符鍵
  • noctrl, noshift, noalt, nometa 僅當未按下該修飾符時才會被觸發
  • self
  • prevent(不觸發原生事件動作), stop
  • keys(...args) 多個按鍵之一觸發
  • exact(...args) 系統修飾符精確匹配時觸發
import { modifiers as m } from "vue-tsx-support";

<div onKeydown={m.enter(this.onEnter)} />;
<div onKeydown={m.enter.prevent(this.onEnter)} />;
<div onKeydown={m.esc.prevent} />;
<div onKeydown={m.keys("enter", "esc")(this.onEnterOrEsc)} />; // <div @keydown.enter.esc="onEnterOrEsc" /> 按下 enter 或 esc 時觸發
<div onKeydown={m.keys(65).exact("ctrl", "alt")(this.onCtrlAltA)} />; // 65 代表 a 鍵
<div onClick={m.exact("ctrl", "shift")(handler)} />;

安裝

  • 在 tsconfig.json 配置,啟用 tsx 的類型提醒
npm install vue-tsx-support -S

{
  "compilerOptions": {
    "...snip...": "...snip..."
  },
  "include": [
    "node_modules/vue-tsx-support/enable-check.d.ts",
    "...snip..."
  ]
}
  • 要啟用某個選項將它們導入即可,例如:allow-unknown-propsimport "vue-tsx-support/options/allow-unknown-props";
  • allow-element-unknown-attrs 在原生元素上允許非 attrs 屬性
  • allow-unknown-props 在組件上允許非 props 屬性
  • enable-html-attrs 在組件上允許非 props 但是是 attrs 的屬性,並且遵循 attrs 的類型校驗
  • enable-nativeon 在組件上允許使用 nativeOn 的方式綁定原生事件
  • enable-vue-router 添加 router-link 和 router-view 定義

不常用——————————————————————————————————

ofType 給現有組件添加類型提醒

import ThirdPartyComponent from "third-party-library";
import * as tsx from "vue-tsx-support";
 
interface MyComponentProps { /* ... */ }
const MyComponent = tsx.ofType<MyComponentProps>().convert(ThirdPartyComponent);
// const MyComponent = tsx.ofType<MyComponentProps, Events, ScopedSlots>().convert(ThirdPartyComponent);

Vue.component 或 Vue.extend 定義組件

props

  • 不支持 props 通過數組定義,例如:props: ["foo", "bar"]
  • 所有 props 都會被 ts 視為可選,即使設置了 required:true。有 3 種辦法解決
    • 使用 as 的方式 text: { type: String, required: true as true }
    • 使用 vue-strict-prop 庫,import p from "vue-strict-prop";text: p(String).required
    • 讓必傳 props 作為 tsx.componentFactory.create 的第二參數 tsx.componentFactory.create({...}, ["text"])

componentFactoryOf 使 event 和 scoped slots 具有 ts 提醒

interface Events {
    onOk: () => void; // 以 on 開頭
    onError: { code: number, detail: string }; // 參數只有一個時的簡易寫法,onError 的參數的類型為接口 { code: number, detail: string }
}
interface ScopedSlots {
    default: { text: string }; // default 作用域插槽將接收到一個參數類型為接口 { text: string }
    optional?: string; // 不僅插槽的參數會有類型提醒,插槽自身也會有必填提醒
}

const MyComponent = tsx.componentFactoryOf<Events, ScopedSlots>().create({
    ...
})

componentFactory 構建 vue 的子類

  • tsx.componenttsx.componentFactory.create 的簡寫
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className(): string {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    render(): VNode {
        return <span class={this.className} onClick={this.onClick}>{this.text}</span>;
    }
});

extendFrom 繼承

import * as tsx from "vue-tsx-support";
// 注釋:const Base = Vue.extend({/* snip */})
// This is equivalent to `const MyComponent = Base.extend({ /* snip */ });`
const MyComponent = tsx.extendFrom(Base).create({
    /* snip */
});

mixin 混入

import * as tsx from "vue-tsx-support";
const StorageMixin = {
    ... // vue options
}
const MyComponent = tsx.componentFactory.mixin(StorageMixin).create({
    ... // vue options
})

const tsx.componentFactory.mixin(FirstMixin).mixin(SecondMixin).create({
    /* snip */ 
})

————————————————————————————————————————————————————————————————

https://www.npmjs.com/package/vue-tsx-support

  • V2.2.0

Install and enable

npm install vue-tsx-support -S
  • And refer vue-tsx-support/enable-check.d.ts from somewhere to enable compiler check. 類型說明文檔在 vue-tsx-support/enable-check.d.ts 可以通過 import 引入或 tsconfig.json 配置
  • 注釋:啟用后在 @vue/cli 生成的項目中,會和 shims-tsx.d.ts 的 IntrinsicElements 出現重復定義
import "vue-tsx-support/enable-check"
{
  "compilerOptions": {
    "...snip...": "...snip..."
  },
  "include": [
    "node_modules/vue-tsx-support/enable-check.d.ts",
    "...snip..."
  ]
}

Using intrinsic elements 使用原生元素

  • 注釋:不需要這個庫也能夠在 tsx 中為原生元素提供提醒

Using custom component 使用自定義組件

  • By default, vue-tsx-support does not allow unknown props. vue-tsx-support 默認時不允許在 tsx 中向元素傳入未定義的 props
  • You must add types to the component by apis memtions below, or enable allow-unknown-props option.可以通過設置 allow-unknown-props 不出現這個報錯(不建議)

available APIs to add type information 用於添加 TSX 類型的 API

componentFactory

  • componentFactory.create can infer types of props from component options same as Vue.extend. 能夠自動推斷類型,例如下例中的 props
  • shorthand props definition(like props: ["foo", "bar"]) is currently not supported. 不支持 props 通過數組定義,例如:props: ["foo", "bar"]
  • all props are regarded as optional even if required: true specified. 但是所有 props 都會被 ts 視為可選,即使設置了 required:true。有 7 種辦法解決?
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    computed: {
        className(): string {
            return this.important ? "label-important" : "label-normal";
        }
    },
    methods: {
        onClick(event) { this.$emit("ok", event); }
    },
    render(): VNode {
        return <span class={this.className} onClick={this.onClick}>{this.text}</span>;
    }
});
  • 1.Instead of required: true, specify required: true as true. 使用required: true as true代替required: true
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true as true },
        important: Boolean,
    },
    /* snip */
});
import * as tsx from "vue-tsx-support";
import p from "vue-strict-prop";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: p(String).required,
        important: Boolean,
    },
    /* snip */
});
  • 3.Specify required prop names as second argument 讓必傳 props 作為 tsx.componentFactory.create 的第二參數
import * as tsx from "vue-tsx-support";
const MyComponent = tsx.componentFactory.create({
    props: {
        text: { type: String, required: true },
        important: Boolean,
    },
    /* snip */
}, ["text"]);

component

  • Shorthand of componentFactory.create tsx.componenttsx.componentFactory.create的簡寫

extendFrom

  • When you want to extend your component from other than Vue, you can use extendFrom 從 Vue 子類創建構造函數
import * as tsx from "vue-tsx-support";
// 注釋:const Base = Vue.extend({/* snip */})
// This is equivalent to `const MyComponent = Base.extend({ /* snip */ });`
const MyComponent = tsx.extendFrom(Base).create({
    /* snip */
});

mixin

import * as tsx from "vue-tsx-support";
 
const StorageMixin = {
    methods: {
        getItem(string name): string {
            return localStorage.getItem(name);
        },
        setItem(string name, string value): void {
            localStorage.setItem(name, value);
        }
    }
}
 
const MyComponent = tsx.componentFactory.mixin(StorageMixin).create(
    {
        props: {
            name: String
        },
        data() {
            return { value: "" }
        },
        mounted() {
            this.value = this.getItem(this.name);
        },
        render(): VNode {
            return (
                <button onClick={() => this.setItem(this.name, this.value)}>
                    SAVE
                </button>
            );
        }
    }
);
 
// You can add 2 or more mixins by method chain
const tsx.componentFactory.mixin(FirstMixin).mixin(SecondMixin).create({
    /* snip */ 
})

componentFactoryOf

  • Return componentFactory with additional types (events and scoped slots) 使 event 和 scoped slots 具有 ts 提醒
import * as tsx from "vue-tsx-support";
 
interface Events {
    // all memebers must be prefixed by 'on' 必須以 on 開頭,這是 jsx 的要求
    onOk: () => void;
    // If event handler has only one parameter, you can specify parameter type as a shorthand.
    // For example, this is equivalent to `onError: (arg: { code: number, detail: string }) => void`
    // 注釋:如果該 event 只有一個參數,可以使用簡易寫法,這里的 onError 的參數類型為 { code: number, detail: string } 這樣的一個接口
    onError: { code: number, detail: string };
}
 
const MyComponent = tsx.componentFactoryOf<Events>().create({
    render(): VNode {
        return (
            <div>
              <button onClick={() => this.$emit("ok")}>OK</button>
              <button onClick={() => this.$emit("error", { code: 9, detail: "unknown" })}>Raise Error</button>
            </div>
        );
    }
});

<MyComponent onOk={() => console.log("ok")} />;
<MyComponent onError={p => console.log("ng", p.code, p.detail)} />;
import * as tsx from "vue-tsx-support";
 
interface ScopedSlots {
    default: { text: string };
    optional?: string;
}
 
const MyComponent = tsx.componentFactoryOf<{}, ScopedSlots>().create({
    props: {
        text: String
    },
    render(): VNode {
        const { default, optional } = this.$scopedSlots;
        return <ul>
                 <li>{ default({ text: this.text || "default text" }) }</li>
                 <li>{ optional ? optional(this.text) : this.text }<li>
               </ul>;
    }
});
 
<MyComponent scopedSlots={{
        default: p => <span>p.text</span>
    }}
/>;
 
// NG: 'default' is missing in scopedSlots 不僅插槽的參數會有類型提醒,插槽自身也會有必填提醒
<MyComponent scopedSlots={{
        optional: p => <span>p</span>
    }}
/>;

Component

import component from "vue-class-component";
import * as tsx from "vue-tsx-support";
 
interface MyComponentProps {
    text: string;
    important?: boolean;
}
 
@component({
    // 這是舊的寫法了,推薦使用 @Prop
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps> {
    /* snip */
}
  • If you want, you can specify event types and scoped slot types as 2nd and 3rd type parameter 參數分別是 props、events、scoped slot 的類型
import component from "vue-class-component";
import * as tsx from "vue-tsx-support";
 
interface MyComponentProps {
    text: string;
    important?: boolean;
}
 
interface Events {
    onOk: void;
    onError: { code: number, detail: string };
}
 
interface ScopedSlots {
    default: { text: string };
}
 
 
@component({
    props: {
        text: { type: String, required: true },
        important: Boolean
    },
    /* snip */
})
class MyComponent extends tsx.Component<MyComponentProps, Events, ScopedSlots> {
    /* snip */
}

ofType

  • If you can't modify existing component definition, wrap it by ofType and convert 給現有組件添加類型提醒
import ThirdPartyComponent from "third-party-library";
import * as tsx from "vue-tsx-support";
 
interface MyComponentProps { /* ... */ }
 
const MyComponent = tsx.ofType<MyComponentProps>().convert(ThirdPartyComponent);
// const MyComponent = tsx.ofType<MyComponentProps, Events, ScopedSlots>().convert(ThirdPartyComponent);

Other attributes 其他屬性

Native event listeners and dom properties 原生 event 和屬性

  • To avoid compilation error, you must use kebab-case attribute name. 在組件上綁定原生屬性和方法不支持 JSX 的寫法,會出現編譯錯誤。例如nativeOnClick={} domPropInnerHTML={}會報錯
  • 注釋:以下兩種方法都沒有類型提醒
<Component nativeOn-click={ ... } />
<Component domProp-innerHTML={ ... } />
  • Or use JSX-spread style. 或者 JSX-spread 的方式
<Component { ...{ nativeOn: { click: ... } } } />
<Component { ...{ domProps: { innerHTML: ... } } } />

HTML attributes attached to the root element 附加到組件上的 HTML 屬性

<SomeInputComponent { ...{ attrs: { min: 0, max: 100 } } } />

Options

  • To enable each options, import them somewhere 要啟用某個選項將它們導入即可,例如:allow-unknown-props
import "vue-tsx-support/options/allow-unknown-props";

allow-element-unknown-attrs

  • Make enabled to specify unknown attributes to intrinsic elements 在原生元素上允許非 attrs 屬性
<div foo="foo" />;

allow-unknown-props

  • Make enabled to specify unknown props to Vue component. 在組件上允許非 props 屬性

enable-html-attrs

  • Make enabled to specify HTML attributes to Vue component. 在組件上允許非 props 但是是 attrs 的屬性,並且遵循 attrs 的類型校驗
<MyComponent foo="foo" min={ 0 } max={ 100 } />;

enable-nativeon

  • Make enabled to specify native event listeners to Vue component. 在組件上允許使用 nativeOn 的方式綁定原生事件
<MyComponent foo="foo" nativeOnClick={ e => ... } />; // and `e` is infered as MouseEvent e 將被推斷為 MouseEvent 事件對象

enable-vue-router

  • Add definitions of router-link and router-view 添加 router-link 和 router-view 定義

Utility

modifiers

  • Event handler wrappers which work like some event modifiers available in template 事件處理包裝函數,等同於在模板中為事件添加修飾符。例如 .enter 等
import { modifiers as m } from "vue-tsx-support";

<div onKeydown={m.enter(this.onEnter)} />;
<div onKeydown={m.enter.prevent(this.onEnter)} />;
<div onKeydown={m.esc.prevent} />;
<div onKeydown={m.keys("enter", "esc")(this.onEnterOrEsc)} />; // <div @keydown.enter.esc="onEnterOrEsc" /> 按下 enter 或 esc 時觸發
<div onKeydown={m.keys(65).exact("ctrl", "alt")(this.onCtrlAltA)} />;

Available modifiers 可以用的修飾器

  • esc, tab, enter, space, up, down, del, left, right 鍵盤事件
    • del allows not only DELETE, but also BACKSPACE. del 會被 DELETE 或 BACKSPACE 觸發
    • left and right have another behavior when specified to mouse event 在鼠標事件中使用 left 和 right 會在點擊鼠標左鍵或右鍵時觸發
    • combination of key modifiers (e.g. m.enter.esc) does not work. m.enter.esc 的方式組合修飾符,並不能夠成功
  • left, right, middle 鼠標事件
  • ctrl, shift, alt, meta 系統修飾符鍵
  • noctrl, noshift, noalt, nometa
    • Execute event handler only when specified system modifier key is not pressed. 僅當未按下該修飾符時才會被觸發
  • self
  • prevent(不觸發原生事件動作), stop
  • keys(...args)
    • Known key name("esc", "tab", "enter", ...) or number can be specified. 支持數字,例如<div onKeydown={m.keys(65)(handler)} />; // 65 代表 a 鍵
  • exact(...args) 系統修飾符精確匹配時觸發,例如:<div onClick={m.exact("ctrl", "shift")(handler)} />;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM