Возможности навигации для SharePoint Online

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

В этой статье описано, как сократить время загрузки страниц в SharePoint Online с помощью структурной навигации и навигации на основе поиска.

Глобальная структура навигации и запросы, необходимые для построения структурной навигации, могут замедлить загрузку страниц в SharePoint Online. Это происходит потому, что каждый из этих запросов отправляет другой запрос на SQL Server. Для каждого вашего сайта и дочернего сайта на SQL Server отправляются дополнительные запросы. Эта проблема также относится к эталонным страницам и поэтому влияет на глобальную структуру навигации.

Для некоторых сайтов SharePoint требуются большие и сложные структуры. Использование стандартной структурной навигации, которая использует содержимого на основе запросов, может привести к медленной загрузке страницы из-за того, что сайт включает несколько уровней. Каждый из уровней дочернего сайта также создает отдельный запрос.

В SharePoint предлагается два основных стандартных варианта навигации, а также третий способ на основе поиска. У каждого из них есть свои преимущества и недостатки, как описано в следующей таблице.

Структурная навигация

Управляемая навигация

Навигация на основе поиска

Преимущества:

  • Простота настройки

  • Учет ролей безопасности

  • Автоматическое обновление по мере добавления сайтов

Преимущества:

  • Простота обслуживания

Преимущества:

  • Учет ролей безопасности

  • Автоматическое обновление по мере добавления сайтов

  • Быстрая загрузка и структура навигации, кэшируемая локально

Недостатки:

  • Низкая производительность при сложной структуре навигации

Недостатки:

  • Не обновляется автоматически с учетом структуры сайта

Недостатки:

  • Нет возможность легко упорядочивать сайты

  • Требуется настройка эталонной страницы (и соответствующие технические навыки)

Если у вашего сайта есть много дочерних сайтов и на нем используется структурная навигация, она может значительно замедлять загрузку страниц. Наиболее подходящий вариант для вашего сайта будет зависеть от ваших потребностей и технических умений. Если вы умеете пользоваться настраиваемыми эталонными страницами и имеете разрешение на управление изменениями, которые могут вноситься в стандартную эталонную страницу в SharePoint Online, вариант на основе поиска позволит улучшить впечатления от использования. Если вам нужно что-то среднее между стандартной структурной навигацией и поиском, вам подойдет управляемая навигация. Управляемой навигацией можно управлять через настройки, для нее не требуется программировать файлы конфигурации, и она гораздо быстрее, чем стандартная структурная навигация.

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

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

Снимок экрана: отображение сайтов и дочерних сайтов

Использование структурной навигации в SharePoint Online

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

Включение структурной навигации в SharePoint Online

Для демонстрации производительности стандартного решения SharePoint Online необходимо включить структурную навигацию и параметр "Показать дочерние сайты". Ниже показан снимок экрана с параметрами на странице Параметры сайта > Навигация.

Снимок экрана: отображение дочерних сайтов

Анализ производительности структурной навигации в SharePoint Online

Для анализа производительности страницы SharePoint используйте вкладку Сеть средств разработчика F12 в Internet Explorer.

Вкладка Сетевое средств разработки снимок F12

На вкладке Сеть щелкните загружаемую ASPX-страницу, а затем откройте вкладку Сведения .

Снимок экрана: вкладка "Сведения"

Щелкните элемент Заголовки ответа.

Вкладка "снимок экрана сведения"

SharePoint возвращает полезные данные диагностики в заголовках ответа. Одним из самых полезных является значение SPRequestDuration   , которое показывает продолжительность обработки запроса на сервере (в миллисекундах).

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

Снимок экрана: время загрузки показано в качестве значения параметра длительности запроса

Значение ключа SPRequestDuration    равно 245 миллисекундам. Оно представляет время, затраченное на возврат запроса. Так как на сайте есть только один элемент навигации, это хороший тест производительности SharePoint Online без сложной навигации. На следующем снимке экрана показано, как добавление дочерних сайтов влияет на этот ключ.

Снимок экрана: запрос длительность 2502 ms

Добавление дочерних сайтов значительно увеличивает время, необходимое для возврата запроса страницы.

Преимущество обычной структурной навигации заключается в том, что вы можете легко упорядочивать элементы, скрывать сайты, добавлять страницы, результаты выводятся с учетом ролей безопасности, а вы не отклоняетесь от эталонных страниц, используемых в SharePoint Online. Если тщательно продумать структуру сайта и сократить количество дочерних сайтов в семействе веб-сайтов, структурная навигация будет прекрасно работать.

Использование управляемой навигации и управляемых метаданных в SharePoint Online

Управляемая навигация — еще один стандартный способ, с помощью которого вы можете воссоздать те же функциональные возможности, что и при структурной навигации.

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

Реализация управляемой навигации и ее результаты   

Существует несколько статей в сети TechNet о деталях управляемой навигации, например, Общие сведения о управляемой навигации в SharePoint Server 2013см.

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

Снимок экрана Subsite1 пример

В следующем примере показана производительность сложной структуры навигации при использовании управляемой навигации.

Снимок экрана: пример параметра SPRequestDuration

Управляемая навигация устойчиво обеспечивает более высокую производительность, чем структурная навигация с запросами контента.

Использование клиентских сценариев на основе поиска

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

Он включает создание пользовательской эталонной страницы и замену стандартного кода навигации собственным HTML-кодом. Выполните указанные ниже действия для замены кода навигации в файле seattle.html.

В данном примере нужно будет открыть файл seattle.html и заменить весь элемент id="DeltaTopNavigation" пользовательским HTML-кодом.

Пример: Для замены кода out box навигации на главной странице

  1. Перейдите на страницу Параметры сайта.

  2. Откройте коллекцию эталонных страниц, щелкнув Эталонные страницы.

  3. На этой странице можно найти файл seattle.master в библиотеке и скачать его.

  4. Измените код в текстовом редакторе и удалите блок, показанный на снимке экрана.

    Снимок экрана: код DeltaTopNavigation, который нужно удалить
  5. Удалите код между тегами <SharePoint:AjaxDelta id="DeltaTopNavigation"> и <\SharePoint:AjaxDelta> и замените его следующим фрагментом:

    <div id="loading">
      <!--Replace with path to loading image.-->
      <div style="background-image: url(''); height: 22px; width: 22px; ">
      </div>
    </div>
    <!-- Main Content-->
    <div id="navContainer" style="display:none">
        <div data-bind="foreach: hierarchy" class="noindex ms-core-listMenu-horizontalBox">
            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                <span class="menu-item-text" data-bind="text: item.Title">
                </span>
            </a>
            <ul id="menu" data-bind="foreach: $data.children" style="padding-left:20px">
                <li class="static dynamic-children">
                    <a class="static dynamic-children menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                        <span aria-haspopup="true" class="additional-background ms-navedit-flyoutArrow dynamic-children">
                            <span class="menu-item-text" data-bind="text: item.Title">
                            </span>
                        </span>
                    </a>
                    <ul id="menu" data-bind="foreach: children; visible: children.length>0" class="dynamic" >
                        <li class="dynamic">
                            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                                <span class="menu-item-text" data-bind="text: item.Title">
                                </span>
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
  6. Замена URL-адрес в загрузки изображений тег в начале со ссылкой на изображение загрузки в семействе веб-сайтов. После внесения изменений переименовать файл, а затем отправьте в коллекции главных страниц. Создает новый файл .master.

  7. Этот HTML-код является базовой разметкой, которая будет заполняться результатами поиска, возвращаемыми кодом JavaScript. Вам потребуется изменить следующий код, чтобы задать значение параметра var root = “site collection URL, как показано в следующем фрагменте:

    var root = “https://spperformance.sharepoint.com/sites/NavigationBySearch”;

    Файл JavaScript целиком выглядит так:

    //Models and Namespaces
    var SPOCustom = SPOCustom || {};
    SPOCustom.Models = SPOCustom.Models || {}
    SPOCustom.Models.NavigationNode = function () {
    
        this.Url = ko.observable("");
        this.Title = ko.observable("");
        this.Parent = ko.observable("");
    
    };
    
    var root = "https://spperformance.sharepoint.com/sites/NavigationBySearch";
    var baseUrl = root + "/_api/search/query?querytext=";
    var query = baseUrl + "'contentClass=\"STS_Web\"+path:" + root + "'&trimduplicates=false&rowlimit=300";
    
    var baseRequest = {
        url: "",
        type: ""
    };
    
    
    //Parses a local object from JSON search result.
    function getNavigationFromDto(dto) {
        var item = new SPOCustom.Models.NavigationNode();
        if (dto != undefined) {
    
            var webTemplate = getSearchResultsValue(dto.Cells.results, 'WebTemplate');
    
            if (webTemplate != "APP") {
                item.Title(getSearchResultsValue(dto.Cells.results, 'Title')); //Key = Title
                item.Url(getSearchResultsValue(dto.Cells.results, 'Path')); //Key = Path
                item.Parent(getSearchResultsValue(dto.Cells.results, 'ParentLink')); //Key = ParentLink
            }
    
        }
        return item;
    }
    
    function getSearchResultsValue(results, key) {
    
        for (i = 0; i < results.length; i++) {
            if (results[i].Key == key) {
                return results[i].Value;
            }
        }
        return null;
    }
    
    //Parse a local object from the serialized cache.
    function getNavigationFromCache(dto) {
        var item = new SPOCustom.Models.NavigationNode();
    
        if (dto != undefined) {
    
            item.Title(dto.Title);
            item.Url(dto.Url);
            item.Parent(dto.Parent);
        }
    
        return item;
    }
    
    /* create a new OData request for JSON response */
    function getRequest(endpoint) {
        var request = baseRequest;
        request.type = "GET";
        request.url = endpoint;
        request.headers = { ACCEPT: "application/json;odata=verbose" };
        return request;
    };
    
    /* Navigation Module*/
    function NavigationViewModel() {
        "use strict";
        var self = this;
        self.nodes = ko.observableArray([]);
        self.hierarchy = ko.observableArray([]);;
        self.loadNavigatioNodes = function () {
            //Check local storage for cached navigation datasource.
            var fromStorage = localStorage["nodesCache"];
            if (false) {
                var cachedNodes = JSON.parse(localStorage["nodesCache"]);
    
                if (cachedNodes && timeStamp) {
                    //Check for cache expiration. Currently set to 3 hrs.
                    var now = new Date();
                    var diff = now.getTime() - timeStamp;
                    if (Math.round(diff / (1000 * 60 * 60)) < 3) {
    
                        //return from cache.
                        var cacheResults = [];
                        $.each(cachedNodes, function (i, item) {
                            var nodeitem = getNavigationFromCache(item, true);
                            cacheResults.push(nodeitem);
                        });
    
                        self.buildHierarchy(cacheResults);
                        self.toggleView();
                        addEventsToElements();
                        return;
                    }
                }
            }
            //No cache hit, REST call required.
            self.queryRemoteInterface();
        };
    
        //Executes a REST call and builds the navigation hierarchy.
        self.queryRemoteInterface = function () {
            var oDataRequest = getRequest(query);
            $.ajax(oDataRequest).done(function (data) {
                var results = [];
                $.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function (i, item) {
    
                    if (i == 0) {
                        //Add root element.
                        var rootItem = new SPOCustom.Models.NavigationNode();
                        rootItem.Title("Root");
                        rootItem.Url(root);
                        rootItem.Parent(null);
                        results.push(rootItem);
                    }
                    var navItem = getNavigationFromDto(item);
                    results.push(navItem);
                });
                //Add to local cache
                localStorage["nodesCache"] = ko.toJSON(results);
    
                localStorage["nodesCachedAt"] = new Date().getTime();
                self.nodes(results);
                if (self.nodes().length > 0) {
                    var unsortedArray = self.nodes();
                    var sortedArray = unsortedArray.sort(self.sortObjectsInArray);
    
                    self.buildHierarchy(sortedArray);
                    self.toggleView();
                    addEventsToElements();
                }
            }).fail(function () {
                //Handle error here!!
                $("#loading").hide();
                $("#error").show();
            });
        };
        self.toggleView = function () {
            var navContainer = document.getElementById("navContainer");
            ko.applyBindings(self, navContainer);
            $("#loading").hide();
            $("#navContainer").show();
    
        };
        //Uses linq.js to build the navigation tree.
        self.buildHierarchy = function (enumerable) {
            self.hierarchy(Enumerable.From(enumerable).ByHierarchy(function (d) {
                return d.Parent() == null;
            }, function (parent, child) {
                if (parent.Url() == null || child.Parent() == null)
                    return false;
                return parent.Url().toUpperCase() == child.Parent().toUpperCase();
            }).ToArray());
    
            self.sortChildren(self.hierarchy()[0]);
        };
    
    
        self.sortChildren = function (parent) {
    
            // sjip processing if no children
            if (!parent || !parent.children || parent.children.length === 0) {
                return;
            }
    
            parent.children = parent.children.sort(self.sortObjectsInArray2);
    
            for (var i = 0; i < parent.children.length; i++) {
                var elem = parent.children[i];
    
                if (elem.children && elem.children.length > 0) {
                    self.sortChildren(elem);
                }
            }
        };
    
        // ByHierarchy method breaks the sorting in chrome and firefix 
        // we need to resort  as ascending
        self.sortObjectsInArray2 = function (a, b) {
            if (a.item.Title() > b.item.Title())
                return 1;
            if (a.item.Title() < b.item.Title())
                return -1;
            return 0;
        };
    
    
        self.sortObjectsInArray = function (a, b) {
            if (a.Title() > b.Title())
                return -1;
            if (a.Title() < b.Title())
                return 1;
            return 0;
        }
    }
    
    //Loads the navigation on load and binds the event handlers for mouse interaction.
    function InitCustomNav() {
        var viewModel = new NavigationViewModel();
        viewModel.loadNavigatioNodes();
    }
    
    function addEventsToElements() {
        //events.
        $("li.dynamic-children").mouseover(function () {
            var position = $(this).position();
            $(this).find("ul").css({ width: 125, left: position.left + 10, top: 50 });
    
        })
            .mouseout(function () {
                $(this).find("ul").css({ width: 0, left: -99999, top: 0 });
            });
    }
    
    _spBodyOnLoadFunctionNames.push("InitCustomNav");
    

    Для подведения итогов код на рисунке выше в функции $(document).ready jQuery есть созданный объект viewModel и затем loadNavigationNodes() работать на этот объект называется. Эта функция либо загружает иерархии навигации построенные, хранящиеся в локальном хранилище HTML5 браузера клиента или вызове функции queryRemoteInterface().

    QueryRemoteInterface() построение запроса с помощью функции getRequest() с параметром запроса, ранее определенных в сценарии и затем возвращает данные с сервера. Выравнивается по существу массив всех сайтов в семействе сайтов, представленное как объекты передачи данных с помощью различных свойств. Эти данные затем анализируется в заранее определенных SPO.Models.NavigationNode объекты, использующие Knockout.js Создание наблюдаемое свойств для использования путем привязки значения в HTML, которое было определено ранее данных. Затем объекты помещаются в массиве результатов. Этот массив анализируется в JSON с помощью частичной и хранящиеся в хранилище используемого браузера для повышения производительности на загрузки будущих страниц.

  8. Затем результаты назначены self.nodes массива и иерархия создается из объекты, используя linq.js присвоение массива self.heirarchyвыходных данных. Этот массив — это объект, связанный с HTML-код. Это делается в функции toggleView() путем передачи собственный объект функции ko.applyBinding() . Затем в результате массив иерархии связан с следующий код HTML:

    <div data-bind=”foreach: hierarchy” class=”noindex ms-core-listMenu-horizontalBox”>

    Наконец обработчики для mouseenter и mouseexit будут добавлены обрабатывать раскрывающиеся меню дочерний сайт верхнего уровня навигации которого выполняется в функции addEventsToElements() .

    На снимке экрана показаны результаты навигации:

    Снимок экрана: результаты навигации

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

    Снимок экрана: SPRequestDuration 301

    Одним из основных преимущество такого подхода является то, что при использовании локального хранилища HTML5 структура навигации хранится локально и доступна при последующей загрузке страницы.

Он значительно улучшает производительность по сравнению с использованием API поиска для структурной навигации, но для внедрения и настройки этой функции требуются технические навыки. В примере реализации сайты упорядочены так же, как при стандартной структурной навигации (в алфавитном порядке). Если вы хотите изменить этот порядок, разработка и обслуживание будут более сложными. Кроме того, при этом вы не сможете использовать поддерживаемые эталонные страницы. Если пользовательскую эталонную страницу не обслуживать, на сайте не будут использоваться обновления и улучшения эталонных страниц, предлагаемые корпорацией Майкрософт.

Указанный выше код имеет следующие зависимости:

Текущая версия LinqJS не содержит метод ByHierarchy, используемый в приведенном выше коде и нарушит код навигации. Чтобы исправить ошибку, добавьте следующий метод к файлу Linq.js перед строкой «Flatten: функция ()».

ByHierarchy: function(firstLevel, connectBy, orderBy, ascending, parent) {
     ascending = ascending == undefined ? true : ascending;
     var orderMethod = ascending == true ? 'OrderBy' : 'OrderByDescending';
     var source = this;
     firstLevel = Utils.CreateLambda(firstLevel);
     connectBy = Utils.CreateLambda(connectBy);
     orderBy = Utils.CreateLambda(orderBy);
    
     //Initiate or increase level
     var level = parent === undefined ? 1 : parent.level + 1;

    return new Enumerable(function() {
         var enumerator;
         var index = 0;

        var createLevel = function() {
                 var obj = {
                     item: enumerator.Current(),
                     level : level
                 };
                 obj.children = Enumerable.From(source).ByHierarchy(firstLevel, connectBy, orderBy, ascending, obj);
                 if (orderBy !== undefined) {
                     obj.children = obj.children[orderMethod](function(d) {
                         return orderBy(d.item); //unwrap the actual item for sort to work
                     });
                 }
                 obj.children = obj.children.ToArray();
                 Enumerable.From(obj.children).ForEach(function(child) {
                     child.getParent = function() {
                         return obj;
                     };
                 });
                 return obj;
             };

        return new IEnumerator(

        function() {
             enumerator = source.GetEnumerator();
         }, function() {
             while (enumerator.MoveNext()) {
                 var returnArr;
                 if (!parent) {
                     if (firstLevel(enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }

                } else {
                     if (connectBy(parent.item, enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }
                 }
             }
             return false;
         }, function() {
             Utils.Dispose(enumerator);
         })
     });
 },

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

Совершенствование навыков
Перейти к обучению
Первоочередный доступ к новым возможностям
Присоединиться к программе предварительной оценки Office

Были ли сведения полезными?

Спасибо за ваш отзыв!

Благодарим за отзыв! Возможно, будет полезно связать вас с одним из наших специалистов службы поддержки Office.

×