vueComponent / pro-components

easy use `Ant Design Vue` layout
MIT License
534 stars 215 forks source link

[Feature] 组件二次开发,扩展问题 #292

Closed luocong2016 closed 9 months ago

luocong2016 commented 10 months ago

🥰 需求描述 Description of Requirement

基于 ant-design-vue 的二次开发,存在一定局限性。

  1. 文件结构

    |- GlobalFooter/
    |- index.tsx
    |- style.ts
    |- index.d.ts
  2. index.d.ts

    // 这里需要提前声明
    // vue-design-vue
    declare module "ant-design-vue/lib/theme/interface" {
    interface ComponentTokenMap {
    GlobalFooter?: {}
    }
    }

3.index.less

import type { CSSObject } from "ant-design-vue/lib/_util/cssinjs"
import {
  genComponentStyleHook,
  FullToken,
  GenerateStyle,
  mergeToken,
} from "ant-design-vue/lib/theme/internal"

export interface ComponentToken {}

type GlobalFooterToken = FullToken<"GlobalFooter"> & {}

export const genBaseStyle: GenerateStyle<GlobalFooterToken> = (
  token: GlobalFooterToken
): CSSObject => {
  const { componentCls } = token

  return {
    [componentCls]: {
      marginBlock: 0,
      marginBlockStart: 48,
      marginBlockEnd: 24,
      marginInline: 0,
      paddingBlock: 0,
      paddingInline: 16,
      textAlign: "center",
      "&__list": {
        marginBlockEnd: 8,
        color: token.colorTextSecondary,
        "&-link": {
          color: token.colorTextSecondary,
          textDecoration: token.linkDecoration,
        },
        "*:not(:last-child)": {
          marginInlineEnd: 8,
        },
        "&:hover": {
          color: token.colorPrimary,
        },
      },
      "&__copyright": { fontSize: "14px", color: token.colorText },
    },
  }
}

export const useStyle = genComponentStyleHook("GlobalFooter", (token) => {
  const globalFooterToken = mergeToken<GlobalFooterToken>(token, {})

  return [genBaseStyle(globalFooterToken)]
})

4.index.tsx

import {
  defineComponent,
  type VNodeChild,
  type VNode,
  type ExtractPropTypes,
  type ComponentPublicInstance,
} from "vue"
import useConfigInject from "ant-design-vue/lib/config-provider/hooks/useConfigInject"
import { makeArrayProp, withInstall } from "@/utils"
import { useStyle } from "./style"

const globalFooterProps = {
  links: makeArrayProp<{
    key?: string
    href: string
    title: VNodeChild | VNode
    blankTarget?: boolean
  }>(),
  copyright: String,
  prefixCls: String,
}
export type GlobalFooterProps = ExtractPropTypes<typeof globalFooterProps>
export type GlobalFooterInstance = ComponentPublicInstance<GlobalFooterProps, {}>

const GlobalFooter = defineComponent({
  name: "ProFooter",
  props: globalFooterProps,
  setup(props, { attrs, slots }) {
    const { prefixCls } = useConfigInject("pro-footer", props)
    const [wrapSSR, hashId] = useStyle(prefixCls)

    const renderLinks = () => {
      if (!props.links) return null
      return (
        <div class={[`${prefixCls.value}__list`, hashId.value]}>
          {props.links.map((link) => (
            <a
              class={[`${prefixCls.value}__list-link`, hashId.value]}
              rel="noreferrer"
              key={link.key}
              title={link.key}
              href={link.href}
              target={link.blankTarget ? "_blank" : "_self"}
            >
              {link.title}
            </a>
          ))}
        </div>
      )
    }
    const renderCopyright = () => {
      if (!props.copyright && !slots.copyright) return null
      return (
        <div class={[`${prefixCls.value}__copyright`, hashId.value]}>
          {slots.copyright ? slots.copyright() : props.copyright}
        </div>
      )
    }

    return () =>
      wrapSSR(
        <div {...attrs} class={[prefixCls.value, hashId.value]}>
          {renderLinks()}
          {renderCopyright()}
        </div>
      )
  },
})

export default withInstall(GlobalFooter)

🧐 解决方案 Solution

能不能抽象出 @ant-design/pro-provider

🚑 其他信息 Other information

image