Навігація в 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, що завантажується, а потім перейдіть на вкладку Відомості.

Функції програми InfoPath 2010, які недоступні у формах браузера

Виберіть Заголовки відповіді.

Знімок екрана: вкладка ''Відомості''

SharePoint повертає корисні діагностичні відомості в заголовках відповіді. Одне з найкорисніших – це SPRequestDuration   . Ця метрика вказує тривалість обробки запиту на сервері в мілісекундах.

На знімку екрана нижче прапорець Відображати дочірні сайти знято для структурної навігації. Це означає, що в глобальній навігації є лише посилання на колекцію сайтів:

Знімок екрана: час завантаження показано як значення параметра тривалості запиту

Ключ SPRequestDuration    має значення 245 мілісекунд. Це тривалість повернення запиту. Оскільки на сайті лише один елемент навігації, це чудовий приклад того, як SharePoint Online працює, коли навігація має небагато рівнів. На знімку екрана нижче показано, як додавання підсайтів впливає на цей ключ.

Знімок екрана зі значенням тривалості запиту 2502

Унаслідок додавання підсайтів запит сторінки повертається значно повільніше.

Перевагами використання звичайної структурної навігації є те, що ви можете легко впорядковувати й приховувати сайти, додавати сторінки, фільтрувати результати за ролями безпеки, а також використовувати підтримувані сторінки, доступні в SharePoint Online. Якщо ретельно структурувати сайт і звести до мінімуму кількість підсайтів у колекції сайтів, структурна навігація працюватиме належним чином.

Використання керованої навігації та керованих метаданих у SharePoint Online

Керована навігація – це ще один готовий варіант, за допомогою якого можна скористатися функціями, притаманними структурній навігації.

Керовані метадані дають змогу значно швидше отримувати дані, щоб створити навігацію сайту, у порівнянні з використанням вмісту за запитом. Хоча цей підхід значно швидший, він не передбачає фільтрування результатів за ролями безпеки. Тому якщо користувач не має доступу до сайтів, посилання й надалі відображатиметься, але з’являтиметься повідомлення про помилку.

Реалізація керованої навігації та результатів   

На сайті TechNet є кілька статей із відомостями про керовану навігацію. Наприклад, ознайомтеся зі статтею Огляд керованої навігації в SharePoint Server 2013.

Щоб реалізувати керовану навігацію, потрібно мати права адміністратора сховища термінів. Якщо настроїти терміни за допомогою URL-адрес, які відповідають структурі колекції сайтів, керовану навігацію можна використовувати замість структурної навігації. Наприклад:

Знімок екрана: приклад Subsite1

У наведеному нижче прикладі показано продуктивність складної навігації, коли використовується керована навігація.

Знімок екрана: приклад параметра SPRequestDuration

Якщо використовувати керовану навігацію послідовно, продуктивність покращиться в порівнянні зі структурною навігацією, у якій використовується вміст за запитом.

Використання сценаріїв на боці клієнта на основі пошуку

Цей підхід дає змогу використовувати вбудовані індекси у фоновому режимі за допомогою неперервного обходу. Це означає, що запити на вміст великого обсягу не використовуються. Результати пошуку отримуються з індексу пошуку, а результати фільтруються за ролями безпеки. Це збільшує швидкість порівняно з використанням звичайних запитів вмісту. Якщо використовувати пошук для структурної навігації, особливо в умовах складної структури сайту, час завантаження сторінки значно зменшиться. Основною перевагою керованої навігації є те, що можна скористатися фільтрацією за ролями безпеки.

Щоб використовувати цей підхід, потрібно створити настроювану основну сторінку й замінити готовий код навігації спеціальним кодом HTML. Виконайте цю процедуру, щоб замінити код навігації у файлі seattle.html.

У цьому прикладі потрібно відкрити файл seattle.html і замінити весь елемент id=”DeltaTopNavigation” спеціальним кодом HTML.

Приклад. Заміна готового коду навігації на основній сторінці

  1. Перейдіть на сторінку Параметри сайту.

  2. Відкрийте колекцію основних сторінок, клацнувши Основні сторінки.

  3. Тут можна переходити між елементами бібліотеки й завантажити файл seattle.master.

  4. Змініть код за допомогою текстового редактора й видаліть блокування коду, як показано на знімку екрана нижче.

    Збереження файлів у хмарі
  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() функції.

    Результати навігації можна побачити на знімку екрана нижче:

    Знімок екрана результатів навігації

    У нашому прикладі складної навігації завантажується окрема сторінка без локального кешування, тож на сервері витрачається менше часу в порівнянні з прикладом структурної навігації. Це дає змогу отримати схожі результати, використовуючи підхід керованої навігації.

    Рядок синіх плиток, які демонструють основні можливості функцій SharePoint 2013, а саме: спільний доступ, упорядкування, надання відомостей, створення та керування.

    Одна з основних переваг такого підходу полягає в тому, що якщо використовується локальне сховище HTML5, навігація зберігається локально для користувачів на випадок, коли вони завантажуватимуть сторінку наступного разу.

Використовуючи API пошуку для структурної навігації, ми суттєво покращуємо продуктивність. Проте, щоб реалізувати та налаштовувати цю функцію, знадобляться певні технічні навички. У прикладі реалізації сайти розміщено так само, як і при структурній навігації – в алфавітному порядку. Якщо потрібно використовувати інший порядок, у такому разі розробляти й обслуговувати буде дещо складніше. Крім того, такий підхід передбачає використання основних сторінок, відмінних від підтримуваних. Якщо спеціальна основна сторінка не підтримується, на вашому сайті не встановлюватимуться оновлення та вдосконалення, які корпорація Майкрософт розробляє для основних сторінок.

Наведений вище код має такі залежності:

Поточна версія LinqJS не містить ByHierarchy спосіб, що використовуються в коді вище та розірве переходів код. Щоб виправити це, додайте наведений нижче спосіб Linq.js файл, до рядка "звести: функція ()".

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. Оскільки статтю перекладено за допомогою служби машинного перекладу, вона може містити смислові, синтаксичні або граматичні помилки.

Отримуйте нові функції раніше за інших
Приєднайтеся до оцінювачів Office

Ця інформація корисна?

Дякуємо за ваш відгук!

Дякуємо за відгук! Схоже, вам може стати в нагоді допомога одного з наших спеціалістів служби підтримки Office, з яким ми вас можемо з’єднати.

×