枫叶建站讨债公司网站建设
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:16
当前位置: 首页 > news >正文
枫叶建站,讨债公司网站建设,西安有几个区,中信建设有限责任公司中标项目APIs 参数说明类型默认值必传width水印的宽度#xff0c;默认值为 content 自身的宽度numberundefinedfalseheight水印的高度#xff0c;默认值为 content 自身的高度numberundefinedfalserotate水印绘制时#xff0c;旋转的角度#xff0c;单位 number-22falsezIndex追加…APIs 参数说明类型默认值必传width水印的宽度默认值为 content 自身的宽度numberundefinedfalseheight水印的高度默认值为 content 自身的高度numberundefinedfalserotate水印绘制时旋转的角度单位 °number-22falsezIndex追加的水印元素的 z-indexnumber9falseimage图片源建议使用 2 倍或 3 倍图优先级高于文字stringundefinedfalsecontent水印文字内容string | string[]‘’falsecolor字体颜色string‘rgba(0,0,0,.15)’falsefontSize字体大小单位pxnumber16falsefontWeight字体粗细‘normal’ | ‘light’ | ‘weight’ | number‘normal’falsefontFamily字体类型string‘sans-serif’falsefontStyle字体样式‘none’ | ‘normal’ | ‘italic’ | ‘oblique’‘normal’falsegap水印之间的间距[number, number][100, 100]falseoffset水印距离容器左上角的偏移量默认为 gap/2[number, number][50, 50]false 效果如下图在线预览 创建水印组件Watermark.vue script setup langts import {unref,shallowRef,computed,watch,onMounted,onBeforeUnmount,nextTick,getCurrentInstance,getCurrentScope,onScopeDispose } from vue import type { CSSProperties } from vue interface Props {width?: number // 水印的宽度默认值为 content 自身的宽度height?: number // 水印的高度默认值为 content 自身的高度rotate?: number // 水印绘制时旋转的角度单位 °zIndex?: number // 追加的水印元素的 z-indeximage?: string // 图片源建议使用 2 倍或 3 倍图优先级高于文字content?: string|string[] // 水印文字内容color?: string // 字体颜色fontSize?: number // 字体大小fontWeight?: normal|light|weight|number // 字体粗细fontFamily?: string // 字体类型fontStyle?: none|normal|italic|oblique // 字体样式gap?: [number, number] // 水印之间的间距offset?: [number, number] // 水印距离容器左上角的偏移量默认为 gap/2 } const props withDefaults(definePropsProps(), {width: undefined,height: undefined,rotate: -22,zIndex: 9,image: undefined,content: ,color: rgba(0,0,0,.15),fontSize: 16,fontWeight: normal,fontFamily: sans-serif,fontStyle: normal,gap: () [100, 100],offset: () [50, 50] }) /*** Base size of the canvas, 1 for parallel layout and 2 for alternate layout* Only alternate layout is currently supported*/ const BaseSize 2 const FontGap 3 // 和 ref() 不同浅层 ref 的内部值将会原样存储和暴露并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。 const containerRef shallowRef() // ref() 的浅层作用形式 const watermarkRef shallowRef() const stopObservation shallowRef(false) const gapX computed(() props.gap?.[0] ?? 100) const gapY computed(() props.gap?.[1] ?? 100) const gapXCenter computed(() gapX.value / 2) const gapYCenter computed(() gapY.value / 2) const offsetLeft computed(() props.offset?.[0] ?? gapXCenter.value) const offsetTop computed(() props.offset?.[1] ?? gapYCenter.value) const markStyle computed(() {const markStyle: CSSProperties {zIndex: props.zIndex ?? 9,position: absolute,left: 0,top: 0,width: 100%,height: 100%,pointerEvents: none,backgroundRepeat: repeat}/** Calculate the style of the offset */let positionLeft offsetLeft.value - gapXCenter.valuelet positionTop offsetTop.value - gapYCenter.valueif (positionLeft 0) {markStyle.left \({positionLeft}pxmarkStyle.width calc(100% - \){positionLeft}px)positionLeft 0}if (positionTop 0) {markStyle.top \({positionTop}pxmarkStyle.height calc(100% - \){positionTop}px)positionTop 0}markStyle.backgroundPosition \({positionLeft}px \){positionTop}pxreturn markStyle }) const destroyWatermark () {if (watermarkRef.value) {watermarkRef.value.remove()watermarkRef.value undefined} } const appendWatermark (base64Url: string, markWidth: number) {if (containerRef.value watermarkRef.value) {stopObservation.value truewatermarkRef.value.setAttribute(style,getStyleStr({…markStyle.value,backgroundImage: url(\({base64Url}),backgroundSize: \){(gapX.value markWidth) * BaseSize}px}))containerRef.value?.append(watermarkRef.value)// Delayed executionsetTimeout(() {stopObservation.value false})} } // converting camel-cased strings to be lowercase and link it with Separato function toLowercaseSeparator(key: string) {return key.replace(/([A-Z])/g, -\(1).toLowerCase() } function getStyleStr(style: CSSProperties): string {return Object.keys(style).map((key: any) \){toLowercaseSeparator(key)}: \({style[key]};).join( ) } /*Get the width and height of the watermark. The default values are as followsImage: [120, 64]; Content: Its calculated by content */ const getMarkSize (ctx: CanvasRenderingContext2D) {let defaultWidth 120let defaultHeight 64const content props.contentconst image props.imageconst width props.widthconst height props.heightconst fontSize props.fontSizeconst fontFamily props.fontFamilyif (!image ctx.measureText) {ctx.font \){Number(fontSize)}px \({fontFamily}const contents Array.isArray(content) ? content : [content]const widths contents.map(item ctx.measureText(item!).width)defaultWidth Math.ceil(Math.max(...widths))defaultHeight Number(fontSize) * contents.length (contents.length - 1) * FontGap}return [width ?? defaultWidth, height ?? defaultHeight] as const } // Returns the ratio of the devices physical pixel resolution to the css pixel resolution function getPixelRatio () {return window.devicePixelRatio || 1 } const fillTexts (ctx: CanvasRenderingContext2D,drawX: number,drawY: number,drawWidth: number,drawHeight: number, ) {const ratio getPixelRatio()const content props.contentconst fontSize props.fontSizeconst fontWeight props.fontWeightconst fontFamily props.fontFamilyconst fontStyle props.fontStyleconst color props.colorconst mergedFontSize Number(fontSize) * ratioctx.font \){fontStyle} normal \({fontWeight} \){mergedFontSize}px/\({drawHeight}px \){fontFamily}ctx.fillStyle colorctx.textAlign centerctx.textBaseline topctx.translate(drawWidth / 2, 0)const contents Array.isArray(content) ? content : [content]contents?.forEach((item, index) {ctx.fillText(item ?? , drawX, drawY index * (mergedFontSize FontGap * ratio))}) } const renderWatermark () {const canvas document.createElement(canvas)const ctx canvas.getContext(2d)const image props.imageconst rotate props.rotate ?? -22if (ctx) {if (!watermarkRef.value) {watermarkRef.value document.createElement(div)}const ratio getPixelRatio()const [markWidth, markHeight] getMarkSize(ctx)const canvasWidth (gapX.value markWidth) * ratioconst canvasHeight (gapY.value markHeight) * ratiocanvas.setAttribute(width, \({canvasWidth * BaseSize}px)canvas.setAttribute(height, \){canvasHeight * BaseSize}px)const drawX (gapX.value * ratio) / 2const drawY (gapY.value * ratio) / 2const drawWidth markWidth * ratioconst drawHeight markHeight * ratioconst rotateX (drawWidth gapX.value * ratio) / 2const rotateY (drawHeight gapY.value * ratio) / 2/** Alternate drawing parameters */const alternateDrawX drawX canvasWidthconst alternateDrawY drawY canvasHeightconst alternateRotateX rotateX canvasWidthconst alternateRotateY rotateY canvasHeightctx.save()rotateWatermark(ctx, rotateX, rotateY, rotate)if (image) {const img new Image()img.onload () {ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight)/** Draw interleaved pictures after rotation */ctx.restore()rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight)appendWatermark(canvas.toDataURL(), markWidth)}img.crossOrigin anonymousimg.referrerPolicy no-referrerimg.src image} else {fillTexts(ctx, drawX, drawY, drawWidth, drawHeight)/** Fill the interleaved text after rotation */ctx.restore()rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight)appendWatermark(canvas.toDataURL(), markWidth)}} } // Rotate with the watermark as the center point function rotateWatermark(ctx: CanvasRenderingContext2D,rotateX: number,rotateY: number,rotate: number ) {ctx.translate(rotateX, rotateY)ctx.rotate((Math.PI / 180) * Number(rotate))ctx.translate(-rotateX, -rotateY) } onMounted(() {renderWatermark() }) watch(() [props],() {renderWatermark()},{deep: true, // 强制转成深层侦听器flush: post // 在侦听器回调中访问被 Vue 更新之后的 DOM}, ) onBeforeUnmount(() {destroyWatermark() }) // Whether to re-render the watermark const reRendering (mutation: MutationRecord, watermarkElement?: HTMLElement) {let flag false// Whether to delete the watermark nodeif (mutation.removedNodes.length) {flag Array.from(mutation.removedNodes).some(node node watermarkElement)}// Whether the watermark dom property value has been modifiedif (mutation.type attributes mutation.target watermarkElement) {flag true}return flag } const onMutate (mutations: MutationRecord[]) {if (stopObservation.value) {return}mutations.forEach(mutation {if (reRendering(mutation, watermarkRef.value)) {destroyWatermark()renderWatermark()}}) } const defaultWindow typeof window ! undefined ? window : undefined type Fn () void function tryOnMounted(fn: Fn, sync true) {if (getCurrentInstance()) onMounted(fn)else if (sync) fn()else nextTick(fn) } function useSupported(callback: () unknown, sync false) {const isSupported shallowRefboolean()const update () (isSupported.value Boolean(callback()))update()tryOnMounted(update, sync)return isSupported } function useMutationObserver(target: any,callback: MutationCallback,options: any, ) {const { window defaultWindow, …mutationOptions } optionslet observer: MutationObserver | undefinedconst isSupported useSupported(() window MutationObserver in window)const cleanup () {if (observer) {observer.disconnect()observer undefined}}const stopWatch watch(() unref(target),el {cleanup()if (isSupported.value window el) {observer new MutationObserver(callback)observer!.observe(el, mutationOptions)}},{ immediate: true })const stop () {cleanup()stopWatch()}tryOnScopeDispose(stop)return {isSupported,stop} } function tryOnScopeDispose(fn: Fn) {if (getCurrentScope()) {onScopeDispose(fn)return true}return false } useMutationObserver(containerRef, onMutate, {attributes: true // 观察所有监听的节点属性值的变化 }) /script templatediv refcontainerRef styleposition: relative;slot/slot/div /template在要使用的页面引入 script setup langts import Watermark from ./Watermark.vue import { reactive } from vue const model reactive({content: Vue Amazing UI,color: rgba(0,0,0,.15),fontSize: 16,fontWeight: 400,zIndex: 9,rotate: -22,gap: [100, 100] as [number, number],offset: [] }) /script templatedivh1Watermark 水印/h1h2 classmt30 mb10基本使用/h2Watermark contentVue Amazing UIdiv styleheight: 360px //Watermarkh2 classmt30 mb10多行水印/h2h3 classmb10通过 content 设置 字符串数组 指定多行文字水印内容。/h3Watermark :content[Vue Amazing UI, Hello World]div styleheight: 400px //Watermarkh2 classmt30 mb10图片水印/h2h3 classmb10通过 image 指定图片地址。为保证图片高清且不被拉伸请设置 width 和 height, 并上传至少两倍的宽高的 logo 图片地址。/h3Watermark:height30:width130imagehttps://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*lkAoRbywo0oAAAAAAAAAAAAADrJ8AQ/originaldiv styleheight: 360px //Watermarkh2 classmt30 mb10自定义配置/h2h3 classmb10通过自定义参数配置预览水印效果。/h3FlexWatermark v-bindmodelp classu-paragraphThe light-speed iteration of the digital world makes products more complex. However, humanconsciousness and attention resources are limited. Facing this design contradiction, thepursuit of natural interaction will be the consistent direction of Ant Design./pp classu-paragraphNatural user cognition: According to cognitive psychology, about 80% of externalinformation is obtained through visual channels. The most important visual elements in theinterface design, including layout, colors, illustrations, icons, etc., should fullyabsorb the laws of nature, thereby reducing the userapos;s cognitive cost and bringingauthentic and smooth feelings. In some scenarios, opportunely adding other sensorychannels such as hearing, touch can create a richer and more natural product experience./pp classu-paragraphNatural user behavior: In the interaction with the system, the designer should fullyunderstand the relationship between users, system roles, and task objectives, and alsocontextually organize system functions and services. At the same time, a series of methodssuch as behavior analysis, artificial intelligence and sensors could be applied to assistusers to make effective decisions and reduce extra operations of users, to saveusersapos; mental and physical resources and make human-computer interaction morenatural./pimgstyle position: relative; z-index: 1; width: 100%; max-width: 800px;srchttps://cdn.jsdelivr.net/gh/themusecatcher/resources0.0.3⁄6.jpgalt示例图片//WatermarkFlexstylewidth: 25%;flex-shrink: 0;border-left: 1px solid #eee;padding-left: 20px;margin-left: 20px;verticalgapmiddlepContent/pInput v-model:valuemodel.content /pColor/pInput v-model:valuemodel.color /pFontSize/pSlider v-model:valuemodel.fontSize :step1 :min0 :max100 /pFontWeight/pInputNumber v-model:valuemodel.fontWeight :step100 :min100 :max1000 /pzIndex/pSlider v-model:valuemodel.zIndex :step1 :min0 :max100 /pRotate/pSlider v-model:valuemodel.rotate :step1 :min-180 :max180 /pGap/pSpace styledisplay: flex alignbaselineInputNumber v-model:valuemodel.gap[0] placeholdergapX /InputNumber v-model:valuemodel.gap[1] placeholdergapY //SpacepOffset/pSpace styledisplay: flex alignbaselineInputNumber v-model:valuemodel.offset[0] placeholderoffsetLeft /InputNumber v-model:valuemodel.offset[1] placeholderoffsetTop //Space/Flex/Flex/div /template style .u-paragraph {margin-bottom: 1em;color: rgba(0, 0, 0, .88);word-break: break-word;line-height: 1.5714285714285714; } /style
- 上一篇: 风铃网做微网站要钱吗社群运营外包
- 下一篇: 蜂蜜网站建设聚通装潢口碑好不好
相关文章
-
风铃网做微网站要钱吗社群运营外包
风铃网做微网站要钱吗社群运营外包
- 技术栈
- 2026年03月21日
-
丰县住房与城乡建设部网站网页网站怎么做
丰县住房与城乡建设部网站网页网站怎么做
- 技术栈
- 2026年03月21日
-
丰台网站开发网页设计与制作的实训报告怎样写
丰台网站开发网页设计与制作的实训报告怎样写
- 技术栈
- 2026年03月21日
-
蜂蜜网站建设聚通装潢口碑好不好
蜂蜜网站建设聚通装潢口碑好不好
- 技术栈
- 2026年03月21日
-
冯站长之家官网携程网站 建设平台分析
冯站长之家官网携程网站 建设平台分析
- 技术栈
- 2026年03月21日
-
凤城市网站建设临沂品牌网站制作
凤城市网站建设临沂品牌网站制作
- 技术栈
- 2026年03月21日






