据我了解,这不是使用哪个库或使用哪种模式的问题。它更像是一个基于角色的架构。假设您可以在编辑器中创建和编辑的元素之一是 <strong> 标签。最终用户会看到
<strong class="some-class">Some content</strong>
虽然您的编辑器会看到相同的元素(因此所见即所得)但具有其他样式或控件,但假设它会显示为红色并有一个“删除”按钮。
<strong class="some-class">Some content <sup>Remove</sup></strong>
我们可以利用 CSS 来实现这些关于元素视觉方面的差异,只需在编辑器画布上使用一个额外的类。
.canvas strong{
font-weight: bold;
}
.canvas strong sup{
display:none;
}
.editing.canvas strong{
color:red;
}
.editing.canvas strong sup{
display:inline;
}
// your end users will see
<div class="canvas">
// but the <sup> element will be display:none; by default
<strong class="some-class">Some content <sup>Remove</sup></strong>
</div>
// your editors will see
<div class="canvas editing">
// here, the 'editing' class will make the <sup> visible and change the color to red
<strong class="some-class">Some content <sup>Remove</sup></strong>
</div>
当然,这是一个非常简单的示例,但您可以看到更复杂的元素如何融入此架构。现在是 js 部分。
假设我们的强元素会在悬停时向最终用户发出警报,而对于我们的编辑器来说,它将处理对“删除”元素的点击。
function StrongElement(){
var id,
el,
data = {
content: 'default content',
classname: 'default classname'
};
function setId(id){
id = id;
render();
}
function setContent(content){
data.content = content;
render();
}
(function create(){
// this is done only once!
el = document.createElement('strong'); // this in more complex elements would be a template
var remove = document.createElement('sup');
remove.innerHTML = 'remove';
el.appendChild(remove);
})();
function render(){
el.id = id;
el.className = data.classname;
el.innerHTML = data.content;
return el;
}
function onHover(){
alert('Im strong and I like it');
}
function remove(){
// more on editor later*
if (editor.isInEditingMode()){
editor.remove(id);
}
}
// expose the public methods
return {
render: render
};
}
我们已经定义了一个 js 'class' 来处理这个元素的任何交互。它可能更复杂,元素可能有嵌套元素。普通 html 插件的附加功能是这些元素有一个 id,并且某些方法仅在变量 editor 存在时才有效。我们来看看编辑器:
function Editor(){
var canvas = document.getElementById('canvas'), // note that the canvas can be a text area, a div, or even a html5 canvas where your elements are rendered graphically instead of the DOM
elements = [],
editingMode = true;
function addElement(element){
// keep track of the js instance of the element
elements.push(element);
// give it an id that both the element and the editor know
element.setId(elements.length);
// append the graphic representation of the instance (some html tags) into the graphic representation of the editor
canvas.appendChild(element.render());
// we return the id so that anyone who added an element can keep track of it
return elements.length; // the id, will be the index in the array of elements
}
function removeElement(id){
// this could be way better but its just for demo purposes
elements[id] = null;
}
function refresh(){
// elements are already in the canvas, so we iterate over all of them
for (var i in elements){
// and re render them
elements[i].render();
}
}
function setEditingMode(mode){
editingMode = mode;
if (editingMode){
canvas.className = 'editing';
}else{
canvas.className = '';
}
}
function isInEditingMode(){
return editingMode;
}
return {
isInEditingMode: isInEditingMode,
addElement: addElement,
removeElement: removeElement,
refresh: refresh
}
}
这是一个非常简单的编辑器,要使其达到生产就绪级别,您需要处理每个元素的位置,在这种情况下,我们可以假设元素的显示顺序与添加它们的顺序相同。但是,当表示在像素画布上绘制的元素的树结构或 x、y 和 z 位置时,这会变得更有趣。该位置数据将被添加到每个元素中,并且每个元素中的渲染函数应该能够参考父编辑器来处理它。
这个超级简单的编辑器可以这样工作:
<div id="canvas"></div>
var editor = new Editor(),
element = new Strong();
element.setContent("I'm Stronger");
editor.addElement( element );
editor.refresh();
editor.setEditingMode(true); // this should add the 'editing' class and you should now see the remove button and red colored content
editor.setEditingMode(false); // this should return the element to a end user state and if you hover you should get an alert
演示:http://jsfiddle.net/pzef52gh/1/
基本上,我要为最终用户设计和实现元素,包括样式和功能。之后,我会在这些元素之上构建您处于编辑模式时的附加样式和功能。您可以使用任何语言和任何框架来执行此操作。这个示例对于主干js 用户来说可能看起来很熟悉,但如果我今天必须做这样的事情,我会使用角度,并且每个“元素”都将是一个具有编辑/非编辑状态的指令。希望对您有所帮助!