您当前的位置:首页 > 网站建设 > javascript
| php | asp | css | H5 | javascript | Mysql | Dreamweaver | Delphi | 网站维护 | 帝国cms | React | 考试系统 | ajax |

浅谈Vue3 defineComponent有什么作用

51自学网 2022-05-02 21:34:41
  javascript

defineComponent函数,只是对setup函数进行封装,返回options的对象;

export function defineComponent(options: unknown) {  return isFunction(options) ? { setup: options } : options}

defineComponent最重要的是:在TypeScript下,给予了组件 正确的参数类型推断 。

在这里插入图片描述

defineComponent重载函数

1:direct setup function

// overload 1: direct setup function// (uses user defined props interface)export function defineComponent<Props, RawBindings = object>(  setup: (    props: Readonly<Props>,    ctx: SetupContext  ) => RawBindings | RenderFunction): DefineComponent<Props, RawBindings>

在这里插入图片描述

2:object format with no props

// overload 2: object format with no props// (uses user defined props interface)// return type is for Vetur and TSX supportexport function defineComponent<  Props = {},  RawBindings = {},  D = {},  C extends ComputedOptions = {},  M extends MethodOptions = {},  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,  E extends EmitsOptions = EmitsOptions,  EE extends string = string>(  options: ComponentOptionsWithoutProps<Props,RawBindings,D,C,M,Mixin,Extends,E,EE>): DefineComponent<Props, RawBindings, D, C, M, Mixin, Extends, E, EE>

在这里插入图片描述

3:object format with array props declaration

// overload 3: object format with array props declaration// props inferred as { [key in PropNames]?: any }// return type is for Vetur and TSX supportexport function defineComponent<  PropNames extends string,  RawBindings,  D,  C extends ComputedOptions = {},  M extends MethodOptions = {},  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,  E extends EmitsOptions = Record<string, any>,  EE extends string = string>(  options: ComponentOptionsWithArrayProps<    PropNames,    RawBindings,...>): DefineComponent<  Readonly<{ [key in PropNames]?: any }>,  RawBindings,...>

在这里插入图片描述

4: object format with object props declaration

// overload 4: object format with object props declaration// see `ExtractPropTypes` in ./componentProps.tsexport function defineComponent<  // the Readonly constraint allows TS to treat the type of { required: true }  // as constant instead of boolean.  PropsOptions extends Readonly<ComponentPropsOptions>,  RawBindings,  D,  C extends ComputedOptions = {},  M extends MethodOptions = {},  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,  E extends EmitsOptions = Record<string, any>,  EE extends string = string>(  options: ComponentOptionsWithObjectProps<    PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>): DefineComponent<PropsOptions, RawBindings, D, C, M, Mixin, Extends, E, EE>

在这里插入图片描述

开发实践

除去单元测试中几种基本的用法,在以下的 ParentDialog 组件中,主要有这几个实际开发中要注意的点:

自定义组件和全局组件的写法

inject、ref 等的类型约束

setup 的写法和相应 h 的注入问题

tsx 中 v-model 和 scopedSlots 的写法

ParentDialog.vue

<script lang="tsx">import { noop, trim } from 'lodash';import {  inject, Ref, defineComponent, getCurrentInstance, ref} from '@vue/composition-api';import filters from '@/filters';import CommonDialog from '@/components/CommonDialog';import ChildTable, { getEmptyModelRow } from './ChildTable.vue'; export interface IParentDialog {  show: boolean;  specFn: (component_id: HostComponent['id']) => Promise<{ data: DictSpecs }>;} export default defineComponent<IParentDialog>({  // tsx 中自定义组件依然要注册  components: {    ChildTable  },  props: {    show: {      type: Boolean,      default: false    },    specFn: {      type: Function,      default: noop    }  },   // note: setup 须用箭头函数  setup: (props, context) => {     // 修正 tsx 中无法自动注入 'h' 函数的问题    // eslint-disable-next-line no-unused-vars    const h = getCurrentInstance()!.$createElement;     const { emit } = context;    const { specFn, show } = props;     // filter 的用法    const { withColon } = filters;     // inject 的用法    const pageType = inject<CompSpecType>('pageType', 'foo');    const dictComponents = inject<Ref<DictComp[]>>('dictComponents', ref([]));        // ref的类型约束    const dictSpecs = ref<DictSpecs>([]);    const loading = ref(false);     const _lookupSpecs = async (component_id: HostComponent['id']) => {      loading.value = true;      try {        const json = await specFn(component_id);        dictSpecs.value = json.data;      } finally {        loading.value = false;      }    };     const formdata = ref<Spec>({      component_id: '',      specs_id: '',      model: [getEmptyModelRow()]    });    const err1 = ref('');    const err2 = ref('');        const _doCheck = () => {      err1.value = '';      err2.value = '';            const { component_id, specs_id, model } = formdata.value;      if (!component_id) {        err1.value = '请选择部件';        return false;      }      for (let i = 0; i < model.length; i++) {        const { brand_id, data } = model[i];        if (!brand_id) {          err2.value = '请选择品牌';          return false;        }        if (          formdata.value.model.some(            (m, midx) => midx !== i && String(m.brand_id) === String(brand_id)          )        ) {          err2.value = '品牌重复';          return false;        }      }      return true;    };     const onClose = () => {      emit('update:show', false);    };    const onSubmit = async () => {      const bool = _doCheck();      if (!bool) return;      const params = formdata.value;      emit('submit', params);      onClose();    };     // note: 在 tsx 中,element-ui 等全局注册的组件依然要用 kebab-case 形式 ????‍    return () => (      <CommonDialog        class="comp"        title="新建"        width="1000px"        labelCancel="取消"        labelSubmit="确定"        vLoading={loading.value}        show={show}        onClose={onClose}        onSubmit={onSubmit}      >        <el-form labelWidth="140px" class="create-page">         <el-form-item label={withColon('部件类型')} required={true} error={err1.value}>            <el-select              class="full-width"              model={{                value: formdata.value.component_id,                callback: (v: string) => {                  formdata.value.component_id = v;                  _lookupSpecs(v);                }              }}            >              {dictComponents.value.map((dictComp: DictComp) => (                <el-option key={dictComp.id} label={dictComp.component_name} value={dictComp.id} />              ))}            </el-select>          </el-form-item>          {formdata.value.component_id ? (              <el-form-item labelWidth="0" label="" required={true} error={err2.value}>                <child-table                  list={formdata.value.model}                  onChange={(v: Spec['model']) => {                    formdata.value.model = v;                  }}                  onError={(err: string) => {                    err3.value = err;                  }}                  scopedSlots={{                      default: (scope: any) => (                        <p>{ scope.foo }</p>                      )                  }}                />              </el-form-item>          ) : null}        </el-form>      </CommonDialog>    );  }});</script> <style lang="scss" scoped></style>

全文总结

  • 引入 defineComponent() 以正确推断 setup() 组件的参数类型
  • defineComponent 可以正确适配无 props、数组 props 等形式
  • defineComponent 可以接受显式的自定义 props 接口或从属性验证对象中自动推断
  • 在 tsx 中,element-ui 等全局注册的组件依然要用 kebab-case 形式
  • 在 tsx 中,v-model 要用 model={{ value, callback }} 写法
  • 在 tsx 中,scoped slots 要用 scopedSlots={{ foo: (scope) => () }} 写法
  • defineComponent 并不适用于函数式组件,应使用 RenderContext 解决

到此这篇关于浅谈Vue3 defineComponent有什么作用的文章就介绍到这了,更多相关Vue3 defineComponent作用内容请搜索wanshiok.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持wanshiok.com!


微信小程序实现列表项左滑删除效果
微信小程序实现上传图片的功能
51自学网,即我要自学网,自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1