Статьи

31 день Windows 8 для HTML5 | День № 16: Контекстные меню

Эта статья посвящена Дню № 16 из 31-й серии Windows 8 . Каждая из статей этой серии будет опубликована как для HTML5 / JS, так и для XAML / C # . Вы можете найти дополнительные ресурсы, загрузки и исходный код на нашем сайте .

advertisementsample


Сегодня мы сосредоточены на контекстных меню, известных как PopupMenu . Это те маленькие маленькие всплывающие команды, которые время от времени появляются в вашем приложении, когда вы щелкаете правой кнопкой мыши по чему-либо. Microsoft предлагает очень конкретные указания относительно того, когда использовать эти контекстные меню, а не когда использовать элемент управления AppBar, поэтому мы будем следовать этим правилам в этой статье. 

Что такое контекстное меню?

Если вы вообще использовали Windows 8, вы наверняка сталкивались с этим раньше. Часто они появляются в результате щелчка правой кнопкой мыши на том, что вы не можете выбрать, или на тексте, с которым вы хотите взаимодействовать. Вот краткий пример контекстного меню:

(изображение с http://msdn.microsoft.com/library/windows/apps/Hh465308 )

Вы также можете запустить контекстное меню из элемента на вашей странице, который не может быть выбран, как это изображение в моем примере приложения:

 образ

Щелчок правой кнопкой мыши по изображению запускает центр контекстного меню прямо над ним. (Я покажу вам, как это сделать дальше.) Каждому из элементов команды будет назначено действие, которое выполняется при нажатии на элемент.

Создание контекстного меню

Создание контекстного меню, которое вы видите выше, довольно просто. Для начала мы подключим обработчик к нашему элементу изображения таким образом, что каждый раз, когда кто-то щелкает правой кнопкой мыши на объекте, он получает наше контекстное меню. Это похоже на любой другой приемник событий, и мы будем слушать «contextmenu» как таковое.

document.getElementById("myImage").addEventListener("contextmenu",
    imageContentHandler, false);

Далее нам нужно создать наш обработчик, который мне удалось вызвать imageContentHandler, я знаю довольно удивительные названия. В нашей функции мы просто начнем с создания объекта PopupMenu и добавления элементов, которые мы хотим показать. У каждого элемента также может быть свой обработчик события, и в приведенном ниже примере я просто даю им один и тот же обработчик событияthingHandler (я знаю более удивительные названия).

var contextMenu = Windows.UI.Popups.PopupMenu();

contextMenu.commands.append(
    new Windows.UI.Popups.UICommand("Clark Sell", somethingHandler));

contextMenu.commands.append(
    new Windows.UI.Popups.UICommandSeparator());

contextMenu.commands.append(
    new Windows.UI.Popups.UICommand("Jeff Blankenburg", somethingHandler));

contextMenu.commands.append(
    new Windows.UI.Popups.UICommand("31 Days of Windows 8", somethingHandler));

contextMenu.commands.append(
    new Windows.UI.Popups.UICommand("Edit", somethingHandler));

contextMenu.commands.append(
    new Windows.UI.Popups.UICommand("Delete", somethingHandler));

С нашим определенным PopupMenu, теперь нам просто нужно показать его. Мы можем сделать это, вызвав showAsync и передав ему некоторые координаты x, y, как показано ниже.

contextMenu.showAsync({ x: [someCoords], y: [someCoords] });

Теперь, как мы выясним, где именно это поставить?

Определение местоположения

Возможно, вы заметили, что контекстные меню появляются прямо над и центрированы по выбранному элементу. Это не происходит волшебством. На самом деле мы должны сами определить положение элемента, на который нажали (а также любые применимые смещения), и передать его, когда мы покажем меню. Время точить карандаши.

Когда пользователь нажимает на наше изображение, наше событие contextmenu запускается , вызывая наш обработчик imageContentHandler . Это собирается передать некоторые аргументы, которые мы должны начать наш факт установления. Здесь мы ищем три критически важных данных. 1. x и y щелчка и 2. смещение элемента, который был его целью, и 3. ширина целевого объекта. (целевым объектом здесь является изображение). Давайте посмотрим код, а затем вернемся к нему.

function showWhereAbove(clickArgs) {
    var zoomFactor = document.documentElement.msContentZoomFactor;
    var position = {
        x: (clickArgs.pageX - clickArgs.offsetX - window.pageXOffset + (clickArgs.target.width / 2)) * zoomFactor,
        y: (clickArgs.pageY - clickArgs.offsetY - window.pageYOffset) * zoomFactor
    }

    return position;
}

Итак, я создал эту простую функцию с именем showWhereAbove, которая принимает нечто, называемое clickArgs . clickArgs — это не более чем аргументы, переданные в наш обработчик contextmenu . Чтобы выяснить, x и y на самом деле в значительной степени одинаковы.

x = (где x щелчок был — смещение к вершине цели — смещение окон x + (ширина цели / 2)) * коэффициент масштабирования окна

Давайте продолжим разбирать это

  • где х клик был = х позиция мыши на момент клика
  • смещение к вершине цели = насколько справа от элементов левого края мы находимся
  • window x offset = где мы находимся относительно прокручиваемого окна
  • target width / 2 = нам нужно переместить PopupMenu в середину объекта, поэтому мы собираемся взять ширину и получить середину
  • коэффициент масштабирования окна = если экран увеличен, примените этот коэффициент

Теперь ось y в принципе совпадает с осью x, за исключением того, что нам не нужно беспокоиться о высоте цели. Поскольку мы работаем с нижним центром контекстного меню, достаточно получить смещение по оси Y, чтобы поместить нижнюю часть PopupMenu в правильное положение.

Снова запомните — мы пытаемся расположить нижнюю середину всплывающего меню. Теперь, когда мы знаем свою позицию, нам просто нужно показать это.

contextMenu.showAsync(showWhereAbove(args));

Вот готовая функция:

function imageContentHandler(args) {
    var contextMenu = Windows.UI.Popups.PopupMenu();

    contextMenu.commands.append(
        new Windows.UI.Popups.UICommand("Clark Sell", somethingHandler));
    contextMenu.commands.append(
        new Windows.UI.Popups.UICommandSeparator());
    contextMenu.commands.append(
        new Windows.UI.Popups.UICommand("Jeff Blankenburg", somethingHandler));
    contextMenu.commands.append(
        new Windows.UI.Popups.UICommand("31 Days of Windows 8", somethingHandler));
    contextMenu.commands.append(
        new Windows.UI.Popups.UICommand("Edit", somethingHandler));
    contextMenu.commands.append(
        new Windows.UI.Popups.UICommand("Delete", somethingHandler));

    contextMenu.showAsync(showWhereAbove(args));
}

 

Запуск контекстного меню из выделенного текста

На самом деле, почти все в этом процессе одинаково, за исключением математики о том, откуда взяться коробке. Первоначально, когда мы решили решить эту проблему, я надеялся добавить в существующее контекстное меню, которое уже появляется, когда вы щелкаете правой кнопкой мыши по тексту:

16-XAML-TextMenuDefault

Как оказалось, вы не можете (по крайней мере, что мы знаем). Итак, для нашего примера, скажем, мы хотим сохранить все эти параметры, но также добавим новый под названием «Удалить» внизу. Чтобы сделать это, мы собираемся создать свой собственный. Хотя мы уже знаем, как это сделать, есть два отличия:

  • Нам нужно поместить наше PopupMenu вверху выбранного текста и посередине.
  • Остановите поведение по умолчанию.

Например, подключить обработчик события к событию contextmenu, например, к элементу <p> .

document.getElementById("myInputBox").addEventListener(
            "contextmenu", inputHandler, false);

— совет — я использую элемент абзаца здесь для демонстрации. Из-за этого мне нужно сделать свой элемент выбираемым. Я сделал это в CSS так

p {
    -ms-user-select: element;
}

Теперь нам нужно создать наш обработчик в этом случае inputHandler. Помните, я сказал, что нам нужно предотвратить дефолт и сделать свое дело. Для этого мы будем вызывать protectDefault И мы увидим, был ли выбран какой-то текст. В этот момент мы можем создать наше PopupMenu и показать его.

function inputHandler(args) {

    args.preventDefault();

    if (isTextSelected()) {
        //create the PopupMenu and its items
     
    }
}

function isTextSelected() {
    return (document.getSelection().toString().length > 0);
}

После того, как ваш PopupMeu создан, нам нужно показать его, но в отличие от того, когда мы вызывали showAsync (), на этот раз нам нужно вызвать showForSectinoAsync . Так как мы собираемся показать выше выборку, нам нужно понять, что именно было выбрано, а не только сам элемент.

contextMenu.showForSelectionAsync(
    showForSelectionWhere(
        document.selection.createRange().getBoundingClientRect()));

Вы можете видеть, что я снова создал вспомогательную функцию showForSelectionWhere, чтобы позаботиться об этой математике. Мы собираемся передать ему ограничивающий прямоугольник нашего выделения. Давайте посмотрим на код, а затем вернемся к нему.

function showForSelectionWhere(boundingRect) {
    var zoomFactor = document.documentElement.msContentZoomFactor;

    var position = {
        x: (boundingRect.left +
            document.documentElement.scrollLeft -
            window.pageXOffset) * zoomFactor,

        y: (boundingRect.top +
            document.documentElement.scrollTop -
            window.pageYOffset) * zoomFactor,

        width: boundingRect.width * zoomFactor,
        height: boundingRect.height * zoomFactor
    }

    return position;
}

showForSelectionAsync принимает объект с 4 свойствами; х, у, ширина, высота. Давайте посмотрим на х быстро.

  • x = левый край ограничительного прямоугольника + любые пиксели, прокручиваемые внутри элемента контейнера — смещение прокрутки окна * коэффициент масштабирования
  • у в основном такое же, как х, другая ось.

Очень похоже на то, когда мы работали с другим элементом изображения, кроме того, что мы должны выяснить свою позицию внутри элемента, частью которого мы являемся. Результаты должны быть такими, как вы ожидаете.

образ

Резюме

Сегодня мы познакомились с искусством создания встроенных контекстных меню для наших пользователей. Они являются отличным способом обеспечения взаимодействия с элементами, которые нельзя выбрать, или для команд, которые имеют больше смысла непосредственно рядом с элементом, с которым взаимодействует.

Если вы хотите увидеть весь пример кода из этой статьи, щелкните значок ниже:

downloadHTML

Завтра мы углубимся в функциональность буфера обмена, доступную нам в разработке для Windows 8. Увидимся позже!

downloadTheTools