
( http://www.simonstalenhag.se/的艺术)
背景/免责声明
大家好,这篇文章实际上是我周一在基辅马拉松比赛中演讲的素材。 但是,不要以为您是我编写文本的听众,只是因为我准备起来比较容易。
我目前是Conductor / WeWork的前端开发人员。 我们不会像晚上那样发展编辑,就像我晚上一样,也不发展这样的事情。 这更多地是关于我以前在UTI(utipi,uti…)上的项目获得的经验。 距今很久,但事实证明,这个话题与今天以及与之相关的门框都息息相关。
我们通常谈论的是名片站点,登录页面以及或多或少的功能站点,但是肯定不是在后台或管理区域。
UTIEditor专为您<3
为什么我们需要这样的编辑器?
这个问题有很多答案,你们当中很多人,我敢肯定会猜到。
我将从提供网站开发服务的UTI的角度回答这个问题。
UTI本质上是一家消费品公司。 我敢肯定,一次,每人每人有十二个名片站点,十二个在线商店和一个品牌樱桃以自己的方式工作-他们自己的CMS。
因此,您创建了另一个登录页面,一个名片网站,并将其提供给客户,他一天后回来,要求更改文本。 改天后,更改背景颜色并仅添加一张图片。 对于客户而言,它看起来像是简单而快速的事情。 很难与它争论。 但是对于您来说,这意味着您需要将开发人员/设计师从当前的工作中撤出。 更不用说花时间在沟通上的经理的工作了。 因此,您要开票,而且金额不小。 客户很愤慨并且抱怨。 下次,您已经预先考虑了这些问题,并开始提出问题,并在TK中放置了编辑功能。
在这里也许值得继续讨论此功能,因为它与众不同。
我想补充一点,在这次对话中,我将不包括WrodPress,Drupal这样的CMS,我们将专注于编辑器市场。
Debry UTI
首先想到的是制作一个表单,用户可以在其中更改他想要的内容:

现实生活中,字段的名称有点不真实,但是您抓住了本质。
从公司的角度来看,她履行了职责,甚至照顾了“定制”。 但是这种方法仍然有很多局限性。
这种方法的优点:
这种方法的缺点:
- 无法更改设计
- 没有办法改变行为
- 没有定位
- 您只能编辑表格中的内容
您是否考虑过CKEeditor ? 有史以来的明星。 请执行下一步,以改善网站上的可编辑内容。

有机会为文本设置格式,甚至插入一些其他元素。 在我加入公司之前,在这个地方的某个地方,他们想到了直接在CKEditor中拖放创建页面编辑器的想法。 不幸的是我没有什么可显示的,但是试着想象一下这种恐怖:)
但是目前来说,可以这么说,2018年CKEditor在这个方向上已经取得了一些进展,这是相当可笑的。 什么不是整页?

但是,这一切在开发和使用中都不方便。 而且,我只知道骨干和jquery,所以大胆地称自己为前端开发人员,并决定提供给他们开发像Wix,Squarespace,Tilda,LPGenerator这样的功能强大的编辑器……然后它们实际上是我的竞争对手。 但是由于UTI是一家无名公司,所以他们对此一无所知。 他们不认识也不会认识。 尽管马拉松的赞助商是Wix。 哦,这只是一个巧合。
他们没有意识到,因为一切都遵循经典-公司并不关心这个项目。
这是两个截屏视频,它们并不完美,带有边框,但是我相信它们将提供编辑器的总体概念。
我一个人在这个项目上。 设计师,产品经理,正面和背面,但没有测试。 但事实是来到公司的手动测试仪在反应堆的火中被调和了。 测试人员当然很有趣。 您会了解什么水平-一次,其中之一被淘汰了:

他们提出了一个错误,他们说该网站已经关闭。 那个家伙刚刚从系统上删除了互联网电缆:)
每次,我都必须以一种新的方式来解释在编辑器中可以完成哪些操作,不能完成哪些操作以及为什么以这种方式工作却可以做到。 实际上,对我来说这很有趣。 一线反馈。 几乎没有客户,而编辑器在很大程度上要归功于他们。
有谁知道我使用哪个堆栈? 可以这么说,该应用程序看起来很棒,坚固。 它不是越野车,因为它不是5年前的越野车。
哦,我的CI / CD处理过程很棒。 每天一次,我尽可能多地去吃食物。 代号Filezilla,拖放,重复。 首先,使用filezilla连接到ftp,然后进行构建,将当前的构建抽出,将其放入名为backup的文件夹中,上传新的构建,然后检查是否有人在此处死亡。 如果死了,请从备份文件夹上载文件。 但说实话,在备份的那一刻,我并不总是这样做,它取决于一组新功能。 考虑到该编辑器处于多个项目中,也就是说我进入了每个项目并检查它是否落在那里,所以我不会。 而且我们仍然使用SVN,具有风味吗?
堆栈呢?
骨干+ jQuery + 0个测试。
模块,异步加载ala代码拆分和服务器端渲染。 这样的术语并没有特别使用,实际上是简单的优化。 但是现在是开放式营销及其革命的时代了!
您所了解的那个时期的Wix,现在与Wix编辑器没有太大区别。 是它具有更多模板,空白和成品组件。 我不知道他们是否完全迁移了反应。 这是完全相同的错误,只有在内存从16 GB开始的Macbook上,并且配备了称为“虚拟房屋”和酷网络引擎的更陡峭的渲染系统。 在如此规模的项目中,工具并没有扮演特别的角色,更多的是关于体系结构和UI / UX的讨论。 UI / UX更为重要。 实现的复杂性,性能以及编辑器创建网站时杀死自己的渴望程度取决于此。 客户通常将远离开发,远离所有这些CSS规则,属性,DOM属性和参数。 他们中将有或多或少的精通人才,他们将为您的客户提供服务,并在将来带走他们。 但是,让我们不要谈论悲伤的事情,让我们尝试进一步考虑几代编辑器。
客户,如果您为他们提供了完美的编辑工具,仍将无法使用它。 他们的手工艺品看起来像这样:

这是对的,但不是对的,因为网络对于人文来说简直是复杂的,另一方面,理想的UI / UX允许您创建一个网站,单击按钮即可完成您想要的事情。
但是有时候这是不可能的,必须寻找中间立场。
HTML视觉编辑器
最初的任务是:与CKEditor中的操作相同,以便您可以移动元素(文本,图片)并以某种方式对其进行编辑/格式化。
主要要求之一是能够加载自定义HTML以便进行进一步的工作。
我首先在可拖动页面上制作元素。 即,用户可以移动它们。 起初,一切看起来都不错,但是我尝试的片段越多,看起来就越糟。 事实是自定义HTML可以是完全任意且不可预测的。 这导致基本的拖放任务,无法了解用户选择哪种元素甚至无法对页面进行平庸控制的问题。 太混乱了。
Grapesjs允许您加载HTML。 他看到的文字包裹在明显的标签中,而只是在正文中的文字,他没有感觉到:

局限性
为了使您能够上传和编辑HTML,无疑是一个大胆的举措。 从用户的角度来看,这是一个很大的自由。 但是有一个很好的例子展示了网络上的事物- 一个蓝色盒子 。
我敢肯定,甚至没有所有的实现选项。 事实是,就语义而言,相同的事物可以使用完全不同的方法以完全不同的方式实现。 想象一下,在页面上,有什么比蓝色方块还要复杂的了。 可以使用<img />标签将相同的图像添加到页面,或使用背景进行设置。 按钮可以是<button>,也可以是<div>或同一图像。 以及如何了解要显示的编辑工具?
没办法
限制00
下一个选择是禁止该布局或该布局,制作样式指南或禁止加载自定义HTML。 当然,我们选择了第二个:)
极限01
由于我们禁止加载自定义HTML,因此我们需要自己的组件/元素,这是真正的编辑器的第一步。
限制02
由于用户将使用我们的许多元素,因此我们必须防止编辑器使用非“我们的元素”,并教我们如何使用它们。
工作环境
不是最有趣的话题,而是重要的。 我真的很喜欢Photoshop界面。 有许多面板和一个工作区。 您可以根据需要操纵工作区,该工作区位于中心,并且根据大小可以水平和垂直滚动。

另外,我很多人都对我的设计Google Web Designer产生了感触:

顺便说一句,这是Google的一种编辑器,有人使用过吗?
最困难的部分是以这种方式破坏页面。 我不是CSS专家,这次对我来说要容易得多,但是那是一种带有表布局的舞蹈。 在继续进行之前,让我们看看总体上是什么样的工作区布局。
的Photoshop
LP发电机

我的创作

Grapesjs

实际上,我们已经在上面讨论了这种布局。 左侧是常用工具,右侧是选项,顶部是其他工具,底部是信息栏。 最明显的选择,但同时对于用户来说却是超负荷的。 他担心所有这些按钮,就好像他在驾驶舱中一样,需要紧急降落。

如此超负荷,您必须隐藏所有内容
蜡

五年来,Vicks的设计变化不大。 进入LPGenerator后,您立即了解到可以将元素拖到页面上,看到设置等。 对于Wix,所有内容最初都是隐藏的。 这是一个好方法。 事实是用户不需要看,他目前很可能不需要的东西。 但是在这里您需要保持平衡。 Wix.com可以添加到页面的元素太多,因此,它们创建了整个元素库。 但是,当然可以将诸如文本或按钮之类的明显内容带到其中一个面板中,以便快速访问。

当您单击某个元素时,与该元素相关的其他功能将显示在其上方。

要意识到这种事情仍然是出血性的,我们稍后再讨论。
极简主义
方形空间

最小的设计,工作空间占据了屏幕的大部分,而从界面来看则是最必要的最小。 该工具箱很奇怪。 例如,带有按钮的第一个屏幕是这样编辑的:

此处的按钮由文本表示。
就其本身而言,编辑模式与预览非常相似,只有在某些屏幕上双击时,才可以切换到编辑模式。

同时,编辑器将我们移至应用程序的另一部分。
我很根
蒂尔达

编辑一个站点,您似乎就在其中。 与Wordpress及其顶部的面板非常相似,具有编辑/发布功能等。 但与此同时,该功能并不像Squarespace那样停止,并且相同的文本更容易编辑。
要添加一些内容,您需要单击+。 将按钮移到您方便的任何位置,否则将无法正常工作。 一切都是有限的。

这样的结果是,对于同一元素,这些画廊具有许多不同的选择。

如您所知,我是Photoshop版本的粉丝。 曾经困扰于表格布局,但现在是2018年,并且出于教育目的,我们不能对CSS网格上的支持和实现布局一无所知。

如果任何人都不熟悉CSS网格,那么这是布局页面布局的最后一种方法。 如果Flexbox更适合用于菜单,表单和其他元素集,则最好使用CSS Grid,它们在全局方面感觉很好。
这不是CSS网格教程,因此我将简要介绍一下,但没有详细说明。
因此,我们的任务是制作左侧面板和右侧面板,并在中间区域显示网站内容。
在FireFox中,使用网格要容易一些,这很奇怪,但是chrome落后了。 在前面的一篇文章中,我已经谈到了这一点。
chrome中的网格检查是什么样的:

同时在莫夫:

有一个网格的微型表示,显示了列/行的语义标签。 因此,如果您想了解更多信息,请立即使用FireFox。 我觉得奇怪,建议使用此浏览器。 Bugzilla的时间已经过去。
让我们从简单的标记开始。
<div class="main"> <div class="left"></div> <div class="content"> <div class="site"></div> </div> <div class="right"></div> </div>
.left-左面板
.content-网站将显示的中间位置
.right-右面板

到目前为止,这还远远不够。 我们希望我们的界面等于视口。 可以使用height: 100%来完成,但是还有视口单位vh和vw 。 我们将使用它们。
.main { height: 100vw; }

默认情况下,子级变成字符串。 这是一种flexbox轴。 我们需要设置列,我们可以通过以下方式做到这一点:
.main { display: grid; grid-template-columns: minmax(200px, .4fr) minmax(560px, 2fr) minmax(200px, .4fr); }
通过反复试验,我得出了一个相当复杂的结论。 minmax功能允许您设置最大和最小尺寸。 fr是通用单位,可避免我们计算像素或百分比大小。 事实是,诸如grid-gap属性会影响如border大小。 fr旨在消除我们的这种痛苦。
淡一点一点并去除body上的margin ,这会困扰我们一些:
body { margin: 0px; } .left, .content, .right { box-sizing: border-box; border: solid 1px; }

太好了 但这是最简单的部分。 现在我们需要创建一个工作区。
.site是我们的虚构网站。 让我们将其设置为标准960px并突出显示。
.site { height: 2000px; width: 960px; background: rebeccapurple; }

如果您挤压此东西,那么它仍然会更加有趣:

但是
.content { overflow: scroll; }
解决问题。 仅保留美学部分。 缩进。
这可以使用margin来完成:
margin: auto; margin-top: 20px; margin-bottom: 20px;

20px取决于您。 但是还有另一个问题。 如果屏幕太小,则左右将没有压痕。 maring: auto以来maring: auto将局促。 首先想到的是设置margin-left和margin-right ,但这是另一个玩笑。 缩进将仅在左侧。 如果向右滚动,则不会存在。 这是一个功能。
无需赘述,您可以使用display: inline-block修复此问题。 是的 但是同时, margin: auto在大屏幕尺寸下表现很好。 下一个最明显的解决方案是使用媒体查询。 在大屏幕上display: block + margin: auto ,在小屏幕上display: block + margin: auto display: inline-block; margin-left/right: 20px display: inline-block; margin-left/right: 20px 。
.site{ height: 2000px; width: 960px; margin: auto; margin-top: 20px; margin-bottom: 20px; background: rebeccapurple; } @media(max-width: 1350px) { .site { display: inline-block; margin: 20px; } }
这样的东西。 如果有人有更好的主意,欢迎发表评论。
网站地图
布局已准备就绪,现在您需要显示用户将要编辑的站点。 这是非常重要的事情。 许多决定取决于它。 事实显示后,有两种显示站点的方法。 在document ,编辑器或iframe的界面在哪里。 两种选择都具有正性和非正性。
相同文件
无论是从心理上还是从技术上,它都更加容易。 但是将来会有更多问题。 事实是,如果添加并且添加了插入自定义CSS和JS的功能,则编辑器将在几分钟后爆炸。
尚未说明如何使用杯子的用户:

封装的CSS尚未像5年前那样成为现实。 有很多选择,但是它们太重或不能完全保护。 当用户倾斜整个界面并意外删除其所有工作时,您将受到指责。 展望未来,当您决定添加许多现成的模板时,您的开发人员将因此而受苦。 无论您如何重新定义某种样式。 现在,如果您看看蒂尔达(Tilda),他们会遇到麻烦。
以出现的该编辑器的第一个UI为例。 文字格式按钮:

你看到这些样式吗? !important颜色!important吗? 完全不需要这些样式,如果您将它们关闭,则什么都不会改变。 无论如何,通过将自定义HTML插入网站页面来重新定义它们非常简单:

我承认,我是手动插入此代码的。 但是我发现可以插入自定义HTML和CSS的免费2周时间,并且达到了完全相同的效果。

那怎么可能? 试想一下,您花了数千美元购买了在蒂尔达(Tilda)开发网站的服务,并且想要设置自己的链接样式。 一切,用户将无法编辑该站点。 好吧,我夸大了边界板,但是您可以想象任何其他样式,更不用说自定义JS了。 此外,冲突甚至扩展到某种嵌套接口,尽管这是显而易见的。

阻止用户嵌入自己的代码将是解决此问题的方法。 但是在现实世界中,这几乎是不可能的。 您不会为每个用户进行自定义集成。 胖客户可以这样做。 但是,如果您拥有90%的功能,则不会花费5到10美元。
iframe
几乎完全封装页面, iframe将为我们提供帮助。 这可能是我使用iframe这么久的唯一地方。 如果iframe内容位于同一域中,我们甚至可以反之亦然。 这就是为什么我们要控制一切。 但是所有这些封装对我们来说有点困惑。 例如,元素的选择,我们将在稍后讨论。 通过定位在iframe上方还是iframe本身,在接口级别隔离它?
当然,在iframe本身中这样做会更容易。 事实是,滚动内容时,您不必更新选择的位置,也不必考虑巧妙的布局(尽管更好)和其他界面。 但是,如果您在一个document的iframe渲染这样的内容,那么计算您的界面是否重叠,编辑器的界面会更容易。 因此,例如,Grapesjs结合了以下两种方法:

选择是通过iframe元素进行的,并且对重叠敏感的其他功能会呈现在iframe顶部。

但是要支持您的样式,您将必须将所需的所有内容导入iframe 。 立即,您将必须附加加载屏幕,以便用户看不到没有组成的站点/界面。
蜡<head>

因此,您应该理解,只有在编辑时才需要这样做。 并且不要忘记用户风格,否则您将再次遇到问题。
我“不小心”更新了带边框的Grapesjs类:

Grapesjs在突出显示时添加了gjs-comp-selected类,该类在检查过程中清晰可见,相信我,这将是用户为定制而复制的第一件事。
选择元素
我们有点领先,因为我们还不了解如何教会编辑者查看页面上的元素,但这不会伤害我们。 在深入探讨技术上更复杂的主题之前,让我们看一下在页面上选择元素的技术难度:)您认为这很难吗? 如果您非常自信,那么下面是所有上述编辑者如何通过文字示例来解决此问题的方法:
我的编辑

蒂尔达

Grapesjs

Google网页设计师

蜡

而当编辑

一部分文字根本看不到。 哦好 从前端开发人员的角度来看,这是一个功能。

事实是,编辑者大部分会选择DOM模型。 但是,请您自己判断,作为用户,远离网站开发,您认为还好吗? 不,那还不行。 内容不仅仅是编辑器向您显示的内容。 在某些情况下,可能会失去选择项目的能力。 浏览器为开发人员分配这种方式是正常的,这在规范中是正确的。
用户看到的内容(蓝色,使文本变得透明,以解决问题),由编辑器,浏览器(红色)突出显示:

镀铬

火狐浏览器

当选择FF中的文字时,Chrome不会。

那么,为什么在所有编辑人员中都出现这种门槛呢? 以我的经验,我会说这是产品经理和/或测试人员喜欢的面条。 通常,每个在编辑器上工作的人都不太可能设置line-height: 1px ,或尝试使用不同样式和大小的文本。 他们的眼睛模糊,乍看之下这些浅滩基本停留在盲区。 相信我,客户在最初的几分钟内就会遇到他们。
从UI / UX的角度来看,这在技术上可能还不清楚,并且通常由开发人员来决定这种实现细节。
那么是否可以选择一个用户友好的产品呢? 有什么想法如何突出一个元素?
选择必须包括以下内容 保证金 ,填充,边框。 尺寸模型并不简单:

在我的沙箱中:

也许我从msdn中提取的最有用的信息是:

但是,我们的问题没有答案。
让我们首先尝试DOM为我们提供的东西。 我们有这样的布局:
font-size: 54px; line-height: 0px; border: 10px solid; padding: 10px;

可见内容的大小为62px,浏览器显示为40px。 如何获得62px?
getBoundingClientRect返回给我们-40px
clientHeight-20px
scrollHeight-41px
您可以玩很长时间的数学,但是我没有找到使用这种方法的解决方案。
但是就像5年前一样,我知道突出显示文本的关键。 好吧,看,如果您选择文本,则选择与我们所需的完全相同:

这不是一个很好的例子,但是我们面临的主要问题是高度-一切都很酷。 但是如何区分某些系统魔术呢?
这么多年后,我用谷歌搜索(学习了!),不幸的是,我如何用谷歌搜索并且链接丢失了,但是下面是解决方法:
const range = document.createRange(); let rangeRect; range.selectNode(elm); rangeRect = range.getBoundingClientRect();
创建一个range ,选择一个节点,然后从range ClientRect获取它。 瞧! 此外,选择适用于所有内容。 您可以选择整个页面( https://developer.mozilla.org/en-US/docs/Web/API/Range )。
无论高度还是宽度,都是完美的亮点。

(编辑器中的突出显示将是蓝色边框,没有背景。选中的文本显示系统选择。)
突出显示的另一个不太重要的部分是如何显示它? 有什么想法吗? 一堆方法。 从边框开始,以另一个浮动元素结束。
首先,决定在iframe或iframe ,我们在上面讨论了利弊。
边框不适合,因为它会增加元素的大小,如果用户将边框设置为元素会怎样? 与outline相同,Grapesjs通过对其进行选择而犯错。
就我而言,我之前使用::,但这也不是很酷。 最可靠的方法是制作4个条带,并将其放置在边缘(将来将是元素大小调整的元素),或在顶部进行块化。 最好从这两个选项中进行选择,并尽可能地组合它们。 页面定位过多对优化已经超载的UI没有帮助。 因此,您放置的多功能东西越多越好。
那还不是全部
我们刚刚意识到了选择。 但是,这种选择是在即时观察的层面上进行的。 与他相关的另外两个问题,我将让您自己考虑。 他们不是那么讨厌。
- 元素的尺寸在编辑时会更改。 您需要对此进行跟踪并更新选择。 这正是我的编辑和Google Web Designer讨厌的。 并非总是如此,但经常如此。
- 要在元素上进行标签/选择,让用户知道该元素是什么,您需要知道它是什么。 因此,应在编辑器中初始化元素。 编辑器的性能取决于此。 一个页面上可以有一百多个元素,并且在启动时仅获取并初始化所有内容并不总是最好的主意。 但是就我的编辑而言,还可以。 哈哈 可以通过单击鼠标悬停,使用频率理论来完成初始化。
编辑中
由于我们开始谈论用示例文本突出显示,因此让我们快速进行编辑。
实际上,在图片和突出显示之后,文本是编辑器中的第二重要部分:)
好吧,这是一种制作方法,以便当我选择部分文本并单击某些格式化功能时,我将完全格式化所选文本吗?
如果您是一位朋友的母亲的儿子,并且是一位聪明的开发人员,那么您一定会说-包裹选定的文本。 哦,您会说对了,好像Ilon回答说要制造一枚火箭===雇用一百名工程师。
包装选定的文本不是那么容易。 结果,会有很多标签,如何在以后的选择和格式化中保存它们是一个很大的问题。 我研究了同一个CKEditor很长时间了,发现了一个奇迹:
contentEditable
( https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/contentEditable )
这是浏览器中的薄煎饼编辑器。 它不仅为我们提供了编写文本的机会,还使我们可以格式化文本。
相关文章:
通过此API,您可以对选定的文本执行格式化命令:
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
, , , .
. , , . , . . , .
contentEditable . , . . , . .
, contentEditable , CKEditor, CodeMirror, . . , .
, . , , CKEditor. , . , , . iframe . , . , /. contentEditable . contentEditable . Wix, 2018 . , iframe . :) , , . , , . . , . , .
:

:

.
, , , , / , / . 0,0 , :

(svg/dom element)
, VC++, MVC
, , Visual C++, C#, Delphi . - , Backbone , , //.

, - , , , . :

, , .
, CSS, .
Backbone, (View), (Model) (Collection). (Router). View. MV*, MVV, .
, Backbone, . View . CSS . , View .
, , View . View Model . , . , View . , . , .parent .

View , View Model, data- . , Model , . , Backbone, React, DOM, . , . 50-100 - .
, , HTML. , , . virtual dom, JS. — . !, . Wix, :
:

:

, :

, . . React.
CSS , . , HTML, . , .
, <style> . , . .
data- , html . !== . html . , ID, , .
//
. , . . , , .
. . .
React? Polymer? Vue ( )? Angular (!)?
3 , React Polymer, React Web Components.
, (Polymer), . . . Shady DOM , , . , .
React
:) . React :
const rootElement = document.getElementById("root").contentDocument.body; ReactDOM.render(<App />, rootElement);
HTML, ReactDOM.hydrate(element, container[, callback]) , - DOM React. . 太棒了 , , Virtual DOM . .
, . Redux, Flux, Mobx . Redux, .
Marrionett . Backbone. . .
, . ? React, . DOM? ? ReactDOM.hydrate HTML? , .
Responsive and Adaptive
. , , . 960px. , , - . .
, , . , .

, relative . , . . . .

( )
, . , , , . .

03
, . . .

960px, . .
, , . Wix, . , .
. 是的是的 , , , — .

. :)
12 , , .
12 , ? https://grapesjs.com/ , .

, , . , . . .
, /,
. . , . . , UI/UX.



- , , , — .
, , , . . , , .
. C . UI/UX. , undo/redo , . , HTML localStorage… , .

. , , — . , , .
PS . , . , :)