在网站后台,我们经常需要发布一些信息(包含文字、图片等等)供用户查阅,这时如果有一些编辑器的使用那么就得心应手了,其实有很多第三方插件实现了此功能,
我们只需要选择性的使用即可,那么今天要介绍一款富文本编辑器的第三方插件
kindeditor
1.首先下载该插件:官网已经挂了,不知怎么回事,去搜索找找
下载完,有如下目录结构:
因为我是在ASP.NET MVC项目中引用的,只需如下即可,把不需要的删掉:
然后添加到项目中:
首先在asp.net文件夹中找到Demo案例,看如何使用的:
<%@ Page Language="C#" AutoEventWireup="true" validateRequest="false" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
this.Label1.Text = Request.Form["content1"];
}
</script>
<!doctype html>
<html>
<head runat="server">
<meta charset="utf-8" />
<title>KindEditor ASP.NET</title>
<link rel="stylesheet" href="../themes/default/default.css" />
<link rel="stylesheet" href="../plugins/code/prettify.css" />
<script charset="utf-8" src="../kindeditor.js"></script>
<script charset="utf-8" src="../lang/zh_CN.js"></script>
<script charset="utf-8" src="../plugins/code/prettify.js"></script>
<script>
KindEditor.ready(function(K) {
var editor1 = K.create('#content1', {
cssPath : '../plugins/code/prettify.css',
uploadJson : '../asp.net/upload_json.ashx',
fileManagerJson : '../asp.net/file_manager_json.ashx',
allowFileManager : true,
afterCreate : function() {
var self = this;
K.ctrl(document, 13, function() {
self.sync();
K('form[name=example]')[0].submit();
});
K.ctrl(self.edit.doc, 13, function() {
self.sync();
K('form[name=example]')[0].submit();
});
}
});
prettyPrint();
});
</script>
</head>
<body>
<asp:Label ID="Label1" runat="server" Text=""></asp:Label>
<form id="example" runat="server">
<textarea id="content1" cols="100" rows="8" style="width:700px;height:200px;visibility:hidden;" runat="server"></textarea>
<br />
<asp:Button ID="Button1" runat="server" Text="提交内容" /> (提交快捷键: Ctrl + Enter)
</form>
</body>
</html>
关键代码部分:
<script charset="utf-8" src="../kindeditor.js"></script>
1.首先在页面上需要引入kindeditor.js文件,我们使用捆绑包的形式,
并且引入KindEditor.ready()方法于script标签里(不要嵌套于页面加载函数里),对里面的参数进行适当修改
KindEditor.ready(function(K) {
var editor1 = K.create('#content1', {
cssPath : '../plugins/code/prettify.css',
uploadJson : '../asp.net/upload_json.ashx',
fileManagerJson : '../asp.net/file_manager_json.ashx',
allowFileManager : true,
afterCreate : function() {
var self = this;
K.ctrl(document, 13, function() {
self.sync();
K('form[name=example]')[0].submit();
});
K.ctrl(self.edit.doc, 13, function() {
self.sync();
K('form[name=example]')[0].submit();
});
}
});
prettyPrint();
});
</script>
加载富文本框:
KindEditor.ready(function(K) {...});
<form id="example" runat="server">
<textarea id="content1" cols="100" rows="8" style="width:700px;height:200px;visibility:hidden;" runat="server"></textarea>
<br />
<asp:Button ID="Button1" runat="server" Text="提交内容" /> (提交快捷键: Ctrl + Enter)
</form>
var editor1 = K.create('#content1', {.....})
content1为一textarea多行文本对象,
cssPath : '../plugins/code/prettify.css',
uploadJson : '../asp.net/upload_json.ashx',
fileManagerJson : '../asp.net/file_manager_json.ashx',
在当前项目下修改这些文件的路径
K('form[name=example]')[0].submit();
要给form表单一个属性值
所以通过以上分析可以看出,该插件是依赖于form表单下的某一textarea元素对象,
实际上就是给textarea元素绑定一个kindeditor富文本框
所以样式的修改的话还是去设置textarea对象
在BundleConfig.cs定义捆绑包:
bundles.Add(new ScriptBundle("~/js/kindeditor").Include(
"~/Content/plugin/kindeditor-4.1.6/kindeditor-all-min.js"));
案例:
我们现在想实现类似新闻信息发布的功能,管理员在后台编辑然后发布信息,供用户查阅信息
1.准备数据表NewInfos:
NewsId为主键自增长
isValid字段默认为true,
添加实体类:
using System;
using System.Data;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web;
namespace MVC_Project08.Models {
public class NewInfos
{
[DisplayName("新闻编号")]
public int NewsId { get; set; }
[DisplayName("新闻标题")]
public string NewTitle { get; set; }
[DisplayName("新闻内容")]
public string NewsContent { get; set; }
[DisplayName("新闻图片")]
public string NewsImage { get; set; }
[DisplayName("用户编号")]
public int UserId { get; set; }
[DisplayName("创建时间")]
public DateTime CreateTime { get; set; }
[DisplayName("有效/无效 ")]
public bool IsValid { get; set; }
//用来接收上传的图片资源(底层是以流的方式)
public HttpPostedFileBase newImageFile { get; set; }
//public HttpPostedFileBase[] newImageFile { get; set; } //多文件上传
}
}
添加News控制器,以及EditNews动作方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MVC_Project08.Models;
using System.Data.SqlClient;
using MVC_Project08.Common;
using LitJson;
namespace MVC_Project08.Controllers
{
public class NewsController : Controller
{
// GET: News
public ActionResult EditNews()
{
return View();
}
}
}
添加动作方法对应的View视图EditNews:
就相当于一个后台的编辑发布功能
@{
Layout = null;
}
@using MVC_Project08.Models
@model NewInfos
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>新闻编辑</title>
@*引入JQuery类库*@
@*<script type="text/javascript" src="~/Content/js/jquery.min.js"></script>*@
@*加载JS捆绑包*@
@Scripts.Render("~/js/jquery")
@Scripts.Render("~/js/kindeditor")
@* @Scripts.Render(new string[] { "~/js/jquery","" });*@
<script>
KindEditor.ready(function (K) {
var editor1 = K.create('#NewsContent', {
cssPath: '/Content/plugin/kindeditor-4.1.6/plugins/code/prettify.css',
uploadJson: '/Content/plugin/kindeditor-4.1.6/asp.net/upload_json.ashx',
fileManagerJson: '/Content/plugin/kindeditor-4.1.6/asp.net/file_manager_json.ashx',
allowFileManager: true,
afterCreate: function () {
var self = this;
K.ctrl(document, 13, function () {
self.sync();
K('form[name=EditNews]')[0].submit();
});
K.ctrl(self.edit.doc, 13, function () {
self.sync();
K('form[name=EditNews]')[0].submit();
});
}
});
});
$(function () {
debugger;
console.log($(".ke-container.ke-container-default").length);
});
</script>
</head>
<body>
<div>
@using (Html.BeginForm("SaveNews","News",FormMethod.Post,new {@id= "EditNews",@name = "EditNews",@enctype = "multipart/form-data" })) {
<table>
<tr>
<td>@Html.DisplayNameFor(model => model.NewTitle)</td>
<td>@Html.TextBoxFor(model => model.NewTitle)</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.NewsImage)</td>
<td>
<input type="file" name="newImageFile" />
@*多文件上传name值要一样,每个文件对应后台一个HttpPostedFileBase对象 *@
@*<input type="file" name="newImageFile" />
<input type="file" name="newImageFile" />*@
</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.NewsContent)</td>
<td>@Html.TextAreaFor(model => model.NewsContent, new { @style = "width:800px;height:400px" })</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.CreateTime)</td>
<td>@Html.TextBoxFor(model=>model.CreateTime,new { @class = "Wdate", @onClick = "WdatePicker({el:this,dateFmt:'yyyy-MM-dd HH:mm:ss'})" })</td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Save"/></td>
</tr>
</table>
}
</div>
</body>
</html>
按照上述的分析修改了路径参数,但是还需要
注意:
此案例中有文件上传的功能,其表单的enctype属性必须设置为"multipart/form-data"
Result:
已成功引入,
但需要注意:
调整宽高时,还是在原textarea上进行设置,我通过css和js设置替换后的元素没有任何效果,在textarea元素设置就ok,应该是插件本身的功能所限制的吧。
Errors:
比如上传图片,报错信息:
缺少LitJson组件的引用,下载的文件有,项目添加引用,然后在控制器中引用namespace即可.
上传路径不存在的问题:
在upload_json文件中:
代码片段:
//文件保存目录路径
String savePath = "../attached/";
//文件保存目录URL(可以指定绝对路径(比如:网络路径("www.xxxxx")))
String saveUrl = aspxUrl + "../attached/";
可以看出需要在kindeditor-4.1.6目录下添加一个attached子文件夹
但是发现,在富文本域填写内容等信息之后,提交表单报错:
这是由于实际底层提交是html字符串代码,不安全,默认下在web是不允许。
解决方案:
博客链接
在提交的控制器的Action动作方法上加上[ValidateInput(false)]注解即可
还有就是文件作为资源文件上传,在MVC后台中使用HttpPostedFileBase类用来获取客户端上传的文件资源,一个文件对应一个HttpPostedFileBase对象,则多文件上传,就对应着HttpPostedFileBase数组,但是要保证多个文件元素的name属性值一致
//用来接收上传的图片资源(底层是以流的方式)
public HttpPostedFileBase newImageFile { get; set; }
public HttpPostedFileBase[] newImageFile { get; set; } //多文件上传
代码片段:
Html.BeginForm("SaveNews","News",...)
将后台设置的信息先保存到数据库中:
public bool AddNews(NewInfos newInfos) {
int count = 0;
if (newInfos!=null) {
string sql = @"INSERT INTO NewInfos
(NewTitle,NewsImage,NewsContent,UserId,CreateTime)
VALUES(@NewTitle,@NewsImage,@NewsContent,@UserId,@CreateTime)";
SqlParameter[] parameters = new SqlParameter[] {
new SqlParameter("@NewTitle",newInfos.NewTitle),
new SqlParameter("@NewsImage",newInfos.NewsImage),
new SqlParameter("@NewsContent",newInfos.NewsContent),
new SqlParameter("@UserId",10001),
new SqlParameter("@CreateTime",newInfos.CreateTime)
};
count=DBHelper.ExecuteNonQuery(sql,parameters);
}
return count > 0;
}
表单提交到News控制器下的SaveNews动作方法,
[ValidateInput(false)]
public ActionResult SaveNews(NewInfos newInfo)
{
if (newInfo != null)
{
//处理文件上传的信息
//生成36位不重复字符串,拼接文件名使其不重名
string fileName = Guid.NewGuid().ToString();
HttpPostedFileBase hpf=newInfo.newImageFile;
if (hpf!=null) {
string passedFileName = hpf.FileName;
int index = passedFileName.IndexOf('.');
string fileExtension = passedFileName.Substring(index);
fileName += fileExtension;
newInfo.NewsImage = $"Content/images/news/{fileName}";
string path = Server.MapPath($"~/{newInfo.NewsImage}");//拼接Web服务器地址
newInfo.newImageFile.SaveAs(path);//保存上传文件的内容
}
bool flag= AddNews(newInfo);//将新闻信息插入到数据库中
if (flag)
{
//return View("NewList");
//return Redirect("/News/NewList");
return RedirectToAction("NewList","News");
}
else {
return View("EditNews");
}
}
else {
newInfo.NewsImage = "";
}
return View("NewList");
}
注意:保存上传的文件,注意是有盘符的路径:
比如本地:d://images/4.png
如果是网站文件的话,应该是 协议/ip地址(端口号)/…
所以对于mvc网站项目,项目部署这个是动态变化,需要动态获取
可以使用Server.MapPath()根据服务器动态拼接
如果新闻纪录成功添加,则重定向到NewList动作方法:
注意:
MVC中Return(viewName) -->只是查找到视图,然后把视图在正常的情况下渲染出来,不是去调用Controller下的某一个Action动作方法
如果想实现调用Action:
1.重定向Redirct()
2.重定向到某一个动作方法: RedirectToAction
public ActionResult NewList() {
//去数据库查询出已编辑好的数据
//ViewBag.message = "You are my destinty!";
string sql = @"SELECT TOP 1 NewsId FROM NewInfos ORDER BY NewsId DESC";
int newsId=(int)DBHelper.ExecuteScalar(sql);
ViewBag.newsId =newsId;
return View();
}
NewList视图:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>新闻列表页</title>
</head>
<body>
<div>
@{
int newsId = ViewBag.newsId;
}
<p>您好,欢迎来到新闻列表页!</p>
<a href="/News/Details/@newsId">新闻详情页</a>
@*<p>Message:@ViewBag.message</p>*@
</div>
</body>
</html>
Rasor变量值如何嵌入到html属性的问题?
直接@变量名加入即可
上面的超链接属于路由传参的方式,之前的博客也讲解过。
Details动作方法:
public ActionResult Details()
{
string newsId = RouteData.Values["id"].ToString();//获取路由参数
//去数据库查询出已编辑好的数据
ViewBag.message = "You are my destinty!";
string sql = @"SELECT * FROM NewInfos WHERE NewsId=@NewsId";
SqlParameter[] parameters = new SqlParameter[] {
new SqlParameter("@NewsId",newsId)
};
NewInfos newInfos= DBHelper.GetModel<NewInfos>(sql,parameters);
return View(newInfos);
}
Details视图页面:
@{
Layout = null;
}
@*强类型视图*@
@using MVC_Project08.Models
@model NewInfos
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>新闻详情页面</title>
</head>
<body>
<div>
<table border="1">
<thead>
<tr>
<td colspan="2" style="color:red">新闻详细信息</td>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.DisplayNameFor(model => model.NewTitle)</td>
<td>@Model.NewTitle</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.UserId)</td>
<td>@Model.UserId</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.NewsContent)</td>
@*@
Html.Raw()方法解析HTML字符串(输出时不编码)
*@
<td>@Html.Raw(@Model.NewsContent)</td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.NewsImage)</td>
<td><img src="/@Model.NewsImage" alt="@Html.DisplayNameFor(model => model.NewsImage)"/></td>
</tr>
<tr>
<td>@Html.DisplayNameFor(model => model.CreateTime)</td>
<td>@Model.CreateTime</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
富文本框保存到数据库中的是底层的html字符串代码,那么在页面上又该如何解析?
在mvc HtmlHelper辅助器中,提供了一个Raw()方法可以用来解析html,输出时不进行编码:
<td>@Html.Raw(@Model.NewsContent)</td>
测试案例:
点击save按钮:
点击新闻详情页链接: