从头开始弹出模式弹出

分享于 

24分钟阅读

Web开发

  繁體

模态弹出

注意:形态是外部力的一个方面,由语法设备( 就是 moods ) 表示,表示
  • 说话者的illocutionary或者一般意图,或者
  • 致力于表达命题。obligatoriness。满意或者现实的表达可以信度的扬声者。
SIL国际, 语言术语词汇表什么是情绪和情态?

1 为什么模式弹出?

术语"模态弹出"doubly混乱。 模式弹出控件元素与本机应用程序编程中理解的不同,因为它们在本地应用程序编程中是理解的,在Web编程中理解它们不是。 但是,它们在某些广义意义上是"模态模式": 激活的模式弹出时,创建一个特殊模式,允许用户只使用这里弹出元素进行交互。 尽管这些元素控制用户交互流,但它们并不阻止代码的执行流程,因为传统的对话框或者模式 Windows 是这样做的。 我将讨论这个差异 下方 。有关模式窗口概念的详细概述,请参见 https://en.wikipedia.org/wiki/Modal_window

模式弹出元素在网络编程中非常重要,具体原因如下。 历史上,创建与主窗口分离的控件元素的方法之一是通过代码创建单独的浏览器窗口,这称为"弹出式菜单"。 even这种技术完全合法,虽然 earned reputation,但它的名声非常糟糕,主要是因为annoying广告 practice advertisement advertisement advertisement Windows。 另一种模式元素( 与传统的对话框或者模式 Windows 类似,使用阻塞调用) 是一组三个函数,alertconfirmprompt 都可以在实际生产应用中被认为是可以接受的。 在开发过程中,他们非常有用,以显示未处理的异常信息,这将作为未固定的Bug。

这些技术相比,模式弹出不会创建任何 Windows,因为它在宿主操作系统中被理解,因此不在"窗口"的意义上。 模态控制元素仅在单个页面上模拟,并且可能仅与实际窗口的样式相似。 它实际上只创建了这个页面上的UI模式,它阻止了用户访问页面的所有元素,除了弹出。 令人惊讶的是,这种方法解决了上面提到的所有问题。

在目前的模式弹出工具中,大多数是 jQuery UI 元素,如jQuery对话框向导或者第三方 Plug-Ins,但是可以在其他框架中实现,如我在本文中所提供的代码。 但是,本文的一个重要目标是解释: 为什么不是模式弹出我将讨论最后一个中模式弹出的缺点文章的一部分

2 为什么从头开始?

因为不是每个人都想要使用大的JavaScript框架,jQuery或者其他任何。 我看到了一些问题,查询需要创建一些客户端呈现效果,而不需要任何 3的方框架。 我也喜欢简约的方法,让一切都在我的控制之下。

最后,但重要的是,理解一切在更基本的层次上是如何工作的。 它认为解释它是有用的。

3 如何?

下面是这个想法:

首先,当输入模态状态时,可以对浏览器窗口的整个客户区进行调光,除了弹出元素。 很容易实现,让我们拥有一些元素,div,覆盖整个客户区。 为了获得效果,我们总是可以将它的不透明度设置为 0到 1之间的值,这个值可以是可选的。 在这个元素的顶部,我们可以使用消息文本。按钮等方式放置,元素。

除了调光效果之外,调光器还将从弹出元素中隔离页面上的所有元素。 鼠标事件不会超过调光和弹出元素。 它是否将页面与所有用户交互隔离开来,除了? 目前还没有。由于Alt+key或者Alt+Shift+key键盘事件,输入元素上的元素仍可以通过键实现,这通常是通过或者键盘事件来实现的。

我结论,阻止这种交互的唯一可以靠方法是暂时禁用页面上的所有输入元素,不包括弹出元素。 当弹出模式启动时,很容易记住具有已经修改/禁用状态的元素集,并自动恢复弹出模式。

基本上,我已经共享了这个功能的所有基本思想及其实现。 在使用more的情况下,我不会解释所有的用法选项;相反,我提供了一个详细的演示应用程序,在与代码结合使用时,演示代码是自我说明的。演示用户界面 ,只是一些评论。 它会留下一些行为和实现的精致时刻,我将在下面尝试描述。

4 操作原理

首先,我的灵活性方法与jQuery非常不同,其中模式弹出是由现有的HTML标记组成的。 没错,modalPopup.show的用户可以完全一样,但这并不是最基本的用法。 我认为最基本的使用最少的用法应该简单得多: 只需使用一些消息字符串进行调用:

modalPopup.show("Some HTML content");

这里调用显示带有预设默认按钮和默认样式的弹出菜单。 其他所有特性都有额外的可选函数参数。 ( 实际上,所有参数都是可选的;参见第一个演示案例"默认值",在" demo.html 。)

功能集的限制是很好的: 这样就很难分解出基本的渲染和行为: 对称外观,甚至按键分布,键盘操作基于按键,拖动和其他预定义处理鼠标和键盘事件等。

那么,现有的HTML标记如何在类似于jQuery对话框的方式中使用? 这是个很简单的事情: 将某些现有DOM元素移到弹出元素 messageWindow。 这可以在基本功能之上完成: 带有HTML标记的元素转换为字符串,它可以进一步用作调用函数 modalPopup.show的第一个参数。 它可以通过 helper 函数。modalPopup.prepareContent 或者 modalPopup.prepareContentById 来完成;请参见 下面显示的代码 fragment 这些函数在获取 innerHTML 字符串后从DOM树移除现有的HTML元素。

有关某些演示,请参见名为"格式化格式"的演示之一:

格式化格式

对格式化功能集的控制是基于我最近""文章中建议的"命名函数参数"方法之一。JavaScript函数的命名参数,第二部分: 进行结构化 用户可以修改一些格式化选项,定义按钮,它是可选属性和可选动作,并定义当模式状态结束时执行的动作。

我将只描述弹出 messageWindow 样式的一个最重要的元素。 options选项are元素的宽度定义为选项,内容格式为 formatted,或者根据消息的按钮部分,或者弹出窗口中的按钮部分定义宽度,而不管是否出现更宽的窗口。 默认的选项是默认的,默认宽度可以通过修改属性 styles.width的修改来修改。 要使用width-to-content格式,应将这里属性设置为 null。 false 或者 0也可以使用,但不是 undefined,因为 undefined 是用于应用默认结构中的值的特殊特性。 这在用例"。宽度到内容,均衡按钮宽度"。"内容的宽度,以消息文本为主"和同样的"格式化格式"案例中演示。 请看 演示应用程序

缺省的缺省机制并不那么简单;它由函数 populateWithDefault 实现;有关详细说明,请参见我的文章专用于这个机制,。 JavaScript函数的命名参数,第二部分: 进行结构化

功能的最重要的方面是没有阻塞操作工作流,所以操作只与" MessageBox.Show"和类似的API相同。 ,和它的他模态 Windows 提供了 block 当前执行流的方式,同时输入事件流通过模态窗口,直到结束。 模式弹出菜单中没有类似的内容。 这只是用户界面模式,它阻止用户与浏览器窗口的其他元素交互。 对 modalPopup.show的调用不执行 block 并立即返回,而用户在"模态模式"模式下继续工作。 在演示应用程序窗口底部部分的测试用例中演示了这一点。 你可以比较 JavaScript alert 和模式弹出用例的行为。 同样的原因,模式弹出不会返回任何内容。 因为调用在用户做出任何决定之前返回,所以这将是无用的。 相反,开发人员可以定义特定于每个按钮和/或者在模态状态结束时调用的操作。 这里时,模态弹出内容的所有控件仍然可以访问,这是在上演示用例"关闭操作""

执行流没有被阻塞的事实与单一模型紧密相关。 实际上,如果应用程序已经处于模态状态,则显示另一个模式弹出是无用的。 这是 modalPopup 单元的骨架:

var modalPopup = {
 show: function (content, buttonDescriptors, styles, onEndModalState) {
 if (!this.instance) {
 //.. .this.instance = newfunction () {
 //.. .this.dimmer = document.createElement("div");
 this.messageWindow = document.createElement("div");
 //.. .this.show = function (
 content,
 buttonDescriptors,
 styles,
 endModalStateHandler) {
 // define content of this.messageWindow// and all the properties// define event handlers for buttons// and the end of modal state handler// show it all  } //this.show//.. . } //this.instance constructor } //if this instance was not yet definedthis.instance.show(content, buttonDescriptors,
 styles, onEndModalState);
 } //show prepareContent: function (element) {
 var content = element.innerHTML;
 element.parentNode.removeChild(element);
 return content;
 }, //prepareContent prepareContentById: function (id) {
 return modalPopup.prepareContent(document.getElementById(id));
 } //prepareContentById} //modalPopup

可以看到,模式弹出的两个顶级元素只创建一次: dimmermessageWindow。在调用实例成员( 属性) 函数 show 时重新创建所有 messageWindow的内容。 messageWindow 事件的输入事件处理程序,只是在页面模式状态中修改了这里对象的输入事件处理程序,以确保不会对该对象的行为进行修改和修改。 我将在这些事件中解释需求 下方

临时禁用的元素

现在,这是模态状态的核心功能: 文档输入元素暂时禁用。 对带有修改的禁用属性元素的引用保存在上下上下文的对象中,并在模式状态结束时恢复。 这就是它的工作方式:

var list = []; //.. .var disableAll = function (list, exclusion, parent) {
 modalPopupIsShowing = true;
 if (parent == exclusion) return;
 var objectSample = {};
 for (var index in parent.childNodes) {
 var child = parent.childNodes[index];
 disableAll(list, exclusion, child);
 if (typeof child == typeof objectSample
 && "disabled"in child &&!child.disabled) {
 child.disabled = true;
 list.push(child);
 } //if } //loop} //disableAllvar modalClosing = function (itself, list) {
 //.. .for (var index in list)
 list[index].disabled = false;
 //.. .} //modalClosing

函数 disableAll 是递归的;当用元素 document.body 调用时,它将禁用页面上的所有元素。

但这并不是目前" modalpopup.js"中的代码;below,我将解释为什么。

Mozilla解决方案

在上面显示的代码 fragment 已经准备发布之后,我注意到Mozilla浏览器( 基于壁虎)的令人失望的行为: 在Mozilla中通过Alt+Shift+key激活的一些访问键在模式状态下没有工作。 为什么只有一些快速检查确认了我的猜测:? 因为一些匹配访问键是为主窗口上的某些元素定义的。 当页元素被禁用时,这些访问键非常自然地操作,但它们也不能操作显示的可以见元素。 一些附加测试显示,即使通过样式属性或者将元素设置为 "hidden" 或者 "collapse",或者通过样式属性 display 设置为 "none",访问键的访问键也会被隐藏。

这看起来完全不合逻辑,因为如果无法使用访问键,它们就不应该干扰启用的元素。 这就是 behind 禁用或者隐藏元素的整体思想。 基于 webkit 布局引擎( 或者眨眼)。Google Chrome。Chromium 和 Opera的浏览器上没有类似的问题。 此外,当两个或者多个可见的元素使用相同的访问键时,它们显示功能非常方便。

当然,该解决方案只需要在模态状态前后两部分中添加/修改两行。 除了禁用之外,当模态状态结束时,元素的所有访问键都应临时取消并恢复:

var list = []; //.. .var disableAll = function (list, exclusion, parent) {
 modalPopupIsShowing = true;
 if (parent == exclusion) return;
 var objectSample = {};
 for (var index in parent.childNodes) {
 var child = parent.childNodes[index];
 disableAll(list, exclusion, child);
 if (typeof child == typeof objectSample
 && "disabled"in child &&!child.disabled) {
 child.disabled = true;
 list.push({ element: child, accessKey: child.accessKey });
 child.accessKey = undefined;
 } //if } //loop} //disableAllvar modalClosing = function (itself, list) {
 //.. .for (var index in list) {
 list[index].element.disabled = false;
 if (list[index].accessKey)
 list[index].element.accessKey = list[index].accessKey;
 } // loop//.. .} //modalClosing

由于元素弹出 messageWindow 上存在匹配访问键,在主页面上禁用某些访问键,这是因为在模式状态结束后的处理程序中删除了它的内容。

模态状态 modalClosingmodalClosed的两个阶段之间的隔离是由一些完全无关的原因完成的。 在调用这两种方法之间,如果按钮提供的开发人员提供了关闭按钮操作,endModalStateHandler 也可以提供。 请查看完整的代码以获得更详细的详细信息。

演示 Bug 只需要几行代码。 我在Mozilla方面找不到 Bug 报告,所以我向Mozilla报告了它: https://bugzilla.mozilla.org/show_bug.cgi?id=1230387

拖动

我不认为模式弹出元素实际上是非常重要的,尤它的是当用户使用( 但是,透明度级别是可选的,因此 background 中的内容可以完全可见) 时,这是不好的。 有一个与拖动有关的微妙问题: 没有鼠标捕获。 在某些DOM元素上处理鼠标移动事件,快速运动可以轻松地将鼠标指针移到元素之外,这将破坏拖动状态。 已经知解决方案是对对象 window 处理这里事件,这显然需要处理鼠标的事件。 added added,added added,another,apparent,symmetric,symmetric,:,:,:,:,window,window,window,window,window

var modalClosing = function (itself, list) {
 window.removeEventListener("resize", windowResizeHandler)
 window.removeEventListener("mousemove", windowMouseMoveHandler);
 window.removeEventListener("mouseup", windowMouseUpHandler);
 for (var index in list)
 list[index].disabled = false;
 hide(itself.messageWindow);
 hide(itself.dimmer);
 modalPopupIsShowing = false;
} //modalClosingthis.show = function (
 content,
 buttonDescriptors,
 styles,
 endModalStateHandler) {
 //.. .if (allowDragging) {
 window.addEventListener("mouseup", windowMouseUpHandler);
 window.addEventListener("mousemove", windowMouseMoveHandler);
 }
 //.. . window.addEventListener("resize", windowResizeHandler);
} //this.show

还有一个 window 对象事件从未被移除: beforeunload ;用于结束模态状态,如果用户决定重新加载页面而不结束模态状态,则重要。

所有其他实现细节或多或少都是微不足道的;请下载完整的代码来了解它的工作原理。

5 模式弹出和演示代码

所有模式弹出功能都放在单个文件" modalpopup.js"中,它不依赖于任何其他文件。 可以下载包中提供的它的他三个文件与演示代码" demo.html"相关,它本身非常复杂,包含了很好的用例。

我保证 上方上方 ,我不会解释所有的用例和使用技巧;代码示例本身可以帮助学习用法和所有选项。 演示用户界面的外观如下:

演示应用程序

这个演示涵盖了布局选项 上述描述 按enter键,不同的按钮描述及其属性,按键键说明的定义,escape键 press,事件处理程序,禁用/启用拖动,样式等等。

演示使用的另外两个JavaScript文件是" namedcaller.js"," autoaccesskey.js"。

"namedcaller。js"用于方便使用多个参数调用函数,这些参数使用我在它的他最近的文章中建议的命名参数。"命名参数",其中详细说明了这里技术: JavaScript函数的命名参数,但另一种方法

对于其他JavaScript文件" autoaccesskey.js",它也用于方便,与本文的主题无关。 这只是一个小小的奖励。

6 小奖金

java函数的作用是将字符串表示为带下划线的访问键的HTML字符串,它的成员函数 next(value, forceIndex) 返回一个经过转换的HTML字符串,它的成员函数返回一个转换后的HTML字符串和一个访问键。 如果网页上的所有访问键都使用这里工具进行选择,则它保证它的唯一性。 第一个参数 value 应该是一个没有HTML标记的字符串,它被添加到返回的对象中。 第二个是可选参数 forceIndex,指示首选访问键的字符串索引,但只选择了可以能的( 该索引有效且选择不破坏唯一性)。 在这里首选项之上,选择按特定顺序执行: 只使用字母字符,大写字母被视为第一个。

这个实现有一个问题。 然而,原生JavaScript函数缺少将字符分类为字母和非字母的特性。 classification classification是指 lowercase 字母和大写字母之间的区别,但只适用于窄的语言子集,因为这些语言中的narrow只对表示小写或者大写字母的Uthe字符( 对应大小写或者大写字母) 起作用。 那些需要在没有小写字母和大写字母的情况下使用其他语言的人可以修改我的代码以使用特定的区域性。 对不起,但这个代码适合我的立即目的,这个示例应用程序。

7 你的用户可能不喜欢这么多

我意识到,提供一些代码并阻止它同时使用是非常不常见的,但这正是本文中最重要的部分。

不应使用模态行为。 你的用户可能不喜欢这么多。 是的,类似的特性应该在每个软件开发人员的工具箱中,这就是我提供这个代码的原因。 我建议在使用任何种类的模式行为之前要先考虑一下可以能的选择。

例如,在模态控制元素中显示异常信息或者某些它的他问题报告是非常糟糕的。 为什么在这样的情况下中断用户活动? 你希望从用户那里得到什么? 如果应用程序从问题中完全恢复,用户可以能不需要对它进行太多的注意。 如果问题阻止进一步的活动,则某些控件将被禁用。 在任何情况下,解释一些状态线或者它的他类似的非模态元素会更好。 只有当用户决定做它的他事情时,用户才会读取这些信息,并帮助克服某些问题。

在少数情况下,当下一步不可以逆时,重要的是要注意用户的情况。 但首先要注意的是: 可能实现"撤消";如果是,则首选"撤消"。 请参见: http://alistapart.com/article/neveruseawarning

有关使用情况,可能出现的问题和建议的更多信息,请参见:

用例问题推荐的工具 ...

UI设计和精细UI的开发不是一件简单的事情。 首先需要的是能够扮演用户的角色并了解活动用户的领域。


相关文章