Navigeringsalternativ för SharePoint Online

Viktigt!: Den här artikeln är maskinöversatt, se ansvarsfriskrivningen. Den engelska versionen av den här artikeln finns här för din referens.

I den här artikeln beskrivs hur du kan förbättra inläsningstider för sidor med SharePoint Online genom strukturell navigering och sökdriven navigering.

Med global navigering och frågor som krävs för att skapa den strukturella navigeringen kan göra att det tar längre tid att läsa in dina sidor i SharePoint Online. Det beror på att var och en av de här frågorna skickar en annan begäran till SQL-servern. För varje webbplats och underwebbplats som du har skapas fler begäranden till SQL-servern. Det här problemet påverkar också huvudsidorna. Det innebär att den globala navigeringen också påverkas.

Vissa SharePoint-webbplatser kräver stora och komplexa strukturer. Den inbyggda strukturella navigeringen, som använder innehåll genom frågor, kan resultera i långsamma inläsningstider för sidor på grund av flera webbplatslager. Varje lager av underwebbplatser skapar också en annan fråga.

Det finns två huvudsakliga inbyggda navigeringsalternativ i SharePoint, samt en tredje, anpassad och sökdriven metod. Varje alternativ har fördelar och nackdelar som beskrivs i följande tabell.

Strukturell navigering

Hanterad navigering

Sökdriven navigering

Fördelar:

  • Enkel att konfigurera

  • Säkerhetsjusterad

  • Uppdateras automatiskt när webbplatser läggs till

Fördelar:

  • Enkel att underhålla

Fördelar:

  • Säkerhetsjusterad

  • Uppdateras automatiskt när webbplatser läggs till

  • Snabb inläsningstid och lokalt cachelagrad navigeringsstruktur

Nackdelar:

  • Komplex webbplatsstruktur kan ge dåliga prestanda

Nackdelar:

  • Uppdateras inte automatiskt för att återspegla webbplatsstrukturen

Nackdelar:

  • Ingen möjlighet att enkelt ordna webbplatser

  • Kräver anpassning av huvudsidan (tekniska färdigheter krävs)

Om du har en webbplats med många underwebbplatser och du använder strukturell navigering kan din sida läsas in betydligt långsammare. Vilket alternativ som passar bäst för din webbplats beror på kraven för din webbplats och din tekniska kapacitet. Om du känner dig bekväm med att använda en anpassad huvudsida och har kapacitet inom organisationen för att göra de ändringar som kan uppstå på standardhuvudsidan för SharePoint Online ger det sökdrivna alternativet den bästa användarupplevelsen. Om du vill ha ett enkelt mellanting mellan den inbyggda strukturella navigeringen och sökning så är den hanterade navigeringen ett mycket bra alternativ. Alternativet med hanterad navigering kan underhållas genom konfiguration, innebär inte kodanpassning av filer och är betydligt snabbare än den inbyggda strukturella navigeringen.

En annan metod är att strukturera om den befintliga webbplatsen och minska antalet navigeringsobjekt och underwebbplatser som krävs. Det beror på att strukturell navigering har bra prestanda så länge webbplatsstrukturen och navigeringen inte är för komplicerad.

I den här artikeln jämförs de olika metoderna i en webbplatssamling. Webbplatssamlingen som används som exempel har 11 underwebbplatser och varje underwebbplats innehåller minst fyra ytterligare underwebbplatser.

Skärmbild med webbplatser och underwebbplatser

Använda strukturell navigering i SharePoint Online

Det här är den inbyggda navigeringen som används som standard och som i de flesta fall är den enklaste och bäst lämpade lösningen. Strukturell navigering ger bra prestanda om det inte finns en komplex struktur med flera underwebbplatser eller många nivåer av underwebbplatser. De stora fördelarna med den här metoden är att den är säkerhetsjusterad, att den uppdateras automatiskt när nya webbplatser läggs till och att den inte kräver någon anpassning av huvudsidan. En användare utan teknisk kunskap kan också enkelt lägga till objekt, dölja objekt och hantera navigeringen från inställningssidan.

Aktivera strukturell navigering i SharePoint Online

Illustrerar prestandan i en SharePoint Online-standardlösning med strukturell navigering och där alternativet för att visa underwebbplatser har aktiverats. Nedan visas en skärmbild från sidan Webbplatsinställningar > Navigering.

Skärmbild av underwebbplatser

Analysera prestanda för strukturell navigering i SharePoint Online

Analysera prestanda på en SharePoint-sida genom att använda fliken Nätverk i utvecklarverktygen F12 i Internet Explorer.

Skärmbild som visar nätverksfliken för F12-enhetsverktyg

Klicka på ASPX-sidan som läses in på fliken Nätverk och klicka på fliken Information.

Skärmbild av fliken Information

Klicka på Svarshuvuden.

Skärmbild av fliken Information

SharePoint returnerar viss användbar diagnostisk information i sina svarshuvuden. Ett av de mest användbara är SPRequestDuration    som är värdet, i millisekunder, för hur lång tid en begäran tog för att bearbeta på servern.

I följande skärmbild har visa underwebbplatser avmarkerats för den strukturella navigeringen. Det innebär att bara webbplatssamlingslänken finns i det globala navigeringsfältet:

Skärmbild med inläsningstider som efterfrågans varaktighet

Nyckeln SPRequestDuration    har värdet 245 millisekunder. Det representerar tiden som gick åt för att returnera begäran. Eftersom webbplatsens navigering endast har ett objekt är det här en bra utgångspunkt för prestanda i SharePoint Online utan tung navigering. I nästa skärmbild visas hur den här nyckeln påverkas när underwebbplatser läggs till.

Skärmbild som visar efterfrågans varaktighet på 2502 ms

Genom att lägga till underwebbplatser har tiden som går åt för att returnera sidbegäran ökat avsevärt.

Fördelarna med att använda den vanliga strukturerade navigeringen är att du enkelt kan bestämma ordningen, dölja webbplatser, lägga till sidor, resultaten är säkerhetsjusterade och du avviker inte från huvudsidorna som stöds och används i SharePoint Online. Om du strukturerar din webbplats noggrant och minimerar antalet underwebbplatser i din webbplatssamling så har strukturell navigering bra prestanda.

Använda hanterad navigering och hanterade metadata i SharePoint Online

Hanterad navigering är ett annat inbyggt alternativ som du kan använda för att återskapa samma typ av funktioner som finns i strukturell navigering.

Fördelen med att använda hanterade metadata är att det går mycket snabbare att hämta data än att använda innehåll från en fråga för att skapa webbplatsnavigeringen. Även om det går mycket snabbare så går det inte att säkerhetsjustera resultaten. Om en användare inte har åtkomst till en viss webbplats så visas fortfarande länken, men den leder till ett felmeddelande.

Så här implementerar du hanterad navigering och resultaten   

Det finns flera artiklar på TechNet med information om hanterad navigering – läs till exempel Översikt över hanterad navigering i SharePoint Server 2013.

Du behöver administratörsbehörighet för termlagring om du vill implementera hanterad navigering. Genom att konfigurera termer med URL:er som matchar strukturen i en webbplatssamling kan hanterad navigering användas för att ersätta strukturell navigering. Till exempel:

Skärmbild av exemplet underwebbplats1

I följande exempel visas prestanda för komplex navigering med hanterad navigering.

Skärmbild av exemplet SPRequestDuration

Om hanterad navigering används konsekvent förbättras prestanda jämfört med innehåll som skapas genom frågor och använder strukturell navigering.

Med sökdrivna skript på klientsidan

Med sökning kan du utnyttja de index som byggs upp i bakgrunden med kontinuerlig crawlning. Det innebär att det inte finns några tunga innehållsfrågor. Sökresultaten hämtas från sökindexet och resultaten är säkerhetsjusterade. Det här går snabbare än att använda vanliga innehållsfrågor. Genom att använda sökning för strukturell navigering går det avsevärt snabbare att läsa in sidor, speciellt om du har en komplex webbplatsstruktur. Den största fördelen med det här framför hanterad navigering är att du kan använda säkerhetsjustering.

Den här metoden innebär att skapa en anpassad huvudsida och ersätta den inbyggda navigeringskoden med anpassad HTML-kod. Gör så här om du vill ersätta navigeringskoden i filen seattle.html.

I det här exemplet öppnar du filen seattle.html och ersätter hela elementet id=”DeltaTopNavigation” med den anpassade HTML-koden.

Exempel: Så här ersätter du den inbyggda navigeringskoden på en huvudsida

  1. Öppna sidan Webbplatsinställningar.

  2. Öppna galleriet för huvudsidor genom att klicka på Huvudsidor.

  3. Där kan du navigera i biblioteket och hämta filen seattle.master.

  4. Redigera koden med en textredigerare och ta bort kodblocket i följande skärmbild.

    Skärmbild av DeltaTopNavigation-kod som ska tas bort
  5. Ta bort koden mellan taggarna <SharePoint:AjaxDelta id=”DeltaTopNavigation”> och <\SharePoint:AjaxDelta> och ersätt den med följande kod:

    <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. Ersätta Webbadressen i inläsningen bild fästpunktstaggen i början med en länk till en inläsningsbild av i webbplatssamlingen. När du har ändrat byta namn på filen och sedan överför till galleriet för huvudsidor. Då skapas en ny .master-fil.

  7. Den här HTML-koden är den grundläggande kod som används för sökresultaten som returneras från JavaScript-koden. Du behöver redigera följande kod för att ändra värdet för var root = “site collection URL enligt följande kodstycke:

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

    Hela JavaScript-filen följer nedan:

    //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");
    

    Om du vill sammanfatta koden som visas ovan i funktionen jQuery $(document).ready det är en viewModel objekt som skapas och sedan loadNavigationNodes() fungerar på det markerade objektet kallas. Den här funktionen läses in antingen tidigare skapad navigeringshierarkin lagras i HTML5 lokala lagringen av klientens webbläsare eller anropas funktionen queryRemoteInterface().

    QueryRemoteInterface() skapar en begäran med hjälp av funktionen getRequest() med frågeparametrar som definierats tidigare i skriptet och returnerar data från servern. Den här informationen är egentligen en matris med alla webbplatser i webbplatssamlingen som representeras som överför dataobjekt med olika egenskaper. Dessa data analyseras sedan till de tidigare definierade SPO.Models.NavigationNode objekt som använder Knockout.js för att skapa synliga egenskaper för användning av data bindning värdena i HTML som vi har definierat tidigare. Objekten placeras sedan i en matris resultat. Den här matrisen tolkas till JSON med blockerade och lagras i den lokala webbläsare lagringen för högre prestanda på framtida sidinläsningen.

  8. Sedan resultatet har tilldelats self.nodes matris och en hierarki byggs ut från objekt med hjälp av linq.js tilldelas en matris self.heirarchyutdata. Den här matrisen är det objekt som är bunden till HTML. Detta görs i funktionen toggleView() genom att skicka själv objektet till funktionen ko.applyBinding() . Detta gör sedan hierarki matrisen ska vara bundet till följande HTML:

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

    Slutligen läggs händelsehanterare för mouseenter och mouseexit till på den högsta nivån navigeringen ska hantera underwebbplats menyerna som görs i funktionen addEventsToElements() .

    Resultatet av navigeringen kan ses i skärmbilden nedan:

    Skärmbild av navigeringsresultat

    I exemplet med den komplexa navigeringen visar tiden för inläsning av en sida utan lokal cachelagring att tiden som används på servern har minskat – jämfört med utgångspunkten för strukturell navigering har vi fått ett resultat som ligger närmare tiden för den hanterade navigeringen.

    Skärmbild av SPRequestDuration 301

    En av de största fördelarna med den här metoden är att navigeringen genom lokal HTML5-lagring lagras lokalt för användaren nästa gång han/hon läser in sidan.

Vi får stora prestandaförbättringar genom att använda söknings-API:et för strukturell navigering. Det krävs dock vissa tekniska kunskaper för att köra och anpassa den här funktionen. I exempelimplementeringen har webbplatserna ordnats på samma sätt som i den inbyggda strukturella navigeringen (i alfabetisk ordning). Om du vill avvika från den här ordningen är det mer komplicerat att utveckla och underhålla. Den här metoden kräver också att du avviker från huvudsidorna som stöds. Om den anpassade huvudsidan inte underhålls går din webbplats miste om uppdateringar och förbättringar från Microsoft.

Koden ovan har följande beroenden:

Den aktuella versionen av LinqJS innehåller inte metoden ByHierarchy används i koden ovan och bryts navigeringskoden. Du åtgärdar detta genom att lägga till följande metod i filen Linq.js före rad ”Flatten: fungera ()”.

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);
         })
     });
 },

Obs!: Ansvarsfriskrivning för maskinöversättning: Den här artikeln har översatts av ett datorsystem utan mänsklig inblandning. Microsoft erbjuder dessa maskinöversättningar för att hjälpa icke engelskspråkiga användare att ta del av information om Microsofts produkter, tjänster och tekniker. Eftersom artikeln är maskinöversatt kan den innehålla fel i ordval, syntax och grammatik.

Utöka dina kunskaper
Utforska utbildning
Få nya funktioner först
Anslut till Office Insiders

Hade du nytta av den här informationen?

Tack för din feedback!

Tack för din feedback! Det låter som att det kan vara bra att koppla dig till en av våra Office-supportrepresentanter.

×