Unity AssetsBundle 详解

文章目录

  • 1.AssetBundle 概念
  • 2.AssetBundle 优势
  • 3.AssetBundle 特性
  • 4.AssetBundle 使用流程
    • 4.1 分组
    • 4.2 打包
    • 4.3 加载包
    • 4.4 加载资源
    • 4.5 卸载资源
  • 5.AssetBundleManifest
  • 6.AssetBundle的内存占用
  • 7.AB包资源加密

1.AssetBundle 概念

AssetBundle又称AB包,是Unity提供的一种用于存储资源的资源压缩包。

Unity中的AssetBundle系统是对资源管理的一种扩展,通过将资源分布在不同的AB包中可以最大程度地减少运行时的内存压力,可以动态地加载和卸载AB包,继而有选择地加载内容。

2.AssetBundle 优势

  1. AB包存储位置自定义,继而可放入可读可写的路径下便于实现热更新
  2. AB包自定义压缩方式,可以选择不压缩或选择LZMA和LZ4等压缩方式,减小包的大小,更快的进行网络传输。
  3. 资源可分布在不同的AB包中,最大程度减少运行时的内存压力, 可做到即用即加载,有选择的加载需要的内容。
  4. AB包支持后期进行动态更新,显著减小初始安装包的大小,非核心资源以AB包形式上传服务器,后期运行时动态加载,提高用户体验。

AssetBundle和Resources的比较

AssetBundleResources
资源可分布在多个包中所有资源打包成一个大包
存储位置自定义灵活必须存放在Resources目录下
压缩方式灵活(LZMA,LZ4)资源全部会压缩成二进制
支持后期进行动态更新打包后资源只读无法动态更改

3.AssetBundle 特性

  1. AB包可以存储绝大部分Unity资源但无法直接存储C#脚本,所以代码的热更新需要使用Lua或者存储编译后的DLL文件。
  2. AB包不能重复进行加载,当AB包已经加载进内存后必须卸载后才能重新加载。
  3. 多个资源分布在不同的AB包可能会出现一个预制体的贴图等部分资源不在同一个包下,直接加载会出现部分资源丢失的情况,即AB包之间是存在依赖关系的,在加载当前AB包时需要一并加载其所依赖的包。
  4. 打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)

4.AssetBundle 使用流程

AssetBundle的使用流程比较繁琐,大致上分为五个阶段:分组、打包、加载包、加载资源、卸载包

4.1 分组

在这里插入图片描述
分组策略:

  1. 按逻辑实体分组
    • 一个UI界面或者所有UI界面一个包(这个界面里面的贴图和布局信息一个包)
    • 一个角色或者所有角色一个包(这个角色里面的模型和动画一个包)
    • 所有的场景所共享的部分一个包(包括贴图和模型)
      2.按照类型分组
      所有声音资源打成一个包,shader打成一个包,模型打成一个包,材质打成一个包
      3.按照使用分组
      把在某一时间内使用的所有资源打成一个包。可以按照关卡分,一个关卡所需要的所有资源包括角色、贴图、声音等打成一个包。也可以按照场景分,一个场景所需要的资源一个包
  • 注意事项:
  1. 经常更新的资源放在一个单独的包里面,跟不经常更新的包分离
  2. 把需要同时加载的资源放在一个包里面
  3. 可以把其他包共享的资源放在一个单独的包里面
  4. 把一些需要同时加载的小资源打包成一个包
  5. 如果对于一个同一个资源有两个版本,可以考虑通过后缀来区分,例如v1、v2、v3

4.2 打包

1、代码打包

Using Unity.Editor;

[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
   string assetBundleDirectory = "Assets/AssetBundles";
   if (!Directory.Exists(assetBundleDirectory))
   {
      Directory.CreateDirectory(assetBundleDirectory);
   }
   //BuildTarget -- 打包平台,打包的资源只能在该平台下使用
   BuildPipeline.BuildAssetBundles(assetBundleDirectory,
                                        BuildAssetBundleOptions.None,
                                        BuildTarget.StandaloneWindows);
}

  此脚本将在 Assets 菜单底部创建一个名为 Build AssetBundles 的菜单项,该菜单项将执行与该标签关联的函数中的代码。单击 Build AssetBundles 时,将随构建对话框一起显示一个进度条。此过程将会获取带有 AssetBundle 名称标签的所有资源,并将它们放在 assetBundleDirectory 定义的路径中的文件夹中。
BuildAssetBundleOptions:

  • None: 默认构建AssetBundle的方式。使用LZMA算法压缩,此算法压缩包小,但是加载时间长,而且使用之前必须要整体解压。解压以后,这个包又会使用LZ4算法重新压缩,这样这种包就不要对其整体解压了。(也就是第一次解压很慢,之后就变快了。
  • UncompressedAssetBundle: 不压缩数据,包大,但是加载很快。
  • ChunkBaseCompression: 使用LZ4算法压缩,压缩率没有LZMA高,但是加载资源不必整体解压。这种方法中规中矩,比较常用。
  • 其它的参数请自行百度

2、AssetBundleBrowse 工具打包
AssetBundleBrowser插件的获取
Unity 2019版本可以直接在Windows —> PackageManager里面找到此插件并直接安装
或在https://github.com/Unity-Technologies/AssetBundles-Browser下载
在这里插入图片描述
2、AssetBundleBrowser面板的使用
通过 Windows --> AssetBundle Browser下打开AB包管理面板 一共有三个面板
Configure面板
查看当前AB包及其内部资源的基本情况(大小,资源,依赖情况等)
在这里插入图片描述
Build面板
负责AssetBundle打包的相关设置 按Build即可进行打包
在这里插入图片描述
三种压缩方式:

  • NoCompression:不压缩,解压快,包较大,不建议使用。
  • LZMA: 压缩最小,解压慢,用一个资源要解压包下所有资源。
  • LZ4: 压缩稍大,解压快,用什么解压什么,内存占用低,更建议使用。
    一般需要进行更改的设置即为图中勾选的相关选项设置。

Inspect面板
主要用来查看已经打包后的AB包文件的一些详细情况(大小,资源路径等)
在这里插入图片描述
打包后的 manifest 文件
打包完成后,会自动生成一个主包(主包名称随平台不同而不同),主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)在这里插入图片描述
在这里插入图片描述

4.3 加载包

// 从文件中加载
AssetBundle.LoadFromFile(abPath);
AssetBundle.LoadFromFileAsync();
// 从内存中加载
AssetBundle.LoadFromMemory();
// 从网络下载
UnityWebRequestAssetBundle.GetAssetBundle();

① AssetBundle.LoadFromFile(Async)

最常用也是最推荐使用的方法。
这个方法可以高性能的加载没有压缩或者通过LZ4方法压缩的AssetBundle。
使用这个方法的时候,大部分平台只加载AssetBundle的包头,剩下的数据仍然在硬盘上。AssetBundles的对象会按需要进行加载,或者被间接引用到的时候加载。在这个情境下不会有额外的内存被消耗。

② AssetBundle.LoadFromMemory(Async)

不建议使用的API。常用于通过加密过的ab资源的加载。
如果你通过下载或者其他方法已经把Assetbundle的字节保存到了内存中的一个数组中,就能通过此函数进行加载。
使用这个方法的时候,底层会把内存中已经加载好的assetbundle数组byte[]拷贝到一个新分配的、相邻的地址上,如果使用了LZMA压缩方法,拷贝的时候还会顺便解压。造成的问题是内存使用的峰值至少是assetbundle的两倍。

③ UnityWebRequestAssetBundle.GetAssetBundle()

从远端服务器加载ab资源时推荐的方法。
UnityWebRequest类允许开发者定义unity应该怎么处理下载的数据,避免不必要的内存消耗。
使用DownloadHandlerAssetBundle 类可以对下载进行配置,使用一个worker线程流式下载数据,并存放在一个可变大小的buffer,或者某个临时的存储空间中。DownloadHandler 不会复制已下载的bytes。
对于LZMA压缩的Assetbundles,下载的时候会顺便解压,存放的时候通过LZ4再次压缩,可以通过Caching.CompressionEnabled 设置。
下载完成后,可以通过DownloadHandler的属性对assetbundle进行访问,这个行为类似于AssetBundle.LoadFromFile。

 UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(assetBundlePath, 0);
 var opt = request.SendWebRequest();
 opt.completed += (_) =>
 {
     AssetBundle = DownloadHandlerAssetBundle.GetContent(request);
 };

④ WWW.LoadFromCacheOrDownload
旧版API,因为性能问题已被废弃,建议使用UnityWebRequest。

4.4 加载资源

// 泛型加载
T obj = ab.LoadAsset<T>(ResourceName); 
// 参数指明资源类型 防止重名
Object obj = ab.LoadAsset(ResourceName, Type); 

// 异步加载,加载较大资源的时候使用
AssetBundle.LoadAssetAsync<GameObject>(assetName)  
// 参数指明资源类型 防止重名
Object obj = ab.LoadAssetAsync(resName,Type); 

// 加载AB包中所有的对象,不包含依赖的包
AssetBundle.LoadAllAssets();
// 异步加载全部资源
AssetBundle.LoadAllAssetsAsync();
// 加载资源及其子资源
AssetBundle.LoadAssetWithSubAssets();

示例:

// 加载AB包
AssetBundle loadedAssetBundle = AssetBundle.LoadFromFile(path);

//加载单个游戏对象:
GameObject gameObject = loadedAssetBundle.LoadAsset<GameObject>(assetName);
//加载所有资源:
Unity.Object[] objectArray = loadedAssetBundle.LoadAllAssets();
//异步加载资源:
AssetBundleRequest request = loadedAssetBundleObject.LoadAssetAsync<GameObject>(assetName);
yield return request;
var loadedAsset = request.asset;
//异步加载所有资源:
AssetBundleRequest request = loadedAssetBundle.LoadAllAssetsAsync();
yield return request;
var loadedAssets = request.allAssets;

4.5 卸载资源

为什么要卸载AssetBundle?

每次加载AB包都会有内存的占用,如果一直不卸载,随着游戏的运行不停加载使用到的新AB包,内存占用会越来越大。
哪些AssetBundle可以卸载?
当前运行时没有使用到的Assetbundle可以卸载。没有使用到的Assetbundle指的是内部的资源当前未被引用。
想要卸载AssetBundle,首先需要了解它在内存中的占用组成。AssetBundle的内存占用查看 5.AssetBundle的内存占用

// 会把 Bundle 卸载,但是已经从 Bundle 里加载出来的 资源 是不会被卸载的。
ab.Unload(false)

// 不但会卸载 Bundle,也会卸载已经从 Bundle 里加载出来的 所有资源,哪怕这些 资源 还被引用着。
ab.Unload(true)

常用的卸载策略

需要通过引用计数管理ab包。
推荐的卸载方式:
加载ab包中资源时,引用计数+1,释放已加载的资源时,引用计数-1;
当引用计数为0时,调用AssetBundle.Unload(true) 彻底卸载ab包资源和从ab包中加载出来的资源;

5.AssetBundleManifest

AssetBundleManifest 文件内容:
主包的manifest下会存储有版本号、校验码(CRC)、所有其它包的相关信息(名称、依赖关系)
在这里插入图片描述
获取AssetBundleManifest:

// 编辑器下:
AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(outputPath, options, buildTarget);

// 正式环境下:
AssetBundle ab = AssetBundle.LoadFromFile(abPath);
AssetBundleManifest assetBundleManifest = ab.LoadAsset<AssetBundleManifest>("AssetBundleManifest");

AssetBundleManifest API:

方法说明
string[] GetAllAssetBundles ()获取清单中的所有 AssetBundle。
string[] GetAllDependencies (string assetBundleName)获取给定 AssetBundle 的所有依赖 AssetBundle。
Hash128 GetAssetBundleHash (string assetBundleName)获取给定 AssetBundle 的哈希值。
string[] GetDirectDependencies (string assetBundleName)获取给定 AssetBundle 的直接依赖 AssetBundle。
string[] GetAllAssetBundlesWithVariant ()返回所有使用给定扩展名的assetbundlenames

6.AssetBundle的内存占用

在这里插入图片描述
黑色部分:www类本身占用内存,通过www接口加载AssetBundle才会有这部分内存,www对象保留了一份对WebStream数据(粉色部分)的引用。使用www =null 或者 www.dispose()释放。
其中www.dispose()会立即释放,而www = null会等待垃圾回收。释放www后WebStream的引用计数会相应减一。

橙色部分:官方称为WebStream数据,是数据真正的存储区域。当AssetBundle被加载进来后,这部分内存就被分配了。
它包含3个内容:压缩后的AssetBundle本身、解压后的资源以及一个解压缓冲区(图绿)。无论www(黑色部分)还是后面会提到的AssetBundle对象(粉色部分),都只是有一个结构指向了WebStream数据,从而能对外部提供操作真正资源数据的方法。而当www对象和AssetBundle对象释放时,WebStream数据的引用计数也会相应减1。当WebStream数据引用计数为0时,系统会自动释放。
但为了不频繁地开辟和销毁解压Buffer,其中绿色Decompression解压缓冲区Unity会至少保留一份。例如同时加载3个AssetBundle时,系统会生成3个Decompression Buffer,当解压完成后,系统会销毁两个。

粉色部分:AssetBundle对象,引用了橙色WebStream数据部分,并提供了从WebStream数据中加载资源的接口。通过AssetBundle.Unload(bool unloadAllLoadedObjects)释放。
如果调用AssetBundle.Unload(false),将释放AssetBundle对象本身,其对WebStream引用也将减少,从而可能引起WebStream释放,我们也就无法再通过接口或依赖关系从该AssetBundle加载资源。但已加载的资源还可以正常使用。
如果调用的是AssetBundle.Unload(true),不仅会释放WebStream部分,所有被加载出来的资源将被释放。

无论true或false,AssetBundle.Unload()都将销毁AssetBundle,销毁后调用该AssetBundle对象的任何方法都不会生效或产生报错,也就是说这个接口只能被调用一次,不能先调用unload(false)再调用unload(true)。

7.AB包资源加密

能被AssetStudio等解密软件解密到的资源

  • Resources文件夹下的资源文件
  • 被场景直接引用的资源文件
  • StreamingAssets下的资源文件(包含未加密的ab资源)

加密思路:

  1. 在构建完AB包后,可以将AB包中的内容以byte[]形式读取。
  2. 之后选用任意加密方式对该byte[]加密。
  3. 加密完后重新写入AB包中。
  4. AB包加密完成。

这样对AB包加密之后,如果使用AssetBundle.LoadFromFile()来加载加密的AB包是会报错的,因为Unity已经无法识别加密过后的内容了,这样也就防止了别人随意对AB包进行的读取和加载,保证了资源的安全性。

解密思路:

  1. 先以byte[]形式读取AB包中的内容。
  2. 之后使用对应的解密算法对该byte[]进行解密。
  3. 解密过后的byte[]通过AssetBundle.LoadFromMemory()来进行加载。
  4. AB包加载完成。
using System.IO;
using System.Security.Cryptography;
using UnityEngine;

/// <summary>
/// AB资源加解密
/// </summary>
public static class AssetBundleEncryption
{
    #region 基于偏移量加密
    private const int OffsetSize = 32; // 插入的字节数

    // 加密AssetBundle
    public static void EncryptAssetBundle(string inputPath, string outputPath)
    {
        byte[] originalBytes = File.ReadAllBytes(inputPath);
        byte[] offsetBytes = new byte[OffsetSize];

        // 随机生成插入的二进制数据(或使用特定标记)
        System.Random random = new System.Random();
        random.NextBytes(offsetBytes);

        byte[] encryptedBytes = new byte[originalBytes.Length + OffsetSize];
        System.Buffer.BlockCopy(offsetBytes, 0, encryptedBytes, 0, OffsetSize);
        System.Buffer.BlockCopy(originalBytes, 0, encryptedBytes, OffsetSize, originalBytes.Length);

        File.WriteAllBytes(outputPath, encryptedBytes);
        Debug.Log("加密完成: " + outputPath);
    }

    // 解密AssetBundle
    public static AssetBundle DecryptAssetBundle(string encryptedPath)
    {
        return AssetBundle.LoadFromFile(encryptedPath, 0, OffsetSize);
    }
    #endregion

    #region 基于AES加密
    private static readonly byte[] Key = new byte[32]; // 256位密钥
    private static readonly byte[] IV = new byte[16];  // 128位初始化向量

    static void AssetBundleAesEncryption()
    {
        // 生成随机密钥和初始化向量
        using (var rng = new RNGCryptoServiceProvider())
        {
            rng.GetBytes(Key);
            rng.GetBytes(IV);
        }
    }

    // 使用AES加密AssetBundle
    public static void AESEncryptAssetBundle(string inputPath, string outputPath)
    {
        byte[] originalBytes = File.ReadAllBytes(inputPath);
        byte[] encryptedBytes;

        using (Aes aes = Aes.Create())
        {
            aes.Key = Key;
            aes.IV = IV;

            ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    cs.Write(originalBytes, 0, originalBytes.Length);
                }
                encryptedBytes = ms.ToArray();
            }
        }

        using (FileStream fs = new FileStream(outputPath, FileMode.Create, FileAccess.Write))
        {
            fs.Write(encryptedBytes, 0, encryptedBytes.Length);
        }

        Debug.Log("AES加密完成: " + outputPath);
    }

    // 解密并加载AES加密的AssetBundle
    public static AssetBundle AesEncryptedAssetBundle(string encryptedPath)
    {
        byte[] encryptedBytes = File.ReadAllBytes(encryptedPath);
        byte[] decryptedBytes;

        using (Aes aes = Aes.Create())
        {
            aes.Key = Key;
            aes.IV = IV;

            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

            using (MemoryStream ms = new MemoryStream(encryptedBytes))
            {
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                {
                    using (MemoryStream decryptedStream = new MemoryStream())
                    {
                        cs.CopyTo(decryptedStream);
                        decryptedBytes = decryptedStream.ToArray();
                    }
                }
            }
        }

        string tempFilePath = Path.GetTempFileName();
        File.WriteAllBytes(tempFilePath, decryptedBytes);

        AssetBundle bundle = AssetBundle.LoadFromFile(tempFilePath);
        File.Delete(tempFilePath);

        // AssetBundle bundle = AssetBundle.LoadFromMemory(decryptedBytes);
        Debug.Log("AES解密并加载完成: " + encryptedPath);
        return bundle;
    }
    #endregion
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux项目自动化构建工具make/Makefile

目录 前言1. Makefile 文件的基本构成2. makefile的依赖关系的自动化推导3. make执行过程中的一些现象及其原理3.1 证明该现象原理3.2 关于 stat 时间属性的拓展 前言 身处 linux 平台环境开发中的伙伴们都知道 gcc/g 编译器以及编译指令&#xff0c;但是不难想象在以后的生活…

解决方案 | IP地址申请专用HTTPS证书的常见问题

IP地址专用的HTTPS证书是一种专门为IP地址设计的SSL/TLS证书&#xff0c;它可以通过HTTPS协议安全地访问基于IP地址实现的网站或服务&#xff0c;以下是申请IP地址https证书时经常遇到的问题以及解决办法。 一 、如何选择合适的IP地址https证书的类型&#xff1f; 1、DV类型IP…

水文:CBA业务架构师

首先&#xff0c; 我们来了解一下什么是CBA业务架构师&#xff1f; CBA业务架构师认证是由业务架构师公会(Business Architecture Guild)授予的一种专业认证。标志着证书持有者已经掌握了业务架构的核心技能和知识&#xff0c;能够在实际工作中熟练运用业务架构技术和框架&…

安全极客团队荣获首届“矩阵杯”网络安全大赛人工智能挑战赛“三等奖”

近日&#xff0c;东半球规格高、规模大且奖金丰厚的网络安全顶级赛事——首届“矩阵杯”网络安全大赛在青岛国际会议中心圆满落幕。本次大赛设置了五大赛事&#xff0c;包括通用产品漏挖赛、国产软硬件安全检测赛、原创漏洞挖掘赛、人工智能&#xff08;大模型&#xff09;挑战…

CDH实操--集群卸载

作者&#xff1a;耀灵 1、停止正在运行的服务 a、控制台停止集群服务 b、控制台停止Cloudera Management Service c、命令行停止cm服务 systemctl stop cloudera-scm-agent #所有节点执行 systemctl stop cloudera-scm-server #cdh01节点执行2、主线并移除Parcles rm -r…

【完结】LeetCode 热题 HOT 100分类+题解+代码详尽指南

目录 LeetCode 热题 100 前言 Leetcode Top100题目和答案-哈希 Leetcode Top100题目和答案-双指针篇 Leetcode Top100题目和答案-滑动窗口篇 Leetcode Top100题目和答案-子串篇 Leetcode Top100题目和答案-普通数组篇 Leetcode Top100题目和答案-矩阵篇 Leetcode Top1…

ABAQUS大连正版代理商:亿达四方——开启东北工业智能仿真新篇章

在东北老工业基地的振兴道路上&#xff0c;大连以其独特的地理位置和深厚的产业基础&#xff0c;成为推动区域经济发展的领头羊。作为国际知名的仿真软件ABAQUS在大连地区的官方授权代理商&#xff0c;亿达四方正以科技创新为驱动&#xff0c;引领当地制造业迈向数字化、智能化…

c++多态——virtual关键字,C++11 override 和 final,析构函数的重写。

目录 多态基本概念 virtual关键字 C11 override 和 final 举个栗子 析构函数的重写(基类与派生类析构函数的名字不同) 多态基本概念 概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同…

Coze触发器:触发任务的Python接口源码

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 Coze触发器 📒📝 触发器接口源码⚓️ 相关链接 ⚓️📖 介绍 📖 自动化,一个在现代软件开发中不可或缺的概念,它让我们的生活和工作变得更加高效。Coze也支持定时任务/触发任务,通过触发器,我们可以更自由的控制Bot去…

【中项第三版】系统集成项目管理工程师 | 第 11 章 规划过程组② | 11.3 - 11.5

前言 第 11 章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节属于10大管理的内容&#xff0c;学习要以教材为准。本章上午题分值预计在15分。 目录 11.3 收集需求 11.3.1 主要输入 11.3.2 主要工具与技术 11.3.3 主要输出 11.4 定义范围 11.4.1 主要输入…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【密钥派生(C/C++)】

密钥派生(C/C) 以HKDF256密钥为例&#xff0c;完成密钥派生。具体的场景介绍及支持的算法规格&#xff0c;请参考[密钥生成支持的算法]。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生成密钥 指定密钥别名。 初始化密钥属…

【JavaEE】Spring AOP详解

一.AOP的定义. Aspect Oriented Programming&#xff08;面向切面编程&#xff09;概括的来说AOP是一种思想, 是对某一类事情的集中处理 什么是面向切面编程呢? 切面就是指某一类特定问题, 所以AOP也可以理解为面向特定方法编程.什么是面向特定方法编程呢? 比如上个博客文章…

Python基础教学之四:面向对象编程——迈向更高级编程

Python基础教学之四&#xff1a;面向对象编程——迈向更高级编程 一、面向对象编程概念 1. 类和对象 定义&#xff1a;在面向对象编程(OOP)中&#xff0c;类是创建对象的模板&#xff0c;它定义了对象的属性和方法。对象是类的实例&#xff0c;具体存在的实体&#xff0c;拥有…

从0到1开发一个Vue3的新手引导组件(附带遇到的问题以及解决方式)

1. 前言: 新手引导组件,顾名思义,就是强制性的要求第一次使用的用户跟随引导使用应用,可以让一些第一次使用系统的新手快速上手,正好我最近也遇到了这个需求,于是就想着开发一个通用组件拿出来使用(写完之后才发现element就有,后悔了哈哈哈&#x1f62d;&#x1f62d;) 示例图…

回车不搜索直接页面刷新问题解决

使用技术栈&#xff1a;vue3、elementUiPlus 问题&#xff1a;回车触发方法&#xff0c;会刷新整个页面&#xff0c;不执行搜索 解决方法&#xff1a;在搜索的表单中增加submit.native.prevent submit.native.prevent

LLM 合成数据生成完整指南

大型语言模型是强大的工具&#xff0c;不仅可以生成类似人类的文本&#xff0c;还可以创建高质量的合成数据。这种能力正在改变我们进行 AI 开发的方式&#xff0c;特别是在现实世界数据稀缺、昂贵或隐私敏感的情况下。在本综合指南中&#xff0c;我们将探索 LLM 驱动的合成数据…

学习测试8-数据库mysql操作

下载配置mysql 网络博客 使用 在Linux里 1 service mysql start 启动服务 2 在Navicatt 中连接Linux服务器 3 第一步 将所有文件上传到/opt目录下 第二步 chmod 777 deploy-mysql.sh 第三步 ./deploy-mysql.sh4 service mysql status 查看状态是否安装成功 5 重启mys…

WPS打开PDF文件的目录

WPS打开PDF文件的目录 其实WPS中PDF文件并没有像Word那样标准的目录&#xff0c;但是倒是有书签&#xff0c;和目录一个效果 点击左上角书签选项&#xff0c;或者使用Alt Shift 1快捷键即可

『Django』自带的后台

theme: smartblue 本文简介 点赞 关注 收藏 学会了 上一篇讲了 Django 操作 MySQL 的方法&#xff0c;讲了如何创建模型&#xff0c;如何对数据库做增删改查的操作。但每次修改数据都要写代码&#xff0c;多少有点麻烦。 有没有简单一点的方法呢&#xff1f; 有的有的&#…

centos 安装ffmpeg

这个错误表明在你的 CentOS 系统的默认仓库中没有 ffmpeg 包。CentOS 的默认仓库通常不包含 ffmpeg&#xff0c;因为它涉及一些许可证问题。但是&#xff0c;你可以通过添加第三方仓库来安装 ffmpeg。 使用 EPEL 和 RPM Fusion 仓库 # 安装 EPEL 仓库 sudo yum install epel-…