封装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