From 9a7fe6e47a71f5aabf7ab3a5467e0b05e407e263 Mon Sep 17 00:00:00 2001 From: kousum Date: Mon, 8 Apr 2024 15:58:03 +0800 Subject: [PATCH] fix: [Vue warn]: Slot "default" invoked outside the render function --- src/components/Watermark.ts | 144 ++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/components/Watermark.ts b/src/components/Watermark.ts index f6f5825..538c00f 100644 --- a/src/components/Watermark.ts +++ b/src/components/Watermark.ts @@ -1,5 +1,5 @@ import type { PropType } from 'vue' -import { defineComponent, h, onMounted, reactive, ref, toRefs, watch } from 'vue' +import { defineComponent, h, reactive, ref, toRefs, watch } from 'vue' import { defaultOptions } from '../options' import { BaseSize, FontGap } from '../constants' import type { WatermarkDrawingParams, WatermarkOptions } from '../types' @@ -13,13 +13,6 @@ export const Watermark = defineComponent({ }, }, setup(props, ctx) { - // Get the default slot content - const slots = ctx.slots.default?.() - // Throw an error if no slot content is provided - if (!slots) throw new Error('@watermarkify: Slot is required to use ') - // Throw an error if more than one slot content is provided - if (slots.length !== 1) throw new Error(`@watermarkify: requires exactly one slot, but got ${slots.length}`) - // Merge props.options with defaultOptions const options = reactive({ ...defaultOptions, @@ -60,7 +53,7 @@ export const Watermark = defineComponent({ canvasCtx.font = `${Number(fontSize)}px ${fontFamily}` const contents = Array.isArray(content.value) ? content.value : [content.value] // Measure the width of each content item - const widths = contents.map((item) => canvasCtx.measureText(item!).width) + const widths = contents.map(item => canvasCtx.measureText(item!).width) // Calculate the default width and height based on the measured content defaultWidth = Math.ceil(Math.max(...widths)) defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap @@ -188,62 +181,6 @@ export const Watermark = defineComponent({ addWatermark(canvas.toDataURL(), watermarkWidth) } - const renderWatermark = () => { - const slot = slots[0] - // Create a new canvas element and get its context - const canvas = document.createElement('canvas') - const canvasCtx = canvas.getContext('2d') - if (canvasCtx) { - // Create a new div element for the watermark if it doesn't exist yet - if (!watermarkRef.value) watermarkRef.value = document.createElement('div') - // Get the watermark size and canvas dimensions - const [watermarkWidth, watermarkHeight] = getWatermarkSize(canvasCtx) - const canvasWidth = (gapX.value + watermarkWidth) * devicePixelRatio - const canvasHeight = (gapY.value + watermarkHeight) * devicePixelRatio - const drawWidth = watermarkWidth * devicePixelRatio - const drawHeight = watermarkHeight * devicePixelRatio - // Set the canvas dimensions - canvas.setAttribute('width', `${appendPixel(canvasWidth * BaseSize)}`) - canvas.setAttribute('height', `${appendPixel(canvasHeight * BaseSize)}`) - // Set the drawing parameters - const drawingParams = { - drawX: (gapX.value * devicePixelRatio) / 2, - drawY: (gapY.value * devicePixelRatio) / 2, - rotateX: (drawWidth + gapX.value * devicePixelRatio) / 2, - rotateY: (drawHeight + gapY.value * devicePixelRatio) / 2, - } - // Set the alternate drawing parameters - const alternateDrawingParams = { - drawX: drawingParams.drawX + canvasWidth, - drawY: drawingParams.drawY + canvasHeight, - rotateX: drawingParams.rotateX + canvasWidth, - rotateY: drawingParams.rotateY + canvasHeight, - } - // Save the canvas state - canvasCtx.save() - // Rotate the canvas - rotateWatermark(canvasCtx, drawingParams.rotateX, drawingParams.rotateY, rotate.value) - - if (image.value) { - // TODO: handle image watermark - } else { - // Draw the text watermark - drawText(canvas, canvasCtx, drawWidth, drawHeight, watermarkWidth, drawingParams, alternateDrawingParams) - } - } - // Return a div element containing the original content and the watermark container - return h( - 'div', - { - ref: watermarkContainerRef, - style: { position: 'relative' }, - }, - [slot], - ) - } - - onMounted(renderWatermark) - watch( () => props.options, () => { @@ -255,17 +192,80 @@ export const Watermark = defineComponent({ ...props.options?.font, }, }) - renderWatermark() }, { deep: true, immediate: true }, ) - return { - renderWatermark, - } - }, - render() { // Render the watermark overlay - return h('div', {}, this.renderWatermark()) + return () => { + // Get the default slot content + const slots = ctx.slots.default?.() + // Throw an error if no slot content is provided + if (!slots) + throw new Error('@watermarkify: Slot is required to use ') + // Throw an error if more than one slot content is provided + if (slots.length !== 1) + throw new Error(`@watermarkify: requires exactly one slot, but got ${slots.length}`) + + const renderWatermark = () => { + const slot = slots[0] + // Create a new canvas element and get its context + const canvas = document.createElement('canvas') + const canvasCtx = canvas.getContext('2d') + if (canvasCtx) { + // Create a new div element for the watermark if it doesn't exist yet + if (!watermarkRef.value) + watermarkRef.value = document.createElement('div') + // Get the watermark size and canvas dimensions + const [watermarkWidth, watermarkHeight] = getWatermarkSize(canvasCtx) + const canvasWidth = (gapX.value + watermarkWidth) * devicePixelRatio + const canvasHeight = (gapY.value + watermarkHeight) * devicePixelRatio + const drawWidth = watermarkWidth * devicePixelRatio + const drawHeight = watermarkHeight * devicePixelRatio + // Set the canvas dimensions + canvas.setAttribute('width', `${appendPixel(canvasWidth * BaseSize)}`) + canvas.setAttribute('height', `${appendPixel(canvasHeight * BaseSize)}`) + // Set the drawing parameters + const drawingParams = { + drawX: (gapX.value * devicePixelRatio) / 2, + drawY: (gapY.value * devicePixelRatio) / 2, + rotateX: (drawWidth + gapX.value * devicePixelRatio) / 2, + rotateY: (drawHeight + gapY.value * devicePixelRatio) / 2, + } + // Set the alternate drawing parameters + const alternateDrawingParams = { + drawX: drawingParams.drawX + canvasWidth, + drawY: drawingParams.drawY + canvasHeight, + rotateX: drawingParams.rotateX + canvasWidth, + rotateY: drawingParams.rotateY + canvasHeight, + } + // Save the canvas state + canvasCtx.save() + // Rotate the canvas + rotateWatermark(canvasCtx, drawingParams.rotateX, drawingParams.rotateY, rotate.value) + + if (image.value) { + // TODO: handle image watermark + } + else { + // Draw the text watermark + drawText(canvas, canvasCtx, drawWidth, drawHeight, watermarkWidth, drawingParams, alternateDrawingParams) + } + } + // Return a div element containing the original content and the watermark container + return h( + 'div', + { + ref: watermarkContainerRef, + style: { position: 'relative' }, + }, + [slot], + ) + } + renderWatermark() + + return h('div', {}, renderWatermark()) + } }, + })