Day57:组件库封装-1

封装element组件

参考对象 折叠面板 按钮

npm create vue@3

npm i

使用vue3建库如果报错可以尝试禁用vs的 vetur 插件,这是vue2插件,会给vue3项目报错(禁用了之后需要重新加载

src新建components文件夹

下面新建Button文件夹,新建vue,ts,css文件

使用postcss书写样式

在APP引入script setup lang=ts

引入自定义前缀button并在appvue视图中实现

<template>
  <div>
    <!-- 组件库中的Button是通过接受一系列的props来添加不同的类名
    然后给这些类名添加不同的样式 -->
    <!-- 实现type=primary 这样一个蓝色的button -->
    <xzd-button type="primary">primary按钮</xzd-button>
    <xzd-button type="danger">danger按钮</xzd-button>
    <xzd-button type="danger" disabled>禁用按钮</xzd-button>
    <xzd-button type="info" circle>圆</xzd-button>
    <xzd-button type="danger" round>圆角按钮</xzd-button>
    <xzd-button size="large">大按钮</xzd-button>
    <xzd-button size="small">小按钮</xzd-button>
  </div>
</template>
<script setup lang="ts">
import XzdButton from './components/Button/XzdButton.vue'
</script>

给button不仅要添加自定义type,也要添加原生的type

组建库中的button是通过接受一系列的props来添加不同的类名

引入组件前缀button从前缀button.vue

传递一个type=primary的蓝色圆角button效果

公共button类

约定每个类的可选类型

把可选类型进一步拆分

把类型传递出去

import type { PropType } from "vue";
export type ButtonType = 'primary' | 'success' | 'waring' |
  'info' | 'danger'
export type ButtonSize = 'large' | 'small'
export type nativeType = 'button' | 'reset' | 'submit'

export interface ButtonProps {
    type?: ButtonType;
    size?: ButtonSize;
    plain?: boolean;
    round?: boolean;
    circle?: boolean;
    disabled?: boolean;
    nativeType?: nativeType;
    autofocus?: boolean
    //还需要接受2个原生的button属性
}
//props的类型如果封装成一个单独的文件 在引入的时候无法正确编译
export const buttonprops = {
    type: {
        type: String as PropType<ButtonType>,
        required: false
    },
    size: {
        type: String as PropType<ButtonSize>,
        required: false
    },
    plain: {
        type: Boolean,
        required: false
    },
    round: {
        type: Boolean,
        required: false
    },
    circle: {
        type: Boolean,
        required: false
    },
    disabled: {
        type: Boolean,
        required: false
    },
    nativeType: {
        type: String as PropType<nativeType>,
        required: false
    },
    autofocus: {
        type: Boolean,
        required: false
    }
}

自己定义的类名前缀button中用模板字符串拼接输入的type

判断是否为朴素类型,圆角,圆形

再加一个:disabled=disabled

在app中给button书写需要的可选类名

给文本内容分配插槽

在src下新建文件夹styles,新建vars.css和index.css。

由于没有设计

在把vars.css中element的系列颜色在检查元素的时候右键全部复制粘贴进来

统一替换el为自己定义的类名前缀

除了color之外还有border、font、相关的

reset.css清除浏览器默认样式。新建文件,并引入到index.css中

/* 定义一批css变量 */
@import './vars.css';
@import './reset.css';

想在css中实现嵌套,安装postcss即可,

新建postcss.config.cjs

npm i postcss-nested -D

安装vs高亮插件

在button的css中定义button的相关样式,并将button的css引入到styles中的index.css

通过type可以决定按钮的样式

在button的css中为button添加间距

选中button需要有focus、hover效果。边框active时变深

.xzd-button {
  & + & {
    margin: 12px;
  }
  &:hover,
  &:focus {
    color: var(--xzd-button-text-color);
    border-color: var(--xzd-button-hover-border-color);
  }
  &:active {
    color: var(--xzd-button-text-color);
    border-color: var(--xzd-button-active-border-color);
  }
}

修改朴素按钮的hover效果 &.is-plain ,&.is-round圆角,&.is-circle圆形

禁用按钮需要用原生的cursor: not-allowed;的禁用。需要给类名和属性,还有类名和属性的hover和focus也添加禁用。

.xzd-button {
  /* disabled */
  &.is-disabled,
  &.is-disabled:hover,
  &.is-disabled:focus,
  &[disabled],
  &[disabled]:hover,
  &[disabled]:focus {
    color: var(--xzd-button-disabled-text-color);
    cursor: not-allowed;
    background-image: none;
    background-color: var(--xzd-button-disabled-bg-color);
    border-color: var(--xzd-button-disabled-border-color);
  }
}

设置large和small对应尺寸的样式,并在buttonvue中添加[`xzd-button--${size}`]: size,

.xzd-button--large {
  --xzd-button-size: 40px;
  height: var(--xzd-button-size);
  padding: 12px 19px;
  font-size: var(--xzd-font-size-base);
  border-radius: var(--xzd-border-radius-base);
}
.xzd-button--small {
  --xzd-button-size: 24px;
  height: var(--xzd-button-size);
  padding: 5px 11px;
  font-size: 12px;
  border-radius: calc(var(--xzd-border-radius-base) - 1px);
}

设置产品系列颜色,使用遍历的方法写。在postcss中,想要支持写遍历,需要安装npm i postcss-each -D

给primary, success, warning, info, danger做一个遍历。 $val相当于循环变量,每次遍历的时候会替换成五个中的一个。遍历到哪个就给他添加一个新的值

/* 给不同的type类型添加上对应的样式(产品色彩) */
@each $val in primary, success, warning, info, danger {
  .xzd-button--$(val) {
    --xzd-button-text-color: var(--xzd-color-white);
    --xzd-button-bg-color: var(--xzd-color-$(val));
    --xzd-button-border-color: var(--xzd-color-$(val));
    --xzd-button-outline-color: var(--xzd-color-$(val)-light-5);
    --xzd-button-active-color: var(--xzd-color-$(val)-dark-2);
    --xzd-button-hover-text-color: var(--xzd-color-white);
    --xzd-button-hover-bg-color: var(--xzd-color-$(val)-light-3);
    --xzd-button-hover-border-color: var(--xzd-color-$(val)-light-3);
    --xzd-button-active-bg-color: var(--xzd-color-$(val)-dark-2);
    --xzd-button-active-border-color: var(--xzd-color-$(val)-dark-2);
    --xzd-button-disabled-text-color: var(--xzd-color-white);
    --xzd-button-disabled-bg-color: var(--xzd-color-$(val)-light-5);
    --xzd-button-disabled-border-color: var(--xzd-color-$(val)-light-5);
  }

primary的按钮不是朴素按钮,hover时有一层白色遮罩,需要单独处理。但每一样单独处理非常麻烦,需要在css中使用遍历

@each $val in primary, success, warning, info, danger {
  .xzd-button--$(val) {...}
  .xzd-button--$(val).is-plain {
    --xzd-button-text-color: var(--xzd-color-$(val));
    --xzd-button-bg-color: var(--xzd-color-$(val)-light-9);
    --xzd-button-border-color: var(--xzd-color-$(val)-light-5);
    --xzd-button-hover-text-color: var(--xzd-color-white);
    --xzd-button-hover-bg-color: var(--xzd-color-$(val));
    --xzd-button-hover-border-color: var(--xzd-color-$(val));
    --xzd-button-active-text-color: var(--xzd-color-white);
  }
}

注:sass原生支持嵌套和变量,和遍历

/* 给不同的type类型添加上对应的样式(产品色彩) */
@each $var in primary,success,warning,info,danger{
  .xzd-button--$(var) {
    --xzd-button-bg-color: var(--xzd-color-$(var));
  }
}

在前缀buttonvue中传一个默认值在网页检查端

折叠面板封装

新建文件夹,在app中引入

<xzd-collapse>
      <xzd-collapse-item name='1' title='标题1' disabled> <!-- 无法展开 -->
        <div>第一个折叠面板的内容</div>
      </xzd-collapse-item>
    </xzd-collapse>

必须要有name属性,添加title属性

新建两个vue——xzd-collapse和xzd-collapse-item

xzd-collapse中只写类名和插槽<solt />

xzd-collapse-item中写类名

在类型ts中,name是必传的,所以单独封装类型

余下的在export interface CollapseItemProps中规定传参类型

import type { InjectionKey } from "vue"

export type PropsName = string | number
export interface CollapseItemProps {
    name:PropsName,
    title?:string,
    disable?:boolean
}

基础用法写法

手风琴效果:每次只能展开一个面板。

通过accordion属性来设置是否以手风琴模式显示

基础写法:可以展开多个面板,面板之间互不影响

在item.vue上写头部样式(div)

在xzd-collapse-item中引入规定好的CollapseItemProps泛型参数

import type { CollapseItemProps } from './type'
defineProps<CollapseItemProps>()

在视图中写动态接受的div{{title}},给title写样式,样式中有一项为id,id中模板字符串为动态唯一值name

标题下面写内容,给内容书写样式,也动态唯一值name

只要传递过来disabled类名,则禁止点击

<div class="xzd-collaspe-item">
  <div class="xzd-collaspe-item__header" :class="{
    'is-disabled': disabled
    }" :id="`xzd-collaspe-head-${name}`">
    {{ title }}
  </div>
  <div class="xzd-clooapse-item__wrapper" :id="`xzd-collaspe-wrapper-${name}`">
    <div class="xzd-clooapse-item__content"></div>
  </div>
</div>

在app中引入两个Collapse,以显示Collapse标签的内容

在item.vue中引入type.ts中定义好的props约束,来约束数据类型

itemvue的title不能直接写为{{}},需要写在传递的插槽里。在app中以具名插槽的形式给插槽title传递title

<div class="xzd-collaspe-item__header" 
:class="{
    'is-disabled': disabled
}" 
:id="`xzd-collaspe-head-${name}`">
    <slot name="title">{{ title }}</slot>
</div>

div中以具名插槽的形式传递title的内容

在Collapse中定义activeName,为空数组,如果点击哪一项,就给中间传哪一项的name。且给activeName传了约束类型PropsName数组型

需要传递一个点击事件,在点击折叠面板头部的时候触发, 点击后在activeName如果有这一项,就删除这一项,如果没有就添加上这一项

给子组件传递activeName,需要在collaspe-item内部做判断,判断这个数组中是否包含当前的name值。如果在,当前折叠面板应该展开,否则闭合

import {ref} from 'vue'
import type {PropsName} from './'
let activeName = ref<PropsName[]>([])
let handleClick = (name: PropsName): void => {
  // 判断这个数组中是否包含当前的name值。在,当前折叠面板应该展开,否则闭合
  const index = activeNames.value.indexOf(name) 
  // 只要不存在就是-1,存在为具体值
  if(index > -1) {
      activeNames.value.splice(index,1) /* 删除 */
  }else{
      activeNames.value.push(name) /* 加上 */
  }
}

跨级且使用插槽不能用props传参,需要使用依赖注入传递参数。

跨级传递,需要给传参一个唯一的key值

在type.ts中export一下collapseContextKey,再引入回item

在CollapseContext中规定要传递的参数的类型,再使用symbol生成唯一的collapseContextKey

从父组件中传参到子组件item

通过inject collapseContextKey来得到父子组件之间的传值

通过isActive的变量来判断当前Item的name是否存在于activeNames中。如果在显示对应的content,否则不显示。

定义一个isActive,通过computed来判断是否为真。在视图中v-show isActive,为真显示,为假不显示。

在item.vue头部定义点击事件handleClick,再实现一下handleClick方法。

点击标题的头部,如果它在显示,让那一条折叠面板收起来;如果没显示,则显示。

如果disable,则直接return

组间传递的方法handleClick和点击的那个头的name

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值