什么叫编辑器cad增强属性编辑器简单地说

知乎回答问题编辑框用 Ctrl+V 粘贴图片是如何实现的? - 知乎467被浏览<strong class="NumberBoard-itemValue" title="7,168分享邀请回答upload.zhihu.com/upload 的请求request 的格式是multipart/form- 图片的内容作为request body 的一部分一起传了过去这里大概就能推测出基本原理了:监听粘贴 → 获取粘贴内容 → 将内容上传搜索代码在 rich_text_editor.js 里面搜索 /upload 字样,搜到了这么一段this.Vz = "http://upload." + Ak.Sl + ":" + location.port + "/upload";
估计是设置属性,那么再搜 .Vz 看看哪里用到了,于是看到function zE(a, b) {
var c = new FormData;
c.append("via", "xhr2");
c.append("upload_file", b);
d = $.ajaxSettings.xhr();
d.withCredentials = i;
var f = $.ajax({url: a.Vz,data: c,processData: l,contentType: l,xhr: function() {
},type: "POST"}).done(function(a) {
啊,找到了,这里应该就是发送图片数据的地方,而且用了 FormData 这个 HTML5 特性简单说就是 ajax 以前只能向服务器发送文本,而 HTML5 提供的 XMLHttpRequest Level2 现在支持发送二进制数据了,这里的 c.append("upload_file", b) 里面 b 应该就是那个图片的二进制数据打断点继续追踪就容易多了,只要在这个地方打个断点,然后往编辑器里面粘贴一个截图Chrome 调试工具的 Call Stack 就会告诉你,程序的上一步在哪里看一看 a 对象的属性基本可以断定它是一个 Event 对象,而且这里的这段 function 就是对粘贴事件的处理,为了验证,搜索一下 .rw 就会看到这样一段 a.f().addEventListener("paste", u(this.rw, this));
确定推断无误,可以看到上面的处理函数中,通过 a.clipboardData 就能取到剪贴板中的数据,并且可以通过 clipboardData.types 来判断数据是不是图片。这么高级的 API 是哪里来的呢?搜一下就知道了 可以看到这个 API 属于 W3C 的标准(当然还是草案阶段),但是不属于 HTML5 另外代码中的重点是这么一段c.type.indexOf("image") && (zE(b, c.getAsFile()), a.preventDefault())
zE 就是上面的那个 ajax 发送函数,而通过 c.getAsFile() 可以从剪贴板中获取二进制的数据结论通过 Clipboard API 可以在用户粘贴时获知粘贴的内容,包括内容的格式(是否为图片),内容的二进制数据等等通过 XMLHttpRequest Level2 可以实现将二进制数据以 ajax 的方式发送到服务器,即实现了上传功能当然以上都需要浏览器的支持,估计IE下就悲剧了最后,我现在迫切期待新浪微博的发布框能支持这个功能15513 条评论分享收藏感谢收起function onPasteEvent (e)
if (e && e.clipboardData && e.clipboardData.getData)
if (/image/.test(e.clipboardData.types))
//粘贴图片
var imageContent = e.clipboardData.getData('image/xxxx');
//检测图片来源
//如果是最原始的 data,比如 QQ 截图、Word 里复制所产生,直接把 data 上传
//这一部分可能用了是 HTML5 中 HTTP_CONTENT_DISPOSITION 上传机制
//除了 HTML5,非显式的 input[type="file"] 应该是无法上传文件的
//如果是 file,上传到知乎服务器
//如果是外部网站 URL,后台 curl get 转移到知乎服务器
//最后生成一个知乎的 URL,作为 img 标签插入到 contentEditable div 中
else if (/text\/plain/.test(e.clipboardData.types)) {
//粘贴简单文本 ....
if (e.preventDefault)
e.stopPropagation();
e.preventDefault();
return false;
219 条评论分享收藏感谢收起楼主邀你扫码
参与上面帖子讨论
你尚未登录或可能已退出账号:(请先或者
【敬请阅读】
亲爱的网友们,、有更新哦!
请您务必审慎阅读、充分理解各条款内容,特别是免除或者限制责任的条款、法律适用和争议解决条款。免除或者限制责任将以粗体标识,您应重点阅读。
【特别提示】
如您继续使用我们的服务,表示您已充分阅读、理解并接受《西祠站规》、《西祠胡同用户隐私保护政策》的全部内容。阅读《西祠站规》、《西祠胡同用户隐私保护政策》的过程中,如果您有任何疑问,可向平台客服咨询。如您不同意《西祠站规》、《西祠胡同用户隐私保护政策》的任何条款,可立即停止使用服务。
南京西祠信息技术股份有限公司
我已阅读并同意、中的全部内容!百度ueditor编辑器上传图片后用什么方法设置img标签里的src、title、alt属性
百度的Ueditor在线编辑器在上传图片后,所插入的img标签中,title、alt属性设置的值通常都是图片名,如33231.jpg,从SEO来说,这个很不好。比如:其中的title是服务器上的新名字,这取决于php服务端传回的JSON中的title属性。而alt属性是这个图片在本地上的名字。也没有太大意义,但是对于SEO来说,alt的作用比title大,然而如果2个标签都要,可能会让搜索引擎认为是恶意堆积关键字。因此,最好的方法是保留alt,而去掉title。如果要改变服务端返回值,就需要先获取这个文章的标题 ,这实现上有点麻烦,我们在UE的源码上直接清空这2个属性的值,注意,title不能取消,因为取消后又会加上&上传中&字样,如图:最终,我们把UE源改成这样:对于ueditor.all.min.js,则搜索 &imageUrlPrefix&,然后在找到处后面查找如图的内容,注意找到imageUrlPrefix后那一行有反白,认真比对,不要搞错了。清空alt和title的目的是为下一步替换准备的,后续的替换就不需要去改UE源码了。我们分开讲用什么方法去掉它,以及用什么方法修改title和alt内容。推荐使用独立的 js函数 放在页面前端处理。方法其实很简单,就是鼠标离开编辑器后触发该函数处理。稍后我会发表在维易PHP网站上,大家到时能够看一下。附:下面两种方式能够了解一下。但其实都不推荐。因为一个好的方法最好不要去影响原代码,因为会造成前端HTML和UE插件以及PHP端的耦合越来越紧,后期修改非常麻烦,只要不影响耦合,一定要做到前端和UE离了谁都能够无关,比如随时把UE换成UM也能够,因为没有什么耦合度。那么就能够改源代码。1、修改UE的服务端接口文件中的返回值。经常使用多图片上传,但是上传后的图片,保存的时候,图片title会自动加上,但是会默认显示 标题的名称,修改alt的时候,还要一个一个修改标题,不方便 ,所有删除掉找到文件:ueditor/php/Uploader.class.php其中返回值 &&title& =& &#39;xxxx&#39;, 你输出的内容,将会插到ueditor中。因此,要么去掉,要么换成你的文章标题2、改源代码方式:可通过修改ueditor.all.js文件中这几个属性的赋值内容操作如下图所示:&
金币:31134
&加载中...温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
demo文件结构:|--js& &|--jquery-1.11.min.js|--emo& &|--emo_1.png& &|--emo_2.png& &|--emo_3.pngindex.htmlindex.html代码:&!DOCTYPE HTML&&html&&head&&meta http-equiv="Content-Type" content="text/ charset=utf-8" /&&title&emotion_test&/title&&style type="text/css"& #test_1 {
width: 100%;
height: 120
line-height: 20
font-size: 20
overflow-y:
border: solid 1px # } #test_1 img {
height: 40
vertical-align: } .emo_panel {
background: #
padding: 1px 0 1px 1 } .emo_panel .one_emo {
display: inline-
height: 30
margin-right: 1
background-position:
background-size: 100%
cursor: } .emo_panel .one_emo:hover {
opacity: 0.8; }&/style&&/head&&body& &div id="btns" onmousedown="return false" ontouchstart="return false" unselectable="on"&
&input type="button" value="getLen" class="getLen"/&
&input type="button" value="getHtml" class="getHtml"/&
&input type="button" value="getTrimHtml" class="getTrimHtml"/&
&input type="button" value="getSel" class="getSel"/&
&input type="button" value="setEnd" class="setEnd"/&
&/div& &div&
&input type="text" id="txt001"& &/div& &div id="testEmo"&
&div class="emo_panel" onmousedown="return false" ontouchstart="return false" unselectable="on"&
&div class="one_emo" data-emo="emo_1.png" style="background-image: url(./emo/emo_1.png)"&&/div&
&div class="one_emo" data-emo="emo_2.png" style="background-image: url(./emo/emo_2.png)"&&/div&
&div class="one_emo" data-emo="emo_3.png" style="background-image: url(./emo/emo_3.png)"&&/div&
&div class="emo_input" id="test_1" contenteditable="true"&&/div& &/div&
&script type="text/javascript" src="./js/jquery-1.11.1.min.js"&&/script& &script type="text/javascript"&
function Emo (id) {
if (typeof jQuery !== "function" || typeof $ !== "function") {
throw new Error("jqery not found");
var $obj = $(document.getElementById(id));
this.$panel = $obj.find(".emo_panel");
this.$content = $obj.find(".emo_input");
Emo.prototype.init = function () {
var _this =
this.$panel.find(".one_emo").click(function (e) {
var status =
var notIE =
var range =
var url = "";
var str = "";
if (this.dataset) {
url = this.dataset.
url = this.getAttribute("data-emo");
str = '&img class="emo" src="./emo/'+url+'"/&';
notIE = document.queryCommandSupported("insertHtml");
sel = document.getSelection();
if (sel.rangeCount == 0) {
console.log("setCaretEnd called..");
_this.setCaretEnd();
range = sel.getRangeAt(0);
if (range.startContainer != _this.$content[0]) {
_this.setCaretEnd();
//内容为空时firefox会自动补&br&
if (_this.$content[0].innerHTML == "&br&") {
_this.$content[0].innerHTML = "";
if (notIE) { //chrome,firefox
status = document.execCommand('insertHTML', false, str);
if (status) {
console.log(1);
console.log(2);
_this.setCaretEnd();
status = document.execCommand('insertHTML', false, str);
} else { //ie
status = document.execCommand('insertImage', false, './emo/'+url);
if (status) {
console.log(11);
console.log(12);
_this.setCaretEnd();
status = document.execCommand('insertImage', false, './emo/'+url);
_this.setCaretAfter();
//插入表情之后将光标定位到当前表情之后
Emo.prototype.setCaretAfter = function () {
var obj = this.$content[0];
var chdLen = obj.childNodes.
var lastNode = obj.childNodes[chdLen-1];
var sel = document.getSelection();
var next =
var range = document.createRange();
//直接插入图片、图片后插入图片
if (sel.focusNode == obj) {
console.log("ie0");
range.setStart(obj, sel.focusOffset);
range.setEnd(obj, sel.focusOffset);
sel.removeAllRanges();
sel.addRange(range);
this.$content[0].focus();
next = sel.anchorNode.nextS
//文字后插入图片
if (next && next.nodeName == "IMG") {
console.log("ie1");
range.setStartAfter(next);
range.setEndAfter(next);
//文字中插入图片
} else if (sel.focusNode.nodeName == "P") {
console.log("ie2");
range.setStart(sel.focusNode, sel.focusNode.childNodes.length);
range.setEnd(sel.focusNode, sel.focusNode.childNodes.length);
//图片之间插入图片
console.log("ie3");
range.setStartBefore(sel.focusNode);
range.setEndBefore(sel.focusNode);
sel.removeAllRanges();
sel.addRange(range);
this.$content[0].focus();
//光标设置到末尾
Emo.prototype.setCaretEnd = function () {
var obj = this.$content[0];
var chdLen = obj.childNodes.
var lastNode = obj.childNodes[chdLen-1];
var range = document.createRange();
console.log(chdLen);
this.$content[0].focus();
if (chdLen == 0) {
range.setStart(obj, 0);
range.setEnd(obj, 0);
if (lastNode.nodeType == 3) {
range.setStart(lastNode, lastNode.length);
range.setEnd(lastNode, lastNode.length);
range.setStart(obj, chdLen);
range.setEnd(obj, chdLen);
console.log(range);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
//输入长度计算,表情按1个长度计算
Emo.prototype.getLen = function () {
var obj = this.$content[0];
var chdLen = obj.childNodes.
console.log(obj.childNodes);
var len = 0;
for (var i = 0; i & chdL i++) {
if (obj.childNodes[i].nodeType == 3) {
len += obj.childNodes[i].
if (obj.childNodes[i].childNodes.length != 0 && obj.childNodes[i].childNodes[0].nodeType == 3) {
len += obj.childNodes[i].childNodes[0].
if (obj.childNodes[i].nodeName == "IMG") {
console.log("len : " + len);
//获取html
Emo.prototype.getHtml = function () {
var str = this.$content.html();
console.log(str);
//获取修剪后的html
Emo.prototype.getTrimHtml = function () {
var str = this.$content.html();
if (str.match(/&div&&br&&\/div&$/)) {
str = str.replace(/(&div&&br&&\/div&)+$/,"");
} else if (str.match(/&p&&br&&\/p&$/)) {
str = str.replace(/(&p&&br&&\/p&)+$/,"");
str = str.replace(/&br&$/,"");
console.log(str);
//获取selection和range对象
Emo.prototype.getSel = function () {
var sel = document.getSelection();
var range =
if (sel.rangeCount != 0) {
range = sel.getRangeAt(0);
console.log(sel);
console.log(range);
$(document).ready(function () {
var oEmo = new Emo("testEmo");
oEmo.init();
$("#btns .getLen").click(function () {
oEmo.getLen();
$("#btns .getHtml").click(function () {
oEmo.getHtml();
$("#btns .getTrimHtml").click(function () {
oEmo.getTrimHtml();
$("#btns .getSel").click(function () {
oEmo.getSel();
$("#btns .setEnd").click(function () {
oEmo.setCaretEnd();
}); &/script&&/body&&/html&& & & &只是简单的demo,可以在IE10以上,chrome,firefox中使用。用contenteditable来做编辑的关键是用execCommand命令,还有对Selection和Range对象的操作,一般的文本编辑器都单独放在一个iframe里面,避免其他非编辑器的元素造成的干扰。关于富文本编辑器,这里还有两个sof上的问题值得一看:
阅读(2406)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'contenteditable属性,简单文本编辑器尝试',
blogAbstract:'& & & &最近一个WebApp项目中,有一个用户留言功能,需要一个简单的输入框,可以插入表情图片。尝试使用contenteditable来做,遇到一些兼容性问题和bug,由于项目进度的原因,最后还是采用了传统的表情替换为特殊字符串的方式来做。不过通过自己尝试的过程还是有所收获,像CKEditor这样的所见即所得(WYSIWYG)编辑器的开发者们确实做了了不起的工作。demo文件结构:|--js& &|--jquery-1.11.min.js|--emo& &|--emo_1.png',
blogTag:'contenteditable,wysiwyg',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:2,
publishTime:5,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 简单编程学习 的文章

 

随机推荐