# vue3组件库项目学习笔记(二):开发一个组件

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

在搭建了基础架构之后我们就需要编写一个完整的组件它应该包括数据接口样式组件的 vue 文件等等内容

编写组件

我们知道组件都有很多的属性字段并且部分的属性是可以枚举的所以我们将这些会传递进组件的内容都写下来放在 types.ts 文件中

import type { ExtractPropTypes } from 'vue';
//枚举可以枚举字段的内容
export const ButtonType = ['primary', 'text'];

export const ButtonSize = ['large', 'small'];

export const buttonProps = {
  //判定内容在枚举字段内
  type: {
    type: String,
    validator(value: string) {
      return ButtonType.includes(value);
    }
  },
  size: {
    type: String,
    validator(value: string) {
      return ButtonSize.includes(value);
    }
  },
  //圆角
  round: Boolean,
  //禁用
  disabled: Boolean
};
//导出
export type ButtonProps = ExtractPropTypes<typeof buttonProps>;

之后我们来编写我们组件的核心逻辑我们的写法如下我们首先接收一个传入组件的参数集合然后根据这些参数来改变我们组件的样式到达配置我们组件的目的最后使用 slot 插槽来将按钮内部的内容输入其中:

<script lang="ts" setup>
import "./style/index.less";
import { computed } from "vue";
import { buttonProps } from "./types";
const props = defineProps(buttonProps);
console.log(props)

const styleClass = computed(() => {
  return {
    "ls-button":true,
    [`ls-button-${props.type}`]: props.type,
    "is-round": props.round,
    "is-disabled": props.disabled,
    [`ls-button-${props.size}`]: props.size,
  };
});
</script>
<template>
  <button  :class="styleClass">
    <slot />
  </button>
</template>

在完成了逻辑之后我们为其编写对应的样式放在 style/index.less 文件中你可以按照自己的喜好来编写自己喜欢的样式:

.ls-button {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #dcdfe6;
  color: #606266;
  appearance: none;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 0;
  transition: 0.1s;
  font-weight: 500;
  padding: 12px 20px;
  font-size: 14px;
  border-radius: 4px;

  &:hover {
    color: #409eff;
    border-color: #c6e2ff;
    background-color: #ecf5ff;
  }
}

.ls-button-primary {
  color: #fff;
  background-color: #409eff;
  border-color: #409eff;

  &:hover {
    background: #66b1ff;
    border-color: #66b1ff;
    color: #fff;
  }
}

.ls-button-text {
  border-color: transparent;
  color: #409eff;
  background: transparent;
  padding-left: 0;
  padding-right: 0;

  &:hover {
    color: #66b1ff;
    border-color: transparent;
    background-color: transparent;
  }
}

.ls-button.is-disabled {
  color: #c0c4cc;
  cursor: not-allowed;
  background-image: none;
  background-color: #fff;
  border-color: #ebeef5;
}

.ls-button-primary.is-disabled,
.ls-button-primary.is-disabled:active,
.ls-button-primary.is-disabled:focus,
.ls-button-primary.is-disabled:hover {
  color: #fff;
  background-color: #a0cfff;
  border-color: #a0cfff;
}

.ls-button-primary.is-disabled.is-plain,
.ls-button-primary.is-disabled.is-plain:active,
.ls-button-primary.is-disabled.is-plain:focus,
.ls-button-primary.is-disabled.is-plain:hover {
  color: #8cc5ff;
  background-color: #ecf5ff;
  border-color: #d9ecff;
}

.ls-button-large {
  padding: 10px 20px;
  font-size: 14px;
  border-radius: 4px;
}

.ls-button-small {
  padding: 9px 15px;
  font-size: 12px;
  border-radius: 3px;
}

.is-round {
  border-radius: 20px;
}

使用 app.use

我们希望我们的组件可以使用 app.use 方法来挂载所以我们需要提供一个方法在我们的 utils 的index.ts 内把内容改写成这个方法

import type { Plugin } from "vue"

export const withInstall = <T, E extends Record<string, any>>(main: T, extra?: E): T => {
  (main as SFCWithInstall<T>).install = (app): void => {
    for (const comp of [main, ...Object.values(extra ?? {})]) {
      app.component(comp.name, comp);
    }
  };

  if (extra) {
    for (const [key, comp] of Object.entries(extra)) {
      (main as any)[key] = comp;
    }
  }
  return main as SFCWithInstall<T> & E;
};

export type SFCWithInstall<T> = T & Plugin;

然后我们可以在 button 组件的 index.ts 内调用这个方法来提供组件这个能力

import { withInstall } from '@ls-ui/utils'
import Button from './button.vue'
const LsButton = withInstall(Button)
export default LsButton

最后我们在 components 文件夹下 与 package.json 同级的位置创建一个 index.ts 文件提供一个 install 方法因为 app.use 要求我们传入的参数具有这个方法

import components from './src/index'
export * from './src/index'
import { App } from 'vue'
import { version } from './package.json';

const install = function (app: App): void {
  Object.entries(components).forEach(([key, value]) => {
    app.component(key, value);
  });
};

export default {
  install,
  version
};

别忘了修改我们的 package.json 文件让他的 main 模块指向我们的刚刚写好的文件

"main": "index.ts",

一切完成之后我们就可以在 examples 里调用我们的模块了 在 main.ts 文件里使用 app.use 的方法来调用

import { createApp } from 'vue';
import App from './app.vue';
import LsButton from "ls-ui"

const app = createApp(App);
app.use(LsButton as any)
app.mount('#app')

之后在 app.vue 文件里尝试调用它如果不出以外你的界面上将会现实一个蓝色的按钮并且它具有圆角

<template>
  <div>
    <ls-button type="primary" size="small" round >
      哈哈哈哈哈
    </ls-button>
  </div>
</template>
<script lang="ts" setup>
</script>

组件Attrs与方法

我们继续完善我们的组件比如我们希望我们的组件具有 name 属性就想原生的 html 元素一样我们可以定义一个props 然后再来写我们的 props属性再绑定到组件代码上但是其实对于这种情况我们可以使用 Attrs 来实现。通过它可以获得绑定在组件上但是 prosp 内不接收的属性如果原生的 html 元素和我们的组件上都需需要某个元素并且作用相同我们可以利用它简化我们的代码

通过 useAttrs 方法我们可以获得我们需要的内容再通过 v-bind 绑定到我们的按钮上:

<script lang="ts" setup>
import { useAttrs  } from "vue";
//...
const attrs = useAttrs()
console.log(attrs)
//.....
</script>
<template>
  <button  :class="styleClass"  v-bind="attrs" >
    <slot />
  </button>
</template>

之后我们在我们的组件里传递一个 name 属此时打开F12 定位到我们的button可以看到我们的标签上具有 name = "lst" 这个字段:

<ls-button type="primary" size="small" round name="lst">
     哈哈哈哈哈
</ls-button>

然后我们可以理所当然的想到一个按钮最重要的就是具有作用比如我们点击它的时候产生一些效果所以我们应该为我们的组件添加一个可以相应的方法其实也很简单和 vue 父子组件通信是一样的以下的完整的demo:

<script lang="ts" setup>
import "./style/index.less";
import { computed , useAttrs , defineEmits } from "vue";
import { buttonProps } from "./types";
const props = defineProps(buttonProps);
console.log(props)
const attrs = useAttrs()
console.log(attrs)


const emits = defineEmits(['click'])

const styleClass = computed(() => {
  return {
    "ls-button":true,
    [`ls-button-${props.type}`]: props.type,
    "is-round": props.round,
    "is-disabled": props.disabled,
    [`ls-button-${props.size}`]: props.size,
  };
});

const myClick = ( ) => {
  emits('click', 11);
}
</script>
<template>
  <button  :class="styleClass"  v-bind="attrs" @click="myClick()">
    <slot />
  </button>
</template>

app.vue

<template>
  <div>
    <ls-button type="primary" size="small" round name="lst" @click="test">
      哈哈哈哈哈
    </ls-button>
  </div>
</template>
<script lang="ts" setup>
const test = ( msg:number ) => {
  console.log(msg);
};
</script>

然后在你点击按钮之后在控制台打印出 2 那么你的组件就编写完成了

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: vue

“# vue3组件库项目学习笔记(二):开发一个组件” 的相关文章