概述

WijmoJS 的客户通过技术社区(GCDN)联系我们,表示他们已准备好从Wijmo 3(基于JQuery的前端开发工具包)迁移到当前版本的WijmoJS,但他们需要一个Ribbon控件,不基于任何 Javascript 库。

最初,我们考虑创建一个新控件并将其添加到WijmoJS的nav导航模块,以及TreeView(树状图控件)和TabPanel(选项卡控件)中。 但经过一些研究,我们意识到使用TabPanel实现 Ribbon 功能区非常简单,因此不需要任何新的控件。

Ribbon(一种电脑用户界面)

Ribbon即功能区,是新的 Microsoft Office Fluent 用户界面 (UI) 的一部分。 在仪表板设计器中,功能区包含一些用于创建、编辑和导出仪表板及其元素的上下文工具。它是一个收藏了命令按钮和图示的面板。

它的本质把工具栏的命令,用一组组的"标签"进行组织分类,每一组包含了相关的命令。每一个应用程序都有一个不同的标签组,展示了程序所提供的功能。在每个标签里,各种的相关的选项被组在一起。

Wijmo 3的wijribbon控件

Wijmo 3(wijribbon)附带的功能区控件如下所示:

Wijmo 3 Ribbon Control

与大多数功能区控件一样,它提供了一个选项卡式UI,其中每个选项卡都包含命令组。 命令通常是按钮或下拉菜单,但可以使用任何UI控件。

WijmoJS的JavaScript功能区控件

为了在WijmoJS中实现类似的功能,我们使用了TabPanel 控件和一些CSS。

这就是 WijmoJS 功能区控件的样子:

Wijmo JavaScript Ribbon Control

其默认外观类似于现代UI和Material Design,但当然可以使用CSS轻松且广泛地自定义。 由于这个新功能区使用WijmoJS,它没有依赖任何前端组件库,完美适用于移动和桌面设备。

WijmoJS Ribbon控件架构

正如我们所提到的,WijmoJS 功能区控件实际上是一个TabPanel 扩展。 选项卡包含组元素。每个组元素都有一个托管命令控件的内容区域(wj-content)和一个显示组名称的头文件(wj-header)。

每个组内容(wj-content)元素包含具有列(wj-column)和/或行(wj-rows)的元素。 这允许设计者更加灵活地控制并定义组内容的布局。行和列元素托管命令控件,可以是常规HTML元素或其他WijmoJS控件类型。

这是用于定义功能区演示中第一个组的标记。请注意层次结构,其中每个选项卡包含两个元素(选项卡标题和内容),选项卡内容元素又包含组元素列表,这些组元素也有两个子组(组头和内容)。 组内容元素又包含用于布局各个控件的行和列元素的集合:

<div id="ribbon">

  <!-- Format tab -->
  <div>
    <div>Format</div>
    <div>
      <div class="wj-group">

        <!-- Group content (Action) -->
        <div class="wj-content">
          <div class="wj-column">
            <button id="save" class="wj-btn wj-btn-large">
              <i class="material-icons">save</i>
              <br/>
              Save
            </button>
          </div>
          <div class="wj-column">
            <div class="wj-row">
              <button id="undo" class="wj-btn" aria-label="Undo">
                <i class="material-icons">undo</i>
              </button>
              … more buttons in the row …
            </div>
            <div class="wj-row">
              <button id="cut" class="wj-btn" aria-label="Cut">
                <i class="material-icons">&#x2702;</i>
              </button>
              … more buttons in the row …
            </div>
          </div>
        </div>

        <!-- Group header -->
        <div class="wj-header">
          Actions
        </div>
      </div>

我们选择使用HTML标记指定功能区内容,因为它提供了灵活且熟悉的示例。此外,可以使用JSON文件或其他一些数据结构中提供的代码和数据填充功能区。

其他功能区行为

除了标准的TabPanel功能外,我们还添加了一些代码,用于在用户双击选项卡标题区域(如MS色带)时切换功能区内容,并在用户单击选项卡时显示选项卡区域:

// create ribbon
var ribbon = new wijmo.nav.TabPanel('#ribbon');

// toggle ribbon content visibility on double-clicks, restore on clicks
var headers = document.querySelector('.wj-tabheaders');
headers.addEventListener('dblclick', function (e) {
  if (!wijmo.hasClass(e.target, 'wj-tabheader')) {
    wijmo.toggleClass(ribbon.hostElement, 'hide-content');
  }
});
headers.addEventListener('click', function (e) {
  if (wijmo.hasClass(e.target, 'wj-tabheader')) {
    wijmo.toggleClass(ribbon.hostElement, 'hide-content', false);
  }
});
我们还定义了一个addTooltips函数,它扫描功能区(或任何其他 WijmoJS 控件)中的所有元素,并根据所包含控件的aria-label属性添加工具提示。这样做增强了应用程序的可访问性,并且无需保留冗余标签信息(如aria-label和title属性):
// add tooltips based on the element's aria-label attribute
function addTooltips(ctl) {
  var tt = new wijmo.Tooltip(),
      els = ctl.hostElement.querySelectorAll('[aria-label]');
  for (var i = 0; i < els.length; i++) {
    tt.setTooltip(els[i], els[i].getAttribute('aria-label'));
  }
}

我们还定义了一个addTooltips函数,它扫描功能区(或任何其他 WijmoJS 控件)中的所有元素,并根据所包含控件的aria-label属性添加工具提示。这样做增强了应用程序的可访问性,并且无需保留冗余标签信息(如aria-label和title属性):

// add tooltips based on the element's aria-label attribute
function addTooltips(ctl) {
  var tt = new wijmo.Tooltip(),
      els = ctl.hostElement.querySelectorAll('[aria-label]');
  for (var i = 0; i < els.length; i++) {
    tt.setTooltip(els[i], els[i].getAttribute('aria-label'));
  }
}

命令控件

每组中的控件都是正常创建和使用的:

// populate combos
var fontFace = new wijmo.input.ComboBox('#font-face', {
  itemsSource: 'Arial,Courier New,…,WingDings'.split(','),
  textChanged: function(s, e) {
    execCommand('fontName', s.text);
  }
});
var fontSize = new wijmo.input.ComboBox('#font-size', {
  itemsSource: 'Very Small,Smaller,…,Very Large'.split(','),
  selectedIndex: 3,
  textChanged: function(s, e) {
    execCommand('fontSize', s.selectedIndex + 1);
  }
});

常规HTML按钮和输入元素也是如此:

// execute commands
ribbon.hostElement.addEventListener('click', function(e) {
  switch (e.target.id) {

    // format group
    case 'save':
      localStorage.editorContent = document.getElementById('editor').innerHTML;
      alert('Document Saved to Local Storage.');
      break;
    case 'undo':
    case 'redo':
    case 'preview':
    case 'removeFormat':
    case 'cut':
    case 'copy':
    case 'paste':
    case 'selectAll':
      execCommand(e.target.id);
      break;

    // font group
    case 'bold':
    case 'italic':
    case 'underline':
    case 'strikethrough':
    case 'subscript':
    case 'superscript':
      execCommand(e.target.id);
      break;

    case 'click-me':
      alert('Wijmo Ribbon Sample');
  }
});

圆满结局

我们的故事有一个圆满的结局:我们将sample发送给客户,他们能够将他们的应用程序从Wijmo 3迁移到 WijmoJS 中。 在此过程中,他们减少了应用程序的依赖性,并使其与移动/触摸设备完美兼容。 TabPanel控件已经提供了足够的功能和灵活性,客户不必进行任何更改或向WijmoJS添加任何代码。