国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

這篇具有很好參考價值的文章主要介紹了記錄--Vue3 + Fabricjs 定制國慶專屬頭像。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

這里給大家分享我在網(wǎng)上總結(jié)出來的一些知識,希望對大家有所幫助

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

生在國旗下,長在春風里!國慶將至,采黎為大家?guī)?定制頭像2.0(國慶頭像),讓我們用代碼的形式為祖國慶生!歡迎大家點贊收藏加關(guān)注哦

前言

想看效果或者想定制春節(jié)頭像的小伙伴請直奔 效果區(qū)域;
想一睹定制頭像2.0小工具的原理及實現(xiàn)思路請耐心閱讀,本文代碼片段較多~

在線定制

?????? 定制頭像入口, 體驗地址 ??????

?????? github項目地址(歡迎?) ??????

喜歡這個小工具的話,動動小手點個star?哦,謝謝!

關(guān)于迭代

定制兔年春節(jié)頭像 上線后,很多小伙伴體驗后第一時間就給了建議、反饋;在大家的幫助下,工具也在不斷的完善;比如導(dǎo)出圖片不夠清晰、不能設(shè)置透明度等等,迭代到1.4.0后,已經(jīng)可以保證正常的使用了,這里采黎給大家說聲謝謝!

由于當時聚焦在兔年、春節(jié)頭像上,工具風格單一,功能還不夠完善,內(nèi)部邏輯有點大材小用等等,于是便有了大版本的定制頭像2.0迭代。

更新內(nèi)容

倉庫名稱

  • custom-rabbitImage 改為 custom-avatar

頁面

  • 重構(gòu)頁面整體風格,調(diào)整為通用型風格
  • 兼容pc、移動端
  • 移動端頭像墻采用瀑布流

畫布相關(guān)

  • 用戶上傳的原圖做短邊適配,保證不變形
  • 優(yōu)化元素控件效果,增加刪除控件
  • 優(yōu)化繪制邏輯,減少無用運算。

新增功能

  • 增加多主題選項(中秋節(jié)、國慶節(jié)、春節(jié)等,其他傳統(tǒng)節(jié)日敬請期待)
  • 增加貼紙效果,可多選、可刪除
  • 增加快速切換頭像框功能
  • 增加通知功能(xx用戶在3分鐘前定制了國慶頭像)
  • 增加分享海報功能
  • 增加頭像墻功能,用戶可預(yù)覽他人定制的頭像

修復(fù)已知問題

  • 修復(fù)qq瀏覽器無法選擇文件
  • 修復(fù)微信瀏覽器無法保存圖片

項目架構(gòu)

vue3 | vite | ts | less | Elemenu UI | eslint | stylelint | husky | lint-staged | commitlint

所需素材

頭像框、貼紙正在設(shè)計中,會一點一點補起來。

中秋主題

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

國慶主題

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

春節(jié)主題

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

思路

基本思路不變,定制兔年春節(jié)頭像中已經(jīng)講過,這里就不再贅述了。

畫布交互邏輯優(yōu)化

這是第一版的邏輯梳理

記錄--Vue3 + Fabricjs 定制國慶專屬頭像

考慮到定制頭像工具圖層不會過多,功能不會太復(fù)雜,于是 在新版中做了如下優(yōu)化

  • 刪除繪制多個圖層邏輯(監(jiān)聽圖層列表變化,進而繪制圖層)
  • 繪制頭像框改為主動調(diào)用,減少無用調(diào)用頻次;
  • 繪制貼紙為主動調(diào)用,可繪制多個
  • 刪除畫布操作同步邏輯(不需要回顯數(shù)據(jù)到頁面,也不用二次繪制,故刪除)

做完上述優(yōu)化后,代碼量明顯下來了;只怪當時沒有過多的思考,就將其他項目的實現(xiàn)方式生搬硬套了。

代碼實現(xiàn)

畫布

  1. 初始化畫布及控件
const init = () => {
    /* 初始化控件 */
    initFabricControl()

    /* 初始化畫布 */
    Canvas = initCanvas(CanvasId.value, canvasSize, false)

    // 元素縮放事件
    Canvas.on('object:scaling', canvasMouseScaling)
}


/* 初始化控件 */
const initFabricControl = () => {
    fabric.Object.prototype.set(control)
    // 設(shè)置縮放搖桿偏移
    fabric.Object.prototype.controls.mtr.offsetY = control.mtrOffsetY
    // 隱藏不需要的控件
    hiddenControl.map((name: string) => (fabric.Object.prototype.controls[name].visible = false))

    /* 添加刪除控件 */
    const delImgElement = document.createElement('img')
    delImgElement.src = new URL('./icons/delete.png', import.meta.url).href

    const size = 52

    const deleteControlHandel = (e, transform:any) => {
        const target = transform.target
        const canvas = target.canvas
        canvas.remove(target).renderAll()
    }

    const renderDeleteIcon = (ctx:any, left:any, top:any, styleOverride:any, fabricObject:any) => {
        ctx.save()
        ctx.translate(left, top)
        ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle))
        ctx.drawImage(delImgElement, -size / 2, -size / 2, size, size)
        ctx.restore()
    }

    fabric.Object.prototype.controls.deleteControl = new fabric.Control({
        x: 0.5,
        y: -0.5,
        cornerSize: size,
        offsetY: -48,
        offsetX: 48,
        cursorStyle: 'pointer',
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        mouseUpHandler: deleteControlHandel,
        render: renderDeleteIcon
    })
}
  1. 監(jiān)聽原圖(用戶上傳的頭像)改變,并進行短邊適配
/* 更改原圖 */
watch(() => props.bg, async (val) => (await drawBackground(Canvas, val)))

/**
 * @function drawBackground 繪制背景
 * @param { Object } Canvas 畫布實例
 * @param { String } bgUrl 用戶上傳得原圖片鏈接
 */
export const drawBackground = async (Canvas, bgUrl: string) => {
    return new Promise((resolve: any) => {
        if (!bgUrl) return resolve()

        fabric.Image.fromURL(bgUrl, (img: any) => {

            img.set({
                left: Canvas.width / 2,
                top: Canvas.height / 2,
                originX: 'center',
                originY: 'center'
            })

            /* 短邊適配 */
            img.width > img.height ? img.scaleToHeight(Canvas.height, true) : img.scaleToWidth(Canvas.width, true)
            Canvas.setBackgroundImage(img, Canvas.renderAll.bind(Canvas))

            resolve()
        }, { crossOrigin: 'Anonymous' })
    })
}
  1. 繪制頭像框,并隱藏刪除按鈕控件
const frameName = 'frame'

/**
 * @function addFrame 添加頭像框圖層
 * @param { String } url 頭像框鏈接
 */
const addFrame = async (url = '') => {
    if (!url) return

    const frameLayer: any = await drawImg(`${ url }!frame`)
    frameLayer.set({
        left: Canvas.width / 2,
        top: Canvas.height / 2
    })

    /* 隱藏刪除按鈕 */
    frameLayer.setControlVisible('deleteControl', false)

    frameLayer.scaleToWidth(Canvas.width, true)

    frameLayer.name = frameName
    addOrReplaceLayer(Canvas, frameLayer)
}
  1. 設(shè)置頭像框透明度
/**
 * @function setFrameOpacity 設(shè)置頭像框透明度
 * @param { Number } opacity 透明度
 */
const setFrameOpacity = (opacity = 1) => {
    const frameLayer: any = findCanvasItem(Canvas, frameName)[1] || ''

    if (!frameLayer) return

    frameLayer.set({ opacity })
    Canvas.renderAll()
}
  1. 繪制貼紙
/**
 * @function addMark 添加貼紙
 * @param { String } url 貼紙鏈接
 */
const addMark = async (url) => {
    if (!url) return

    const markLayer: any = await drawImg(url)
    markLayer.set({
        left: Canvas.width / 2,
        top: Canvas.height / 2
    })

    markLayer.width > markLayer.height ? markLayer.scaleToHeight(200, true) : markLayer.scaleToWidth(200, true)

    markLayer.name = `mark-${ createUuid() }`
    addOrReplaceLayer(Canvas, markLayer)
}
  1. 保存圖片,導(dǎo)出base64
/**
 * @function save 保存效果圖
 * @return { String } result base64 保存/預(yù)覽時返回
 */
const save = async (): Promise<string> => {
    return Canvas.toDataURL({
        format: 'png',
        left: 0,
        top: 0,
        width: Canvas.width,
        height: Canvas.height
    })
}

現(xiàn)在代碼明朗了很多,猶如柳暗花明。

頁面交互

  1. 用戶上傳圖片,生成本地短鏈,然后繪制原頭像,并默認繪制第一個頭像框。
const uploadFile = async (e: any) => {
    if (!e.target.files || !e.target.files.length) return ElMessage.warning('上傳失??!')

    const file = e.target.files[0]
    if (!file.type.includes('image')) return ElMessage.warning('請上傳正確的圖片格式!')

    const url = getCreatedUrl(file) ?? ''
    /* 用戶初次上傳頭像默認選中第一個頭像框 */
    if (!originAvatarUrl.value) {
        originAvatarUrl.value = url
        selectFrame(0)
    } else {
        originAvatarUrl.value = url
    }

    (document.getElementById('uploadImg') as HTMLInputElement).value = ''
}
  1. 用戶點擊頭像框或點擊快速切換按鈕,繪制頭像框
/* 快速切換頭像框 */
const changeFrame = (isNext) => {
    if (!originAvatarUrl.value) return ElMessage.warning('請先上傳頭像!')

    const frameList =  picList[styleIndex.value].frameList
    if (isNext) {
        (selectFrameIndex.value === frameList.length - 1) ? selectFrameIndex.value = 0 : (selectFrameIndex.value as number)++
    } else {
        (selectFrameIndex.value === 0) ? selectFrameIndex.value = frameList.length - 1 : (selectFrameIndex.value as number)--
    }
    selectFrame(selectFrameIndex.value as number)
}

/* 繪制頭像框-調(diào)用畫布繪制函數(shù) */
const selectFrame = (index: number) => {
    if (!originAvatarUrl.value) return ElMessage.warning('請先上傳頭像!')

    opacity.value = 1
    selectFrameIndex.value = index
    frameUrl.value = picList[styleIndex.value].frameList[index]
    DrawRef.value.addFrame(frameUrl.value)
}
  1. 設(shè)置頭像框透明度
const opacity = ref<number>(1)
const opacityChange = (num: number) => DrawRef.value.setFrameOpacity(num)
  1. 點擊貼紙,繪制貼紙
const selectMark = (index: number) => {
    if (!originAvatarUrl.value) return ElMessage.warning('請先上傳頭像!')

    const markUrl = picList[styleIndex.value].markList[index]
    DrawRef.value.addMark(markUrl)
}

頁面的交互邏輯相對簡單,一步一步走就ok。

滾動通知動畫效果

這里使用vue的過渡動畫,模擬了滾動的效果, 本質(zhì)就是key變了后,會觸發(fā)彈入彈出效果。

<transition name="notice" mode="out-in">
    <div v-if="avatarList && avatarList.length" class="notice" :key="avatarList[noticeIndex].last_modified">
        <p>
            <span style="color: #409eff;">游客{{ (avatarList[noticeIndex].last_modified + '').slice(-5) }} </span>
            <span style="padding-left: 2px;">{{ calcOverTime(avatarList[noticeIndex].last_modified) }}前</span>
            <span style="padding-right: 2px;">制作了</span>
            <span style="color: #f56c6c;">{{ styleEnums[avatarList[noticeIndex].id] }}頭像 </span>
            <span style="padding-left: 4px;"></span>
        </p>
        <img :src="avatarList[noticeIndex].url" alt="">
    </div>
</transition>

海報功能

這個用html2canvas庫就好了,用正常的css屬性,他都可以實現(xiàn)。

<!-- 生成海報 -->
<div id="poster" class="poster">
    <!-- 內(nèi)容省略 -->
</div>
/* 注意圖片跨域 */
await nextTick(() => {
    /* 生成海報 */
    const posterDom = document.getElementById('poster') as HTMLElement
    html2canvas(posterDom, { useCORS: true }).then((canvas) => {
        shareUrl.value = canvas.toDataURL('image/png')
        shareShow.value = true
        loading.value = false
    })
})

移動端瀑布流實現(xiàn)

pc和移動端都是grid布局,我們給移動端的行列份數(shù)隨機,pc端強制設(shè)為1,保證行、列所占的份數(shù)一致就好(定制頭像導(dǎo)出都是正方形的)

grid-auto-flow: dense;?這個樣式是關(guān)鍵,

<div class="wall">
    <div class="wall-list">
        <el-image v-for="(url, index) in avatarPageUrlList" :key="url" :src="url" 
        :style="{ gridColumn: `span ${ avatarList[index].span}`, gridRow: `span ${ avatarList[index].span }` }" />
    </div>
</div>
.wall {
    .wall-list {
        display: grid;
        gap: 8px;
        grid-template-columns: repeat(8, minmax(0, 1fr));
        grid-auto-flow: dense;
    }

    .wall-more {
        padding-top: 16px;
        text-align: center;
    }
}

/* pc端不使用瀑布流,強覆蓋行列份數(shù) */
@media only screen and (min-width: 769px) {
    .wall {
        .wall-list {
            > div {
                grid-row: span 1 !important;
                grid-column: span 1 !important;
            }
        }
    }
}

到這里,基本核心、細節(jié)的點都實現(xiàn)了;若想知道更多代碼設(shè)計、開發(fā)思路,請移步github,代碼已開源。

本文轉(zhuǎn)載于:

https://juejin.cn/post/7283018190594572328

如果對您有所幫助,歡迎您點個關(guān)注,我會定時更新技術(shù)文檔,大家一起討論學習,一起進步。

?記錄--Vue3 + Fabricjs 定制國慶專屬頭像文章來源地址http://www.zghlxwxcb.cn/news/detail-710178.html

到了這里,關(guān)于記錄--Vue3 + Fabricjs 定制國慶專屬頭像的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 【定制小程序:開啟你的專屬數(shù)字化之旅】

    在當今數(shù)字化的時代,擁有一個定制的小程序已成為企業(yè)和個人展示個性、提升服務(wù)的必要手段。本文將為你詳細介紹定制小程序開發(fā)的優(yōu)勢、流程以及如何選擇合適的開發(fā)團隊。 一、定制小程序開發(fā)的優(yōu)勢 個性化定制:根據(jù)你的需求和品牌特色,打造獨一無二的小程序。

    2024年01月21日
    瀏覽(19)
  • ChatGPT神奇應(yīng)用:定制化學習體驗,get專屬家教

    ChatGPT神奇應(yīng)用:定制化學習體驗,get專屬家教

    正文共? 601? 字,閱讀大約需要? 2? 分鐘 面向所有有學習需求的人群,您將在2分鐘后獲得以下超能力: 1、獲取定制化學習體驗 2、全面了解任何想學習的科目 Beezy評級?:B級 *經(jīng)過簡單的尋找, 大部分人能立刻掌握。主要節(jié)省時間。 推薦人? |?Alice ? 編輯者? |? Linda ●此

    2024年02月11日
    瀏覽(19)
  • 超實用的 IPTV 管理工具,xTeVe 助你定制專屬電視頻道。

    超實用的 IPTV 管理工具,xTeVe 助你定制專屬電視頻道。

    雖然現(xiàn)在視頻流媒體點播平臺已經(jīng)成為了大家主要的影音娛樂渠道,似乎沒什么人看電視了,但我想需求還是在的,比如家里的長輩可能就不太會操作點播平臺,他們比較習慣傳統(tǒng)的直播電視,再比如新聞或者體育賽事,這類節(jié)目可能還是需要看直播,有時候放個電視節(jié)目當

    2024年01月17日
    瀏覽(28)
  • AnythingLLM:基于RAG方案構(gòu)專屬私有知識庫(開源|高效|可定制)

    AnythingLLM:基于RAG方案構(gòu)專屬私有知識庫(開源|高效|可定制)

    繼OpenAI和Google的產(chǎn)品發(fā)布會之后,大模型的能力進化速度之快令人驚嘆,然而,對于很多個人和企業(yè)而言,為了數(shù)據(jù)安全不得不考慮私有化部署方案,從GPT-4發(fā)布以來,國內(nèi)外的大模型就拉開了很明顯的差距,能夠?qū)崿F(xiàn)的此路徑無非就只剩下國內(nèi)的開源大模型可以選擇了。而

    2024年02月04日
    瀏覽(23)
  • 阿里首提前向訓練框架:讓大模型深度思考,可快速定制專屬模型

    大語言模型(LLM)是當前自然語言處理領(lǐng)域最核心的技術(shù),以 GPT-4 為代表的大語言模型展現(xiàn)出了類人的學習能力。其中,情境學習(In-context Learning)是大語言模型最神秘的能力之一。如下圖所示,在這種情境學習的范式下,大模型無需更新任何參數(shù),僅依賴幾個示例樣本(demonstrations)就可以學習新任務(wù),執(zhí)行新樣本的預(yù)測。

    2024年02月11日
    瀏覽(20)
  • 想要定制專屬AI聲音?這是一份來自微軟的保姆級攻略

    想要定制專屬AI聲音?這是一份來自微軟的保姆級攻略

    得益于AI技術(shù)的發(fā)展,合成聲音已經(jīng)能媲美人聲。而聲音定制服務(wù)的出現(xiàn)使得越來越多的企業(yè)和個人可以擁有個性化的獨特AI聲音。通常這種AI音色的定制需要采集人類配音員(發(fā)音人)的聲音數(shù)據(jù)作為AI機器學習的對象,因此,個性化的聲音定制又稱為“聲音復(fù)刻”,或者“

    2024年02月07日
    瀏覽(18)
  • 微火:AI繪圖網(wǎng)站程序源碼搭建,定制專屬的ai繪畫小程序

    微火:AI繪圖網(wǎng)站程序源碼搭建,定制專屬的ai繪畫小程序

    隨著AI繪畫的火熱,群眾對于AI繪畫的需求與日俱增,目前已有的小程序、ai繪圖軟件已不能很好地滿足當下用戶的畫圖需求,經(jīng)常排隊生圖,一排就是幾個小時,或者前面直接8萬人排隊的現(xiàn)象早日屢見不鮮。 新的優(yōu)秀的AI繪畫小程序急待出爐。 做ai繪畫程序,除了應(yīng)對當下龐

    2024年02月02日
    瀏覽(18)
  • 寵物賽道,用AI定制寵物頭像搞錢項目教程

    寵物賽道,用AI定制寵物頭像搞錢項目教程

    今天給大家介紹一個非常有趣,而粉絲價值又極高,用AI去定制寵物頭像或合照的AI項目。 接觸過寵物行業(yè)應(yīng)該知道,獲取1位鏟屎官到私域,這類用戶的價值是極高的,一個寵物粉,是連鏟個屎都要花錢的,每年在寵物身上投入的錢在4-5位數(shù)。 假如她還愿給自己的寵物來做頭

    2024年02月11日
    瀏覽(25)
  • 上傳圖片到騰訊云對象存儲桶cos 【騰訊云對象存儲桶】【cos】【el-upload】【vue3】【上傳頭像】【刪除】

    上傳圖片到騰訊云對象存儲桶cos 【騰訊云對象存儲桶】【cos】【el-upload】【vue3】【上傳頭像】【刪除】

    1、首先登錄騰訊云官網(wǎng)控制臺 進入對象存儲頁面 2、找到跨越訪問CIRS設(shè)置 配置規(guī)則 ?點擊添加規(guī)則 ?填寫信息 ?3、書寫代碼 這里用VUE3書寫 第一種用按鈕出發(fā)事件形式 4、測試 點擊選擇文件 選擇圖片? 等待結(jié)果 ? 第二種用el-upload 也可以把el-upload嵌套button包裝成這種形式

    2024年02月15日
    瀏覽(88)
  • 【Vue】fabricjs 實現(xiàn)局部截圖及el-image-viewer大圖預(yù)覽

    【Vue】fabricjs 實現(xiàn)局部截圖及el-image-viewer大圖預(yù)覽

    效果圖: 再結(jié)合el-image-viewer可以實現(xiàn)大圖預(yù)覽局部圖的效果。

    2024年02月22日
    瀏覽(17)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包