zoukankan      html  css  js  c++  java
  • 框架-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)} />;
  • 相关阅读:
    list tuple dict 方法
    字典的方法
    看不懂的缩写
    canvas画图
    DOM2和DOM3
    表单脚本
    事件
    DOM扩展
    DOM
    BOM
  • 原文地址:https://www.cnblogs.com/qq3279338858/p/12762021.html
Copyright © 2011-2022 走看看