vue3中使用live2D

概述

本文将介绍如何在vue3项目中使用Live2D

Live2D 介绍

Live2D 是什么

Live2D 是一种用于将二维图像转化为可动画三维模型的技术,主要应用于游戏、虚拟角色和互动应用中。它允许开发者通过对静态图像进行分层和建模,使角色在不同角度下能够进行流畅的动作和表情变化。

Live2D 主要特点

  • 动态表现:Live2D 可以让角色在不改变原始图像的情况下,实现多种动作和表情,例如眨眼、微笑、转头等。

  • 用户交互:它可以与用户的输入进行互动,比如鼠标移动或触摸屏幕时,角色会作出相应的反馈。

  • 应用广泛:被广泛应用于手机游戏、动画、虚拟直播、社交软件等领域。

  • 易于使用:通过 Live2D 提供的工具(如 Live2D Cubism),艺术家可以方便地创建和编辑模型,无需深入的编程知识。

Live2D 效果

在这里插入图片描述

vue3 中使用 Live2D

如果前端项目是用vite搭建,则需要在index.html中引入live2d.min.js库,因为在 vue 组件中引入会报错。

封装 Live 组件

template

template部分如下:

<template><div:class="{'vue-live2d': true,'vue-live2d-on-left': true,// 'vue-live2d-on-right': direction === 'right',}":style="{width: `300px`,height: `300px`,position: 'absolute',left: '10px',bottom: '20px',}"@mouseover="openLive2dTool"@mouseout="closeLive2dTool"><divv-show="true"v-html="data.tipText":class="{'vue-live2d-tip': true,'vue-live2d-tip-on-top': true,// 'vue-live2d-tip-on-bottom': tipPosition === 'bottom',}"></div><canvas:id="customId"v-show="mainShow":class="{'vue-live2d-main': true,'vue-live2d-main-on-left': true,// 'vue-live2d-main-on-right': direction === 'right',}"width="300"height="300"></canvas><div v-show="toolShow" class="vue-live2d-tool"><spanv-for="(tool, index) in tools":key="index":class="tool.className"v-html="tool.svg"@click="tool.click"/></div><divv-show="toggleShow"@click="openLive2dMain":class="{'vue-live2d-toggle': true,'vue-live2d-toggle-on-left': true,// 'vue-live2d-toggle-on-right': direction === 'right',}"><span>Kanban girl</span></div></div>
</template>

template部分主要是定义 UI 部分,以及绑定界面点击和hove的事件,Live2d的模型是在 canvas 中绘制的。

核心逻辑
核心逻辑主要就是加载Live2D的模型以及定义事件,其实现如下:

<script setup>
import { onMounted, nextTick, ref, computed } from "vue";import tips from "./options/tips";// const model = ["Potion-Maker/Pio", "school-2017-costume-yellow"];
const model = ["ShizukuTalk/shizuku-48", "default"];const apiPath = "https://evgo2017.com/api/live2d-static-api/indexes";let [modelPath, modelTexturesId] = model;const customId = "vue-live2d-main";let messageTimer = null;const data = ref({containerDisplay: {tip: false,main: true,tool: false,toggle: false,},tipText: "vue-live2d Kanban girl",modelTexturesId: modelTexturesId,
});const changeLive2dSize = () => {document.querySelector(`#${customId}`).outerHTML = `<canvas id=${customId} width="300" height="300" class="vue-live2d-main"></canvas>`;loadModel();
};const loadModel = () => {window.loadlive2d(customId,`${apiPath}/${modelPath}/${data.value.modelTexturesId}.json`);console.log(`Live2D 模型 ${modelPath},服装 ${data.value.modelTexturesId} 加载完成`);
};const loadRandModel = () => {http({url: `${apiPath}/models.json`,success: (data) => {const models = data.filter(({ modelPath: i }) => i !== modelPath);const { modelPath: j, modelIntroduce } =models[Math.floor(Math.random() * models.length)];modelPath = j;showMessage(`${modelIntroduce}`, 4000);loadRandTextures(true);},});
};const loadRandTextures = (isAfterRandModel = false) => {http({url: `${apiPath}/${modelPath}/textures.json`,success: (resp) => {const modelTexturesIds = resp.filter((modelTexturesId) => modelTexturesId !== data.value.modelTexturesId);data.value.modelTexturesId =modelTexturesIds[Math.floor(Math.random() * modelTexturesIds.length)];loadModel();if (!isAfterRandModel) {showMessage("我的新衣服好看嘛?", 4000);}},});
};const showMessage = (msg = "", timeout = 6000) => {if (messageTimer) {clearTimeout(messageTimer);messageTimer = null;} else {data.value.containerDisplay.tip = true;}data.value.tipText = msg;messageTimer = setTimeout(() => {data.value.containerDisplay.tip = false;messageTimer = null;}, timeout);
};const takePhoto = () => {showMessage("照好了嘛,留个纪念吖~");window.Live2D.captureName = "photo.png";window.Live2D.captureFrame = true;
};const showHitokoto = () => {http({url: "https://v1.hitokoto.cn",success: ({ hitokoto, id, creator, from }) => {showMessage(`${hitokoto} <br> - by <a href="https://hitokoto.cn?id=${id}">${creator}</a> from 《${from} 》`);},});
};const closeLive2dMain = () => {data.value.containerDisplay.main = false;
};const openLive2dMain = () => {data.value.containerDisplay.main = true;
};
const closeLive2dTool = () => {data.value.containerDisplay.tool = false;
};
const openLive2dTool = () => {data.value.containerDisplay.tool = true;
};
const loadEvent = () => {for (const event in tips) {for (const { selector, texts } of tips[event]) {const dom =selector === "document" ? document : document.querySelector(selector);if (dom == null) {continue;}dom.addEventListener(event, () => {const msg = texts[Math.floor(Math.random() * texts.length)];showMessage(msg, 2000);});}}
};
const http = ({ url, success }) => {const xhr = new XMLHttpRequest();xhr.onreadystatechange = function () {if (xhr.readyState === 4) {if (xhr.status >= 200 || xhr.status < 300 || xhr.status === 304) {success && xhr.response && success(JSON.parse(xhr.response));} else {console.error(xhr);}}};xhr.open("GET", url);xhr.send(null);
};nextTick(() => {loadEvent();
});
onMounted(() => {loadModel();
});defineProps({tips: {default: () => tips,type: Object,},width: {default: 0,type: Number,},height: {default: 0,type: Number,},size: {default: 255,type: Number,},
});const tipShow = computed(() => {return mainShow && data.value.containerDisplay.tip;
});const mainShow = computed(() => {return data.value.containerDisplay.main;
});const toolShow = computed(() => {return mainShow && data.value.containerDisplay.tool;
});const toggleShow = computed(() => {return !mainShow;
});const tools = ref([{className: "custom-fa-comment",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M256 32C114.6 32 0 125.1 0 240c0 49.6 21.4 95 57 130.7C44.5 421.1 2.7 466 2.2 466.5c-2.2 2.3-2.8 5.7-1.5 8.7S4.8 480 8 480c66.3 0 116-31.8 140.6-51.4 32.7 12.3 69 19.4 107.4 19.4 141.4 0 256-93.1 256-208S397.4 32 256 32z"/></svg>',click: showHitokoto,},{className: "custom-fa-user-circle",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 96c48.6 0 88 39.4 88 88s-39.4 88-88 88-88-39.4-88-88 39.4-88 88-88zm0 344c-58.7 0-111.3-26.6-146.5-68.2 18.8-35.4 55.6-59.8 98.5-59.8 2.4 0 4.8.4 7.1 1.1 13 4.2 26.6 6.9 40.9 6.9 14.3 0 28-2.7 40.9-6.9 2.3-.7 4.7-1.1 7.1-1.1 42.9 0 79.7 24.4 98.5 59.8C359.3 421.4 306.7 448 248 448z"/></svg>',click: loadRandModel,},{className: "custom-fa-street-view",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M367.9 329.76c-4.62 5.3-9.78 10.1-15.9 13.65v22.94c66.52 9.34 112 28.05 112 49.65 0 30.93-93.12 56-208 56S48 446.93 48 416c0-21.6 45.48-40.3 112-49.65v-22.94c-6.12-3.55-11.28-8.35-15.9-13.65C58.87 345.34 0 378.05 0 416c0 53.02 114.62 96 256 96s256-42.98 256-96c0-37.95-58.87-70.66-144.1-86.24zM256 128c35.35 0 64-28.65 64-64S291.35 0 256 0s-64 28.65-64 64 28.65 64 64 64zm-64 192v96c0 17.67 14.33 32 32 32h64c17.67 0 32-14.33 32-32v-96c17.67 0 32-14.33 32-32v-96c0-26.51-21.49-48-48-48h-11.8c-11.07 5.03-23.26 8-36.2 8s-25.13-2.97-36.2-8H208c-26.51 0-48 21.49-48 48v96c0 17.67 14.33 32 32 32z"/></svg>',click: loadRandTextures,},{className: "custom-fa-camera-retro",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M48 32C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h416c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48H48zm0 32h106c3.3 0 6 2.7 6 6v20c0 3.3-2.7 6-6 6H38c-3.3 0-6-2.7-6-6V80c0-8.8 7.2-16 16-16zm426 96H38c-3.3 0-6-2.7-6-6v-36c0-3.3 2.7-6 6-6h138l30.2-45.3c1.1-1.7 3-2.7 5-2.7H464c8.8 0 16 7.2 16 16v74c0 3.3-2.7 6-6 6zM256 424c-66.2 0-120-53.8-120-120s53.8-120 120-120 120 53.8 120 120-53.8 120-120 120zm0-208c-48.5 0-88 39.5-88 88s39.5 88 88 88 88-39.5 88-88-39.5-88-88-88zm-48 104c-8.8 0-16-7.2-16-16 0-35.3 28.7-64 64-64 8.8 0 16 7.2 16 16s-7.2 16-16 16c-17.6 0-32 14.4-32 32 0 8.8-7.2 16-16 16z"/></svg>',click: takePhoto,},{className: "custom-fa-info-circle",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/></svg>',click: () => {},},{className: "custom-fa-times",svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="-40 -40 432 592" fill="currentColor" height="20px" width="20px"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"/></svg>',click: closeLive2dMain,},
]);
</script>

Demo地址

Demo地址和具体示例可参考:https://github.com/Jinuss/maps

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/443689.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系统编程】第二十八弹---构建基础文件操作库与理解标准错误流(stderr)在C与C++中的应用

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、封装简单的库 1.1、定义文件结构 1.2、打开文件 1.3、刷新缓冲区 1.4、写文件 1.5、关闭文件 1.6、各文件代码 2、s…

【element-tiptap】如何增加一个扩展项,为文字渲染颜色?

源码地址&#xff1a; https://github.com/Leecason/element-tiptap 可以看到&#xff0c;当前这个页面的文字&#xff0c;都是黑色的&#xff08;除了链接&#xff09; 酱紫有些单调&#xff0c;我喜欢五颜六色的。那么这篇文章就来看下菜单项里面如何增加一个颜色的扩展&…

k8s微服务

一 、什么是微服务 用控制器来完成集群的工作负载&#xff0c;那么应用如何暴漏出去&#xff1f;需要通过微服务暴漏出去后才能被访问 Service是一组提供相同服务的Pod对外开放的接口。 借助Service&#xff0c;应用可以实现服务发现和负载均衡。 service默认只支持4层负载均…

Springboot 整合 logback 日志框架

文章目录 整合 Logback 日志框架第一步&#xff1a;导入依赖第二步&#xff1a;导入配置&#xff08;logback.xml&#xff09;详解 使用&#xff08;记录日志&#xff09; 遇到问题一解决方案 整合 Logback 日志框架 第一步&#xff1a;导入依赖 &#xff08;Springboot 会自己…

Squid + Stunnel 配置

环境&#xff1a; 亚马逊服务器一台&#xff1a;3.26.80.132 华为云服务器一台&#xff1a;122.59.52.68 客户机一台&#xff1a; Win11 实现的需求&#xff1a;客户机通过设置华为云代理&#xff0c;实现透过亚马逊服务器上网 一、亚马逊服务器 1、安装Squid https://bl…

python爬虫 - 深入requests模块

&#x1f308;个人主页&#xff1a;https://blog.csdn.net/2401_86688088?typeblog &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html 目录 前言 一、下载网络文件 &#xff08;一&#xff09;基本步骤 &#xff08;二&…

大模型部署-​Ollama+WebUI

Ollama&#xff08;安装包和安装文档文末领取&#xff01;&#xff09; Ollama 简介 主要特点&#xff1a; 易于使用&#xff1a;它提供了一个简洁的界面和命令行工具&#xff0c;使得用户可以方便地管理和运行不同的大语言模型。 多种模型支持&#xff1a;可以运行多种开源…

介绍一款开源的 Modern GUI PySide6 / PyQt6的使用

首先附上大神的开源地址&#xff08;自行克隆吧&#xff09;&#xff1a; https://github.com/Wanderson-Magalhaes/Modern_GUI_PyDracula_PySide6_or_PyQt6 步骤一&#xff1a;安装PySide6库 pip install PySide6 步骤二&#xff1a;运行main文件 python main.py 就得…

Windows 11 24H2版本有哪些新功能_Windows 11 24H2十四大新功能介绍

距离上次发布的23H2版本已经过去了一年时间&#xff0c;现在&#xff0c;Win 11的24H2版本终于等到了&#xff0c;微软已经全面公开发布Win11 24H2版本&#xff0c;版本号为26100.1742&#xff0c;此次官宣的版本包括了消费者版、商业版、LTSC 2024版等&#xff0c;各种语言版本…

python使用装饰器来统计函数被调用次数、格式化dict以及Python-smtplib邮件发送的IP name possibly forged问题解决

一、python调试&#xff1a;使用装饰器来统计函数被调用次数及格式化dict 喜欢调试的时候显示数据并显示一些其它的信息&#xff0c;比如区分是哪次调用的调试信息&#xff0c;比如友好的显示dict等相对复杂的数据类型&#xff0c;所以这里涉及到两个方面。一是统计函数被调用次…

【计算机网络】网络相关技术介绍

文章目录 NAT概述NAT的基本概念NAT的工作原理1. **基本NAT&#xff08;静态NAT&#xff09;**2. **动态NAT**3. **NAPT&#xff08;网络地址端口转换&#xff0c;也称为PAT&#xff09;** 底层实现原理1. **数据包处理**2. **转换表**3. **超时机制** NAT的优点NAT的缺点总结 P…

大模型微调十诫:关于将微调模型部署到生产环境的十条建议

转自NLP工程化 大模型微调十诫&#xff1a;关于将微调模型部署到生产环境的十条建议&#xff1a; &#xff08;1&#xff09;不要盲目微调模型&#xff0c;先尝试使用提示的方式满足需求。只有当提示无法达到质量、性能或成本目标时&#xff0c;才考虑微调。 &#xff08;2&…

RabbitMQ延迟队列

1场景&#xff1a; 1.下单之后&#xff0c;给10分钟时间进行支付&#xff0c;如果10分钟后&#xff0c;没有支付&#xff0c;订单取消。&#xff08;可以使用队列的ttl&#xff0c;因为所有的消息都是一样的停留时长10分钟&#xff09; 2.定时发布文章&#xff08;要求4月1号…

MPA-SVM多变量分类预测|海洋捕食者优化算法-支持向量机|Matalb

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&…

JavaScript 数组简单学习

目录 1. 数组 1.1 介绍 1.2 基本使用 1.2.1 声明语法 1.2.2 取值语法 1.2.3 术语 1.3 案例 1. 数组 1.1 介绍 1.2 基本使用 1.2.1 声明语法 1.2.2 取值语法 1.2.3 术语 1.3 案例

基于java+springboot的旅游信息网站、旅游景区门票管理系统设计与实现

该系统是基于javaspringboot开发的旅游景区门票管理系统。是给师弟开发的大四实习作品。学习过程中&#xff0c;遇到问题可以咨询github作者。 演示地址 前台地址&#xff1a; http://travel.gitapp.cn 后台地址&#xff1a; http://travel.gitapp.cn/admin 后台管理帐号&am…

植物大战僵尸修改器-MFC

创建项目 创建mfc应用 基于对话框 打开资源视图下的 IDD_MFCAPPLICTION2_DIALOG 限制对话框大小 将属性中Border的值改为对话框外框 删除对话框中原有的控件 属性-外观-Caption 设置对话框标题 工具箱中拖放一个按钮 修改按钮名称 将按钮ID改为IDC_COURSE 在MFCApplication2…

Fiddler配合wireshark解密ssl

环境&#xff1a; win11&#xff08;wireshark&#xff09;--虚拟机win7&#xff08;Fiddler&#xff09;---虚拟机win7&#xff08;HTTPS站点&#xff09; 软件安装问题&#xff1a; 需要.net环境&#xff0c;NDP461-KB3102436-x86-x64-AllOS-ENU.exe。 安装fiddler后安装下…

Golang通用代码生成器:仙童,电音仙女尝鲜版十二,为售前准备的哑数据模式

Golang通用代码生成器&#xff1a;仙童,电音仙女尝鲜版十二,为售前准备的哑数据模式 哑数据模式是一种使用内存数据的为快速原型准备的模式。专门为售前&#xff0c;产品经理和项目经理准备。Golang通用代码生成器支持此种模式&#xff0c;请见视频&#xff1a;https://www.bi…

【Qt+Python项目构建】- 02 Qt creator 14.0 + PySide6 如何让图像控件的尺寸变化和窗口一致

前言&#xff1a;【这是个AI不会回答的问题】 Qt Creator 新的版本又发出了&#xff0c;Pyside6 有很多新功能。但是&#xff0c;一些传统的方法要被淘汰了。 一个经典的例子是&#xff1a; 我有个一个图像要显示在Form里面的图像控件上&#xff0c;OK&#xff0c; 我现在拖…