个人资料

跳过导航链接首页 > 博客列表 > 博客正文

在asp.netcore中使用CkEditor富文本编辑器

:

前端:


<link href="~/lib/ckeditor/style.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.ckeditor.com/ckeditor5/45.2.0/ckeditor5.css" crossorigin>
<script src="https://cdn.ckeditor.com/ckeditor5/45.2.0/ckeditor5.umd.js" crossorigin></script>
<script src="https://cdn.ckeditor.com/ckeditor5/45.2.0/translations/zh-cn.umd.js" crossorigin></script>
<div class="main-container">
	<div class="editor-container editor-container_classic-editor" id="editor-container">
		<div class="editor-container__editor"><div id="editor"></div></div>
	</div>
</div>

@section Scripts {
	<script type="text/javascript">
		var token1=csrfToken;//注意:'@Html.AntiForgeryToken()';
		const {
			ClassicEditor,
			Alignment,
			Autoformat,
			AutoImage,
			AutoLink,
			Autosave,
			Bold,
			Code,
			CodeBlock,
			Essentials,
			FontBackgroundColor,
			FontColor,
			FontFamily,
			FontSize,
			GeneralHtmlSupport,
			Heading,
			Highlight,
			ImageBlock,
			ImageCaption,
			ImageInline,
			ImageInsert,
			ImageInsertViaUrl,
			ImageResize,
			ImageStyle,
			ImageTextAlternative,
			ImageToolbar,
			ImageUpload,
			Indent,
			IndentBlock,
			Italic,
			Link,
			LinkImage,
			List,
			ListProperties,
			Paragraph,
			PasteFromOffice,
			RemoveFormat,
			SimpleUploadAdapter,
			SourceEditing,
			SpecialCharacters,
			SpecialCharactersArrows,
			SpecialCharactersCurrency,
			SpecialCharactersEssentials,
			SpecialCharactersLatin,
			SpecialCharactersMathematical,
			SpecialCharactersText,
			Strikethrough,
			Subscript,
			Superscript,
			Table,
			TableCaption,
			TableCellProperties,
			TableColumnResize,
			TableProperties,
			TableToolbar,
			TextTransformation,
			Underline
		} = window.CKEDITOR;
		var protocol = window.location.protocol; // e.g., "http:"
		var hostname = window.location.hostname; // e.g., "www.example.com"
		var LICENSE_KEY = 'eyJhbGciOiJFUzI1NiJ9.eyJleHAiOjE3NTAyMDQ3OTksImp0aSI6IjVkYWJkY2Q1LWE0MjktNDllMC1iZDVjLTc0MDJlNjQ2OWU0MiIsInVzYWdlRW5kcG9pbnQiOiJodHRwczovL3Byb3h5LWV2ZW50LmNrZWRpdG9yLmNvbSIsImRpc3RyaWJ1dGlvbkNoYW5uZWwiOlsiY2xvdWQiLCJkcnVwYWwiLCJzaCJdLCJ3aGl0ZUxhYmVsIjp0cnVlLCJsaWNlbnNlVHlwZSI6InRyaWFsIiwiZmVhdHVyZXMiOlsiKiJdLCJ2YyI6IjcyYzZhOGNjIn0.4uxOoLHGley_G_J3QlsYqCD-DGflj65CpOQ3PkXzUNn4zhUZRHUH6kwix5PxEcQ1Ix00ntQ67s_wNjC3I7K8gg';
		if (hostname.includes('localhost') | protocol=='file:') {
			//console.log(hostname);
		} else {
			LICENSE_KEY = '********OiJFUzI1NiJ9.eyJleHAiOjE3ODA3MDM5OTksImp0aSI6ImU3MzI3OGJiLTU3MTYtNDkwZi1hODJkLTkzZmJjZGM2ZWJmNiIsImxpY2Vuc2VkSG9zdHMiOlsic29uZ3NoaXpoYW8uY29tIiwiYmxvZy5zb25nc2hpemhhby5jb20iXSwidXNhZ2VFbmRwb2ludCI6Imh0dHBzOi8vcHJveHktZXZlbnQuY2tlZGl0b3IuY29tIiwiZGlzdHJpYnV0aW9uQ2hhbm5lbCI6WyJjbG91ZCIsImRydXBhbCJdLCJmZWF0dXJlcyI6WyJEUlVQIiwiRTJQIiwiRTJXIl0sInZjIjoiNGYxMzIwNzkifQ.w5lsqAUsigLiEASuz27VhW1XNTM003qcLpa6naWWMxmw3fhm4tCPjuvSDQRAf2MbmPxCQ0T2mT6TvjBcreG-Rg';
		}

		const editorConfig = {
			toolbar: {
				items: [
					'undo',
					'redo',
					'|',
					'sourceEditing',
					'|',
					'heading',
					'|',
					'fontSize',
					'fontFamily',
					'fontColor',
					'fontBackgroundColor',
					'|',
					'bold',
					'italic',
					'underline',
					'strikethrough',
					'subscript',
					'superscript',
					'code',
					'removeFormat',
					'|',
					'specialCharacters',
					'link',
					'insertImage',
					'insertTable',
					'highlight',
					'codeBlock',
					'|',
					'alignment',
					'|',
					'bulletedList',
					'numberedList',
					'outdent',
					'indent'
				],
				shouldNotGroupWhenFull: true
			},
			plugins: [
				Alignment,
				Autoformat,
				AutoImage,
				AutoLink,
				Autosave,
				Bold,
				Code,
				CodeBlock,
				Essentials,
				FontBackgroundColor,
				FontColor,
				FontFamily,
				FontSize,
				GeneralHtmlSupport,
				Heading,
				Highlight,
				ImageBlock,
				ImageCaption,
				ImageInline,
				ImageInsert,
				ImageInsertViaUrl,
				ImageResize,
				ImageStyle,
				ImageTextAlternative,
				ImageToolbar,
				ImageUpload,
				Indent,
				IndentBlock,
				Italic,
				Link,
				LinkImage,
				List,
				ListProperties,
				Paragraph,
				PasteFromOffice,
				RemoveFormat,
				SimpleUploadAdapter,
				SourceEditing,
				SpecialCharacters,
				SpecialCharactersArrows,
				SpecialCharactersCurrency,
				SpecialCharactersEssentials,
				SpecialCharactersLatin,
				SpecialCharactersMathematical,
				SpecialCharactersText,
				Strikethrough,
				Subscript,
				Superscript,
				Table,
				TableCaption,
				TableCellProperties,
				TableColumnResize,
				TableProperties,
				TableToolbar,
				TextTransformation,
				Underline
			],
			fontFamily: {
				supportAllValues: true
			},
			fontSize: {
				options: [10, 12, 14, 'default', 18, 20, 22],
				supportAllValues: true
			},
			heading: {
				options: [
					{
						model: 'paragraph',
						title: 'Paragraph',
						class: 'ck-heading_paragraph'
					},
					{
						model: 'heading1',
						view: 'h1',
						title: 'Heading 1',
						class: 'ck-heading_heading1'
					},
					{
						model: 'heading2',
						view: 'h2',
						title: 'Heading 2',
						class: 'ck-heading_heading2'
					},
					{
						model: 'heading3',
						view: 'h3',
						title: 'Heading 3',
						class: 'ck-heading_heading3'
					},
					{
						model: 'heading4',
						view: 'h4',
						title: 'Heading 4',
						class: 'ck-heading_heading4'
					},
					{
						model: 'heading5',
						view: 'h5',
						title: 'Heading 5',
						class: 'ck-heading_heading5'
					},
					{
						model: 'heading6',
						view: 'h6',
						title: 'Heading 6',
						class: 'ck-heading_heading6'
					}
				]
			},
			htmlSupport: {
				allow: [
					{
						name: /^.*$/,
						styles: true,
						attributes: true,
						classes: true
					}
				]
			},
			image: {
				toolbar: [
					'toggleImageCaption',
					'imageTextAlternative',
					'|',
					'imageStyle:inline',
					'imageStyle:wrapText',
					'imageStyle:breakText',
					'|',
					'resizeImage'
				]
			},
			initialData:
				'<h2>Congratulations on setting up CKEditor 5! 🎉</h2>\n<p>\n\tYou\'ve successfully created a CKEditor 5 project. This powerful text editor\n\twill enhance your application, enabling rich text editing capabilities that\n\tare customizable and easy to use.\n</p>\n<h3>What\'s next?</h3>\n<ol>\n\t<li>\n\t\t<strong>Integrate into your app</strong>: time to bring the editing into\n\t\tyour application. Take the code you created and add to your application.\n\t</li>\n\t<li>\n\t\t<strong>Explore features:</strong> Experiment with different plugins and\n\t\ttoolbar options to discover what works best for your needs.\n\t</li>\n\t<li>\n\t\t<strong>Customize your editor:</strong> Tailor the editor\'s\n\t\tconfiguration to match your application\'s style and requirements. Or\n\t\teven write your plugin!\n\t</li>\n</ol>\n<p>\n\tKeep experimenting, and don\'t hesitate to push the boundaries of what you\n\tcan achieve with CKEditor 5. Your feedback is invaluable to us as we strive\n\tto improve and evolve. Happy editing!\n</p>\n<h3>Helpful resources</h3>\n<ul>\n\t<li>📝 <a href="https://portal.ckeditor.com/checkout?plan=free">Trial sign up</a>,</li>\n\t<li>📕 <a href="https://ckeditor.com/docs/ckeditor5/latest/installation/index.html">Documentation</a>,</li>\n\t<li>⭐️ <a href="https://github.com/ckeditor/ckeditor5">GitHub</a> (star us if you can!),</li>\n\t<li>🏠 <a href="https://ckeditor.com">CKEditor Homepage</a>,</li>\n\t<li>🧑‍💻 <a href="https://ckeditor.com/ckeditor-5/demo/">CKEditor 5 Demos</a>,</li>\n</ul>\n<h3>Need help?</h3>\n<p>\n\tSee this text, but the editor is not starting up? Check the browser\'s\n\tconsole for clues and guidance. It may be related to an incorrect license\n\tkey if you use premium features or another feature-related requirement. If\n\tyou cannot make it work, file a GitHub issue, and we will help as soon as\n\tpossible!\n</p>\n',
			language: 'zh-cn',
			licenseKey: LICENSE_KEY,
			link: {
				addTargetToExternalLinks: true,
				defaultProtocol: 'https://',
				decorators: {
					toggleDownloadable: {
						mode: 'manual',
						label: 'Downloadable',
						attributes: {
							download: 'file'
						}
					}
				}
			},
			list: {
				properties: {
					styles: true,
					startIndex: true,
					reversed: true
				}
			},
			placeholder: 'Type or paste your content here!',
			table: {
				contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', 'tableProperties', 'tableCellProperties']
			},
			simpleUpload: {
				// The URL that the images are uploaded to.
				uploadUrl: '?handler=Upload',
				//uploadUrl: 'api/imagemanager/upload',
				// Enable the XMLHttpRequest.withCredentials property.
				withCredentials: true,
				
				// Headers sent along with the XMLHttpRequest to the upload server.
				// headers: {
				// 	'X-CSRF-TOKEN': 'CSRF-Token',
				// 	Authorization: token1,
				// }
                headers: {
					'RequestVerificationToken': token1 // 使用jQuery获取令牌值
				},
			}
		};

		ClassicEditor.create(document.querySelector('#editor'), editorConfig);

	</script>
}
后端配置图片上传注意:


1.如使用razor页面,razor自动配置了csrf验证,需要在simpleUpload中添加header(如上代码所示),否则将返回 400 bad request,关于如何获得csrf值,这里不再赘述。

如不配置csrf,也可在当前页面禁用csrf验证,可在PageModel类中添加标签[IgnoreAntiforgeryToken],可用来测试,不推荐


    [IgnoreAntiforgeryToken]
    public class AddModelPage : PageModel
    {
        public void OnGet()
        {
        }
        public async Task<IActionResult> OnPostUpload(List<IFormFile> files)
        {
            long size = files.Sum(f => f.Length);

            foreach (var formFile in files)
            {
                if (formFile.Length > 0)
                {
                    var filePath = Path.GetTempFileName();

                    using (var stream = System.IO.File.Create(filePath))
                    {
                        await formFile.CopyToAsync(stream);
                    }
                }
            }

            // Process uploaded files
            // Don't rely on or trust the FileName property without validation.

            return new JsonResult(new { count = files.Count, size });
        }
    }

文中方法示例不符合ckeditor返回值要求,json格式参考官方说明。

2.如使用cotroller api


则写法略有不同,razor的优势是可以把方法写在页面本身的cs代码中。而使用controller建立api可统一管理。


    [ApiController]
    [Route("api/[controller]")]
    public class ImageManagerController : ControllerBase
    {

        [HttpPost("upload")]
        //[EnableCors("AllowAll")]
        //[IgnoreAntiforgeryToken]
        ///api/ImageManager/upload
        public IActionResult OnPostUpload(IFormFile uploadedFile)
        {
            if (uploadedFile != null && uploadedFile.Length > 0)
            {
                // 保存文件逻辑
                var filePath = Path.Combine(Directory.GetCurrentDirectory(), "Uploads", uploadedFile.FileName);
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    uploadedFile.CopyTo(stream);
                }


                return new JsonResult(new UploadResult { url = $"/Uploads/{uploadedFile.FileName}" });
            }
            return RedirectToAction("Index"); // 或者返回其他视图/结果
        }
    }


songshizhao
最初发表2025/6/9 15:15:00 最近更新2025/6/9 15:16:32 12
为此篇作品打分
10