You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blazor Server中Quill编辑器插入图片的存储方案求助

Blazor Server 中 Quill 编辑器多图上传解决方案

问题分析

你当前已实现Quill编辑器文本内容的SQL存储与读取,但插入的图片无法保存——默认Quill会将图片转为Base64嵌入HTML,若要将图片存储到服务器文件夹或SQL数据库,需要拦截Quill的图片插入事件,替换为后端上传逻辑,再将返回的图片URL插入编辑器内容。


解决方案步骤

1. 配置Quill编辑器的图片上传拦截

在Blazor项目的wwwroot目录下创建quill-config.js文件,拦截图片插入操作并调用Blazor后端方法完成上传:

window.quillImageHandler = {
    register: function (dotNetRef) {
        const quill = new Quill('#editor-container', {
            theme: 'snow',
            modules: {
                toolbar: [
                    ['image']
                    // 保留其他工具栏配置
                ]
            }
        });

        // 拦截工具栏的图片点击事件
        quill.getModule('toolbar').addHandler('image', function () {
            const input = document.createElement('input');
            input.setAttribute('type', 'file');
            input.setAttribute('accept', 'image/*');
            input.setAttribute('multiple', true); // 支持多图选择
            input.click();

            input.onchange = async function () {
                const files = Array.from(input.files);
                for (const file of files) {
                    // 调用Blazor后端上传方法
                    const imageUrl = await dotNetRef.invokeMethodAsync('UploadImage', file);
                    // 将图片URL插入编辑器
                    const range = quill.getSelection();
                    quill.insertEmbed(range.index, 'image', imageUrl);
                    quill.setSelection(range.index + 1);
                }
            };
        });
    }
};

2. Blazor后端实现图片上传与整合逻辑

在页面组件中添加JS交互引用,实现图片上传方法,并整合到原有保存流程:

@inject IWebHostEnvironment WebHostEnv
@inject MonthlySharingService monthlySharingService

@implements IDisposable

@code {
    private MarkupString preview;
    private MonthlySharing monthlySharing = new();
    private string message = string.Empty;
    private DotNetObjectReference<YourComponentName>? _dotNetRef;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            _dotNetRef = DotNetObjectReference.Create(this);
            // 注册Quill图片处理逻辑
            await JS.InvokeVoidAsync("quillImageHandler.register", _dotNetRef);

            // 原有HTML内容加载逻辑
            bool loading = true;
            while (loading)
            {
                try
                {
                    if (!string.IsNullOrEmpty(monthlySharing.Content))
                    {
                        await QuillHtml.LoadHTMLContent(monthlySharing.Content);
                    }
                    loading = false;
                }
                catch
                {
                    await Task.Delay(10);
                    loading = true;
                }
            }
        }
        await base.OnAfterRenderAsync(firstRender);
    }

    // 供JS调用的图片上传方法
    [JSInvokable]
    public async Task<string> UploadImage(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return string.Empty;

        // 方案1:保存到服务器文件夹
        var uploadPath = Path.Combine(WebHostEnv.WebRootPath, "uploads", "images");
        if (!Directory.Exists(uploadPath))
            Directory.CreateDirectory(uploadPath);
        
        var fileName = $"{Guid.NewGuid()}_{Path.GetFileName(file.FileName)}";
        var filePath = Path.Combine(uploadPath, fileName);
        
        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await file.CopyToAsync(stream);
        }
        // 返回可访问的图片URL
        return $"/uploads/images/{fileName}";

        // 方案2:保存到SQL数据库(替换上方代码)
        // using var memoryStream = new MemoryStream();
        // await file.CopyToAsync(memoryStream);
        // var imageData = memoryStream.ToArray();
        // // 调用服务层保存图片数据,返回关联标识
        // var imageId = await imageService.SaveImage(imageData, file.ContentType, monthlySharing.Id);
        // return $"/api/images/{imageId}"; // 需对应图片读取接口
    }

    private async Task Save()
    {
        message = "wait...";
        // 获取已替换为图片URL的编辑器HTML内容
        monthlySharing.Content = await QuillHtml.GetText();

        if (monthlySharingService.AddUpdate(monthlySharing))
        {
            message = "Your post is successfully created! ";
            monthlySharing = new();
        }
        else
        {
            message = "Could not saved";
        }
    }

    public void Dispose()
    {
        _dotNetRef?.Dispose();
    }
}

3. 关键配置与注意事项

  • 若选择服务器文件夹存储,需在Program.cs中配置静态文件访问:
    app.UseStaticFiles();
    // 若uploads目录不在wwwroot,需额外配置:
    // app.UseStaticFiles(new StaticFileOptions
    // {
    //     FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath, "uploads")),
    //     RequestPath = "/uploads"
    // });
    
  • 若选择SQL数据库存储,需创建图片关联表(如ArticleImages),存储字节数组、ContentType、文章ID等字段,并实现接口返回图片流。
  • 确保Quill编辑器容器ID(#editor-container)与JS配置一致。

内容的提问来源于stack exchange,提问作者user21185171

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 18:23:38