CSS 自定义形状 - clip-path

143 阅读1分钟

11.png 子组件文件:clipPath.vue

<template>

<div class="bottom-box" :style="{width: state.width - state.borderRadius + 'px', height: state.height - state.borderRadius + 'px'}">

<div class="title" :style="{width: state.titleWidth - 20 + 'px', height: state.titleHeight - 20 + 'px'}">

<span class="title-text">{{ state.title }}</span>

</div>

<div class="content" :style="{width: state.width + 'px', height: state.height + 'px'}">

<div class="clip-box" :style="{clipPath: state.path}"></div>

</div>

<slot class="slot"></slot>

</div>

</template>

<script setup>

import { onMounted, reactive, watch } from "vue";

const props = defineProps({

width: {

type: Number,

default: 320,

},

height: {

type: Number,

default: 320,

},

borderRadius: {

type: Number,

default: 10,

},

titleWidth: {

type: Number,

default: 148,

},

titleHeight: {

type: Number,

default: 50,

},

title: {

type: String,

default: '',

}

});

const state = reactive({

path: `path('M148 0 H300 A10 10 0 0 1 310 10 V300 A10 10 90 0 1 300 310 H10 A10 10 0 0 1 0 300 V60 Q0 50, 20 50 H120 Q130 50, 132 40 L138 10 Q140 0, 148 0 Z')`,

width: props.width,

height: props.height,

borderRadius: props.borderRadius,

titleWidth: props.titleWidth,

titleHeight: props.titleHeight,

title: props.title,

});

onMounted(() => {

let width = state.width - state.borderRadius;

let height = state.height - state.borderRadius;

state.path = `path('M${state.titleWidth} 0 H${width} A${state.borderRadius} ${state.borderRadius} 0 0 1 ${state.width} ${state.borderRadius} V${height} A${state.borderRadius} ${state.borderRadius} 90 0 1 ${width} ${state.height} H${state.borderRadius} A${state.borderRadius} ${state.borderRadius} 0 0 1 0 ${height} V${state.titleHeight} Q0 ${state.titleHeight - 10}, 20 ${state.titleHeight - 10} H${state.titleWidth - 28} Q${state.titleWidth - 18} ${state.titleHeight - 10}, ${state.titleWidth - 16} ${state.titleHeight - 15} L${state.titleWidth - 10} 10 Q${state.titleWidth - 8} 0, ${state.titleWidth} 0 Z')`;

});

</script>

<style scoped>

.bottom-box {

position: absolute;

margin: 100px;

width: 300px;

height: 300px;

background-color: #e0ebfe;

position: absolute;

box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.5);

border-radius: 10px;

}

.content {

width: 320px;

height: 320px;

position: absolute;

top: -10px;

left: -10px;

filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.5));

}

.clip-box {

width: 100%;

height: 100%;

background: #3775ff;

/* clip-path: path(

"M148 0 H300 A10 10 0 0 1 310 10 V300 A10 10 90 0 1 300 310 H10 A10 10 0 0 1 0 300 V60 Q0 50, 20 50 H120 Q130 50, 132 40 L138 10 Q140 0, 148 0 Z"

); */

}

.title {

position: absolute;

background-color: transparent;

top: 0;

left: 0;

color: #3775ff;

display: flex;

align-items: center;

justify-content: center;

}
</style>

父组件应用:

<ClipPath width="500" height="400" title-width="120" title-height="60" title="标题">

<div class="ccontent" >自定义内容</div>

</ClipPath>
// ccontent 是自定义内容,具体位置由样式控制
.ccontent {

position: absolute;

top: 50%;

left: 50%;

transform: translate(-50%, -50%);

width: 100px;

height: 100px;

background-color: bisque;

}