Vue3实现印章徽章组件
1、组件结构
2、组件封装
src/components/StampBadge/src/StampBadge.vue 文件代码
<template>
<div
class="first-ring"
v-bind="getBindValue"
:class="getStampBadgeClass"
>
<div class="second-ring" :class="getStampBadgeClass">
<div class="third-ring" :class="getStampBadgeClass">
<div class="forth-ring" :class="getStampBadgeClass">
<div class="content-rectangle ellipsis" :class="getStampBadgeClass">
<span class="">{{content}}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "StampBadge",
inheritAttrs: false,
});
</script>
<script lang="ts" setup>
import { computed, onMounted, unref } from "vue";
import { stampBadgeProps } from "./props";
// import { useAttrs } from "/@/hooks/core/useAttrs";
const props = defineProps(stampBadgeProps);
// get component class
// const attrs = useAttrs({ excludeDefaultKeys: false });
const getStampBadgeClass = computed(() => {
const { color, size } = props;
return [
{
[`stamp-badge-${color}`]: !!color,
[`stamp-badge-${size}`]: !!size,
},
];
});
onMounted(() => {
rotate()
});
async function rotate() {
const { rotate ,opacity} = props;
var element = document.getElementsByClassName('first-ring')[0]; // 获取你想要旋转的元素
element.style.webkitTransform = 'rotate('+ rotate +'deg)'; // Chrome, Safari 和 Opera
element.style.msTransform = 'rotate('+ rotate +'deg)'; // 旧版的IE
element.style.transform = 'rotate('+ rotate +'deg)'; // 标准语法
element.style.opacity = opacity;
};
// get inherit binding value
// const getBindValue = computed(() => ({ ...unref(attrs), ...props }));
const getBindValue = computed(() => ({ ...props }));
</script>
<style lang="less" scoped>
.first-ring {
display: flex;
align-items: center;
justify-content: center;
/* 生成的图片是有一张,开启repeat自动填充 */
pointer-events: none;
background: repeat;
border-radius: 100px;
/* 核心部分,决定水印层与内容部分的结合方式 */
mix-blend-mode: multiply;
}
.second-ring {
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 100px;
}
.third-ring {
display: flex;
align-items: center;
justify-content: center;
border-radius: 100px;
}
.forth-ring {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 100px;
}
.content-rectangle {
position: absolute;
font-weight: bold;
text-align: center;
background: #fff;
}
.ellipsis {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// primary
.stamp-badge-primary.first-ring {
background: #1890ff;
}
.stamp-badge-primary.third-ring {
background: #1890ff;
}
.stamp-badge-primary.content-rectangle {
color: #1890ff;
border: 1px solid #1890ff;
}
// success
.stamp-badge-success.first-ring {
background: #52c41a;
}
.stamp-badge-success.third-ring {
background: #52c41a;
}
.stamp-badge-success.content-rectangle {
color: #52c41a;
border: 1px solid #52c41a;
}
// error
.stamp-badge-error.first-ring {
background: #ff4d4f;
}
.stamp-badge-error.third-ring {
background: #ff4d4f;
}
.stamp-badge-error.content-rectangle {
color: #ff4d4f;
border: 1px solid #ff4d4f;
}
// warning
.stamp-badge-warning.first-ring {
background: #faad14;
}
.stamp-badge-warning.third-ring {
background: #faad14;
}
.stamp-badge-warning.content-rectangle {
color: #faad14;
border: 1px solid #faad14;
}
// info
.stamp-badge-info.first-ring {
background: #ccc;
}
.stamp-badge-info.third-ring {
background: #ccc;
}
.stamp-badge-info.content-rectangle {
color: #ccc;
border: 1px solid #ccc;
}
// large
.stamp-badge-large.first-ring {
width: 84px;
height: 84px;
}
.stamp-badge-large.second-ring {
width: 80px;
height: 80px;
}
.stamp-badge-large.third-ring {
width: 74px;
height: 74px;
}
.stamp-badge-large.forth-ring {
width: 64px;
height: 64px;
}
.stamp-badge-large.content-rectangle {
width: 90px;
font-size: 1.2rem;
}
// middle
.stamp-badge-middle.first-ring {
width: 64px;
height: 64px;
}
.stamp-badge-middle.second-ring {
width: 60px;
height: 60px;
}
.stamp-badge-middle.third-ring {
width: 56px;
height: 56px;
}
.stamp-badge-middle.forth-ring {
width: 48px;
height: 48px;
}
.stamp-badge-middle.content-rectangle {
width: 70px;
font-size: 1rem;
}
// small
.stamp-badge-small.first-ring {
width: 54px;
height: 54px;
}
.stamp-badge-small.second-ring {
width: 50px;
height: 50px;
}
.stamp-badge-small.third-ring {
width: 46px;
height: 46px;
}
.stamp-badge-small.forth-ring {
width: 38px;
height: 38px;
}
.stamp-badge-small.content-rectangle {
width: 60px;
font-size: 0.8rem;
}
// auto
.stamp-badge-auto.first-ring {
width: 100%;
height: 100%;
}
.stamp-badge-auto.second-ring {
width: 80%;
height: 80%;
}
.stamp-badge-auto.third-ring {
width: 80%;
height: 80%;
}
.stamp-badge-auto.forth-ring {
width: 80%;
height: 80%;
}
.stamp-badge-auto.content-rectangle {
width: 80%;
font-size: 80%;
border-width:0.3rem;
}
</style>
src/components/StampBadge/src/props.ts 文件代码
export const stampBadgeProps = {
color: {
type: String,
default: "primary",
validator: (v) =>
["primary", "error", "warning", "success", "info"].includes(v),
},
/**
* stamp badge size.
* @default: middle
*/
size: {
type: String,
default: "middle",
validator: (v) => ["large", "middle", "small", "auto"].includes(v),
},
/**
* stamp badge rotate deg.
* @default: 0
*/
rotate: { type: Number, default: 0 },
opacity: { type: Number, default: 1 },
content: { type: String, default: "Unknown" },
};
src/components/StampBadge/index.ts 文件代码
import { withInstall } from "@/utils/StamoBadge";
import type { ExtractPropTypes } from "vue";
import stampbadge from "./src/StampBadge.vue";
import { stampBadgeProps } from "./src/props";
export const StampBadge = withInstall(stampbadge);
export declare type ButtonProps = Partial<
ExtractPropTypes<typeof stampBadgeProps>
>;
src/utils/index.ts 文件代码
export const withInstall = <T>(component: T, alias?: string) => {
const comp = component as any;
comp.install = (app: App) => {
app.component(comp.name || comp.displayName, component);
if (alias) {
app.config.globalProperties[alias] = component;
}
};
return component as T & Plugin;
};
3、组件应用
···