1. 海报
This commit is contained in:
113
vite-tailwindcss/src/components/FestiveQrCard.vue
Normal file
113
vite-tailwindcss/src/components/FestiveQrCard.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div class="fq" :class="{ 'fq--compact': compact }">
|
||||
<div class="fq-title">扫码观喜</div>
|
||||
<div class="fq-frame">
|
||||
<span class="fq-corner fq-tl">囍</span>
|
||||
<span class="fq-corner fq-tr">囍</span>
|
||||
<span class="fq-corner fq-bl">囍</span>
|
||||
<span class="fq-corner fq-br">囍</span>
|
||||
<canvas ref="canvasRef" class="fq-canvas"></canvas>
|
||||
</div>
|
||||
<div v-if="!compact" class="fq-hint">手机扫码打开本页</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { renderFestiveQr } from '@/composables/renderFestiveQr'
|
||||
|
||||
const props = defineProps({
|
||||
url: { type: String, required: true },
|
||||
size: { type: Number, default: 148 },
|
||||
compact: { type: Boolean, default: false },
|
||||
centerImg: { type: String, default: '' },
|
||||
})
|
||||
|
||||
const canvasRef = ref(null)
|
||||
|
||||
async function render() {
|
||||
if (!canvasRef.value || !props.url) return
|
||||
const width = props.compact ? Math.min(props.size, 112) : props.size
|
||||
await renderFestiveQr(canvasRef.value, props.url, {
|
||||
size: width,
|
||||
centerImg: props.centerImg,
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(render)
|
||||
watch(() => [props.url, props.size, props.compact, props.centerImg], render)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.fq {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
padding: 14px 16px 12px;
|
||||
background:
|
||||
radial-gradient(circle at 50% 0%, rgba(240, 215, 140, 0.25), transparent 55%),
|
||||
linear-gradient(180deg, #9b0000, #6e0000);
|
||||
border: 1.5px solid #d4af37;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
|
||||
color: #f0d78c;
|
||||
min-width: 200px;
|
||||
}
|
||||
.fq--compact {
|
||||
min-width: 0;
|
||||
padding: 8px 10px 8px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 8px 22px rgba(0, 0, 0, 0.32);
|
||||
}
|
||||
.fq--compact .fq-title {
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.35em;
|
||||
padding-left: 0.35em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.fq--compact .fq-frame { padding: 8px; }
|
||||
.fq--compact .fq-corner { font-size: 10px; }
|
||||
.fq-title {
|
||||
font-size: 15px;
|
||||
letter-spacing: 0.45em;
|
||||
padding-left: 0.45em;
|
||||
font-weight: 600;
|
||||
text-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.2;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.fq-frame {
|
||||
position: relative;
|
||||
padding: 14px;
|
||||
background: linear-gradient(145deg, #fff8e7, #f7e7c3);
|
||||
border: 2px solid #d4af37;
|
||||
border-radius: 10px;
|
||||
box-shadow: inset 0 0 0 1px rgba(155, 0, 0, 0.12);
|
||||
}
|
||||
.fq-corner {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: #c41e3a;
|
||||
line-height: 1;
|
||||
opacity: 0.9;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
.fq-tl { top: 3px; left: 4px; }
|
||||
.fq-tr { top: 3px; right: 4px; }
|
||||
.fq-bl { bottom: 3px; left: 4px; }
|
||||
.fq-br { bottom: 3px; right: 4px; }
|
||||
.fq-canvas {
|
||||
display: block;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.fq-hint {
|
||||
margin-top: 8px;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.18em;
|
||||
color: rgba(240, 215, 140, 0.85);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user