Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

二次封装vant组件时继承原组件所有的属性 #8701

Closed
yangss3 opened this issue May 13, 2021 · 20 comments
Closed

二次封装vant组件时继承原组件所有的属性 #8701

yangss3 opened this issue May 13, 2021 · 20 comments
Labels

Comments

@yangss3
Copy link

yangss3 commented May 13, 2021

这个功能解决了什么问题

方便在二次封装vant组件时继承原组件的所有prop,让新组件具有与原组件完全相同的API

描述您想要的解决方案

在导出的组件对象上添加包含所有prop定义的Props属性,或者可以单独导出组件的props定义对象

建议的API是什么样的

方案一:在导出的组件对象上添加Props属性

// MyNavBar.ts
import { NavBar } from 'vant'
import { defineComponent } from 'vue'
export default defineComponent({
    props: {
        ...NavBar.Props
    },
   // ...
})

方案二: 支持直接导出组件Props定义对象

// MyNavBar.ts
import { NavBar } from 'vant'
import { Props } from 'vant/lib/nav-bar'
import { defineComponent } from 'vue'
export default defineComponent({
    props: {
       ...Props
    },
   // ...
})
@yangss3 yangss3 changed the title 二次封装vant组件时,如何继承原组件所有的属性 二次封装vant组件时继承原组件所有的属性 May 13, 2021
@zhoucan38
Copy link
Contributor

v-attr不是可以么

@yangss3
Copy link
Author

yangss3 commented May 13, 2021

v-attr不是可以么

能给个例子吗,非常感谢

@zhoucan38
Copy link
Contributor

@yangss3
Copy link
Author

yangss3 commented May 14, 2021

https://www.vue3js.cn/docs/zh/guide/component-attrs.html#attribute-%E7%BB%A7%E6%89%BF

v-bind="$attrs"

我指的是props,不是attrs,props是组件向外定义的接口,在二次封装vant组件时需要能方便的继承原组件定义的props,这样就能完全兼容原组件接口,而不需要再手动去一个个定义,特别是在搭配TS的场景下,还可以得到原组件props的类型提示

比如我要在NavBar的基础上封装自己的MyNavBar,实现一些定制化的逻辑,但是需要它接受与NavBar完全相同的props,可以这样做:

import { NavBar } from 'vant'
import { defineComponent, h, PropType } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
  name: 'MyNavBar',
  props: { 
    // 继承NavBar的props
    ...NavBar.props,  
   // 自定义prop
    onClickLeft: {
      type: Function as PropType<() => void>,
    }
  }
  setup(props, { attrs, slots }) {
    const router = useRouter()
    return ()  => h(
      NavBar,
      {
        ...props,
        ...attrs,
        'onClick-left': props.onClickLeft || () => router.back()
      },
      slots
    )
  }
})

这样在使用 MyNavBar 时,用法能基本和NavBar保持一致:

<my-nav-bar title="标题" left-arrow right-text="保存" />
<van-nav-bar title="标题" left-arrow right-text="保存" @click-left="() => router.back()"/>

@chenjiahan
Copy link
Member

每个组件本身都是有 props 定义的,只是经过 defineComponent 处理后,props 对应的类型定义无法获取到了。

这个应该是 Vue 框架层面解决的问题。

@zhoucan38
Copy link
Contributor

https://www.vue3js.cn/docs/zh/guide/component-attrs.html#attribute-%E7%BB%A7%E6%89%BF
v-bind="$attrs"

我指的是props,不是attrs,props是组件向外定义的接口,在二次封装vant组件时需要能方便的继承原组件定义的props,这样就能完全兼容原组件接口,而不需要再手动去一个个定义,特别是在搭配TS的场景下,还可以得到原组件props的类型提示

比如我要在NavBar的基础上封装自己的MyNavBar,实现一些定制化的逻辑,但是需要它接受与NavBar完全相同的props,可以这样做:

import { NavBar } from 'vant'
import { defineComponent, h, PropType } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
  name: 'MyNavBar',
  props: { 
    // 继承NavBar的props
    ...NavBar.props,  
   // 自定义prop
    onClickLeft: {
      type: Function as PropType<() => void>,
    }
  }
  setup(props, { attrs, slots }) {
    const router = useRouter()
    return ()  => h(
      NavBar,
      {
        ...props,
        ...attrs,
        'onClick-left': props.onClickLeft || () => router.back()
      },
      slots
    )
  }
})

这样在使用 MyNavBar 时,用法能基本和NavBar保持一致:

<my-nav-bar title="标题" left-arrow right-text="保存" />
<van-nav-bar title="标题" left-arrow right-text="保存" @click-left="() => router.back()"/>

你这样不是已近实现了么,原有组件的属性也继承了,难道你仅仅是想要一点点提示?

@yangss3
Copy link
Author

yangss3 commented May 15, 2021

https://www.vue3js.cn/docs/zh/guide/component-attrs.html#attribute-%E7%BB%A7%E6%89%BF
v-bind="$attrs"

我指的是props,不是attrs,props是组件向外定义的接口,在二次封装vant组件时需要能方便的继承原组件定义的props,这样就能完全兼容原组件接口,而不需要再手动去一个个定义,特别是在搭配TS的场景下,还可以得到原组件props的类型提示
比如我要在NavBar的基础上封装自己的MyNavBar,实现一些定制化的逻辑,但是需要它接受与NavBar完全相同的props,可以这样做:

import { NavBar } from 'vant'
import { defineComponent, h, PropType } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
  name: 'MyNavBar',
  props: { 
    // 继承NavBar的props
    ...NavBar.props,  
   // 自定义prop
    onClickLeft: {
      type: Function as PropType<() => void>,
    }
  }
  setup(props, { attrs, slots }) {
    const router = useRouter()
    return ()  => h(
      NavBar,
      {
        ...props,
        ...attrs,
        'onClick-left': props.onClickLeft || () => router.back()
      },
      slots
    )
  }
})

这样在使用 MyNavBar 时,用法能基本和NavBar保持一致:

<my-nav-bar title="标题" left-arrow right-text="保存" />
<van-nav-bar title="标题" left-arrow right-text="保存" @click-left="() => router.back()"/>

你这样不是已近实现了么,原有组件的属性也继承了,难道你仅仅是想要一点点提示?

现在通过NavBar.props 拿不到 NavBar 的 props 定义

@GapMAX
Copy link

GapMAX commented May 19, 2021

每个组件本身都是有 props 定义的,只是经过 defineComponent 处理后,props 对应的类型定义无法获取到了。

这个应该是 Vue 框架层面解决的问题。

defineComponent本来就只是一个函数,感觉就是vant自己本身没有把props的类型导出来而已。

@GapMAX
Copy link

GapMAX commented May 19, 2021

https://www.vue3js.cn/docs/zh/guide/component-attrs.html#attribute-%E7%BB%A7%E6%89%BF
v-bind="$attrs"

我指的是props,不是attrs,props是组件向外定义的接口,在二次封装vant组件时需要能方便的继承原组件定义的props,这样就能完全兼容原组件接口,而不需要再手动去一个个定义,特别是在搭配TS的场景下,还可以得到原组件props的类型提示
比如我要在NavBar的基础上封装自己的MyNavBar,实现一些定制化的逻辑,但是需要它接受与NavBar完全相同的props,可以这样做:

import { NavBar } from 'vant'
import { defineComponent, h, PropType } from 'vue'
import { useRouter } from 'vue-router'
export default defineComponent({
  name: 'MyNavBar',
  props: { 
    // 继承NavBar的props
    ...NavBar.props,  
   // 自定义prop
    onClickLeft: {
      type: Function as PropType<() => void>,
    }
  }
  setup(props, { attrs, slots }) {
    const router = useRouter()
    return ()  => h(
      NavBar,
      {
        ...props,
        ...attrs,
        'onClick-left': props.onClickLeft || () => router.back()
      },
      slots
    )
  }
})

这样在使用 MyNavBar 时,用法能基本和NavBar保持一致:

<my-nav-bar title="标题" left-arrow right-text="保存" />
<van-nav-bar title="标题" left-arrow right-text="保存" @click-left="() => router.back()"/>

你这样不是已近实现了么,原有组件的属性也继承了,难道你仅仅是想要一点点提示?

那样并不能获取到props类型,人家只是写个样子,表示想要这样的功能。还有写ts难道不就是为了检查和提示吗?

@chenjiahan
Copy link
Member

chenjiahan commented May 19, 2021

defineComponent 是一个类型转换的函数,组件本身是一个对象,对象里有 props 这个属性,但经过 defineComponent 转换后,组件的类型会变成一个映射后的构造函数,构造函数上不再存在 props 属性。

@GapMAX
Copy link

GapMAX commented May 19, 2021

defineComponent 是一个类型转换的函数,组件本身是一个对象,对象里有 props 这个属性,但经过 defineComponent 转换后,组件的类型会变成一个映射后的构造函数,构造函数上不再存在 props 属性。

正如你说的defineComponent是一个类型转换函数,那我觉得defineComponent并没有义务帮我们保留类型。当然或许之后也会演变成如你想的那样,但现在官方并没有实现,是不是应该把组件Props的类型导出来比较合理?

@chenjiahan
Copy link
Member

嗯呢,导出 Props 这个改动我们会评估一下,同时也建议到 vue-next 仓库下提一个相关的 issue,看看能否在 defineComponent 时进行处理

@Zclhlmgqzc
Copy link

Zclhlmgqzc commented May 19, 2021

感觉已经解决了看图 应该是类型问题
VTD41KAOV}}0`XV~PL6(RWT

@OFFSO%O@C3` {O}YC2K2(D

改造 vue 的类型文件后 再加上 props 就可以提示了

DGP9`LHK1JFL3E_{0XN~L4D

` B~M492 30T2AC$TJ4 }24

@chenjiahan
Copy link
Member

Vue 仓库已有相关 PR:vuejs/core#3798

组件库就不做调整了,等框架发版吧

@hairyf
Copy link

hairyf commented Jun 27, 2021

我是这样解决的,不知道能不能帮到你。
image
image

@agileago
Copy link

agileago commented Nov 5, 2021

@TuiMao233 强啊,兄弟, 不过用类组件解决HOC的问题轻而易举

@jawa0919
Copy link

我是这样写的

import { NavBar, NavBarProps } from "vant";
import { defineComponent, h, ExtractPropTypes } from "vue";

const myNavBarProps = {
  routerMode: Boolean,
};

type MyNavBarProps = ExtractPropTypes<typeof myNavBarProps>;

export default defineComponent<NavBarProps & MyNavBarProps>({
  name: "MyNavBar",
  setup(props, { attrs, slots }) {
    console.log(typeof props.routerMode == "boolean");
    console.log(typeof props.title == "string");
    return () =>
      h(
        NavBar,
        {
          ...props,
          ...attrs,
        },
        slots
      );
  },
});

QQ截图20220326012522

@yhhcg
Copy link

yhhcg commented May 20, 2022

Vue 仓库已有相关 PR:vuejs/core#3798

组件库就不做调整了,等框架发版吧

发版了吗

@xiangshu233
Copy link

@yangss3 请问该 issues 解决了吗,可以 直接使用 ...NavBar.Props 导出了吗

@chenjiahan
Copy link
Member

@xiangshu233 Vant 4 导出了所有组件的 props 值

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants