组件搭建
接着第一章节开始组件部分的内容
首先在packages下创建三个目录文件夹,目录结构如下:
+ packages
- components # 组件代码
- theme-chalk # 样式
- utils # 公共方法
然后分别cd
到每个目录下初始化pnpm init -y
生成三个包,修改package.json
,三个内容类似
# 以components为例子,其它同,修改name即可
{
"name": "@w-plus/components",
"version": "1.0.0",
"main": "index.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "WQ",
"license": "ISC"
}
这样每个目录下现在有一个package.json
文件,现在我们希望每个包可以互相引用使用,所以要在根目录下安装,也可以独立发布
在根目录下安装三个子包pnpm install @w-plus/components -w
,其它两个包同样的操作,-w
或--workspace
代表允许安装到根目录下,不加会报错,然后查看根目录下的package.json
已经有了这三个包
在components
目录下创建icon目录,来编写一个icon组件,目录如下:
+ components
+ icon
+ src # 组件源代码
- icon.ts # 放组件的props及公共方法
- icon.vue # 组件代码
- index.ts # 组件入口
在icon.ts
下来定义props
// 这里放组件的props及公共方法
import type { ExtractPropTypes } from "vue"
// as const,会让对象的每个属性变成只读(readonly)
export const iconProps = {
size:{
type:Number
},
color:{
type:String
}
} as const
export type IconProps = ExtractPropTypes<typeof iconProps>
在icon.vue
中写组件代码
<template>
<i class="w-icon" :style="style">
<slot></slot>
</i>
</template>
<script lang="ts">
import { computed, defineComponent } from "vue";
import { iconProps } from "./icon";
export default defineComponent({
name: "WIcon",
props: iconProps,
setup(props) {
const style = computed(() => {
if(!props.size && !props.color){
return {}
}
return {
...(props.size ? { 'font-size':props.size + 'px'} : {}),
...(props.color ? { 'color':props.color} : {}),
}
})
return { style }
},
});
</script>
在组件入口处导出组件,index.ts
中
import { withInstall } from "@w-plus/utils/with-install"
import Icon from "./src/icon.vue";
const WIcon = withInstall(Icon);
export{
WIcon
}
export default WIcon;
最后在play
下的main.ts
中引入组件测试,增加以下代码:
import { WIcon } from "@w-plus/components/icon“
app.use(WIcon)
这时候会发现use(WIcon)
报错传入的类型不对,传入的类型要为Plugin_2
所以我们需要处理一下这个问题,在Icon组件下的index.ts
中,修改代码为:
import { withInstall } from "@w-plus/utils/with-install"
import Icon from "./src/icon.vue";
const WIcon = withInstall(Icon);
export default WIcon;
因为在每个组件中都要处理这个问题,所以我们封装一个withInstall
方法在utils
下新建文件with-install.ts
文件,代码如下:
import type { App, Plugin } from "vue"; // 只是导入类型不是导入App的值
/**
* 组件外部使用use时执行install,然后将组件注册为全局
*/
// 类型必须导出否则生成不了.d.ts文件
export type SFCWithInstall<T> = T & Plugin;
/**
* 定义一个withInstall方法处理以下组件类型问题
* @param comp
*/
export const withInstall = <T>(comp: T) => {
/**
* 直接写comp.install = function(){} 的话会报错,因为comp下没有install方法
* 所以从vue中引入Plugin类型,断言comp的类型为T&Plugin
*/
(comp as SFCWithInstall<T>).install = function (app: App) {
app.component((comp as any).name, comp);
};
return comp as SFCWithInstall<T>;
};
在这里补充一个ts的小知识,Type 类型别名
可以使用类型别名接收抽离出来的内联类型实现复用,可以通过如下所示“type别名名字 = 类型定义”的格式来定义类型别名
/** 类型别名 */
{
type LanguageType = {
/** 以下是接口属性 */
/** 语言名称 */
name: string;
/** 使用年限 */
age: () => number;
}
}
// 针对接口类型无法覆盖的场景,比如组合类型、交叉类型,我们只能使用类型别名来接收
{
/** 联合 */
type MixedType = string | number;
/** 交叉 */
type IntersectionType = { id: number; name: string; }
& { age: number; name: string };
/** 提取接口属性类型 */
type AgeType = ProgramLanguage['age'];
}
类型别名,即我们仅仅是给类型取了一个新的名字,并不是创建了一个新的类型。
我们在play
下的app.vue
文件中使用icon组件,然后npm run dev
可以看到组件已经生效了
<template>
测试
<w-icon color="blue" :size="20">Hello Icon</w-icon>
</template>
Icon组件需要有图标,这里使用iconfont,在iconfont中新建项目,名称为w-plus
,然后再图标库添加自己想添加的图标到项目里,打开项目设置,更换图标前缀,配置如下:
设置好后把项目下载到本地
接着需要编写样式文件,在我们的样式目录theme-chalk
下,目录结构如下:
+ theme-chalk
+ src
+ fonts # 字体文件存放,将刚才下载的字体文件放入
- iconfont.ttf
- iconfont.woff
- iconfont.woff2
+ mixins
- config.scss # 全局配置
- mixins.scss # 混入mixin
- icon.scss # 图标文件
- index.scss # 入口
config.scss
代码如下(sass语法):
$namespace:'w'
/**
* 命名规范 BEM规范
<div class="z-cell">
<div class="z-cell__label"></div>
<div class="z-cell__value is_check"></div>
</div>
*/
mixins.scss
代码如下:
// 声明公共的sass方法
/*
* 引入config
*/
@use 'config' as *;
/*
* 将config暴露给全局使用
*/
@forward 'config';
icon.scss
将刚才下载的css文件内容copy
到里面,修改如下:
index.scss
中导入icon.scss
,代码如下:
@use 'icon.scss';
最后验证iconfont
配置是否生效,修改play/app.vue
文件(class是刚才icon.scss中的class):
<template>
测试
<w-icon color="blue" :size="30" class="w-icon-delete">Hello Icon</w-icon>
</template>
npm run dev
启动服务,测试,页面中已经显示图标:
到此,Icon组件已经基本完成了,并且可以正常使用
后续见下一章节:工具库打包