Navigationsindstillinger for SharePoint Online

Vigtigt: Denne artikel er maskinoversat. Se ansvarsfraskrivelsen. Du kan finde den engelske version af denne artikel her til din orientering.

I denne artikel beskrives, hvordan sideindlæsningstider forbedres for Sharepoint Online ved at bruge struktureret navigation og søgebaseret navigation.

Global navigation og de forespørgsler, der kræves for at opbygge strukturel navigationen, kan medvirke til at siderne indlæses langsommere i SharePoint Online. Dette skyldes, at hver af disse forespørgsler sender en anden anmodning til SQL-server. For hvert websted og underordnet websted du har, sendes der flere anmodninger til SQL-server. Dette problem påvirker også mastersiderne. Dette betyder, at global navigation også påvirkes.

Nogle SharePoint-websteder kræver store og komplekse strukturer. Brug af køreklar strukturel navigation, der bruger indhold i henhold til forespørgsel, kan medføre langsomme sideindlæsningstider, da der er flere webstedslag. Hvert af lagene for underordnede websteder opretter også en anden forespørgsel.

Der er to primære køreklare navigationsindstillinger i SharePoint samt en tredje søgebaseret fremgangsmåde, der kan tilpasses. Hver indstilling har fordele og ulemper, som er beskrevet i følgende tabel.

Strukturel navigation

Administreret navigation

Søgebaseret navigation

Fordele:

  • Nem at konfigurere

  • Sikkerhedstilpasset

  • Opdateres automatisk, når der tilføjes websteder

Fordele:

  • Nem at vedligeholde

Fordele:

  • Sikkerhedstilpasset

  • Opdateres automatisk, når der tilføjes websteder

  • Hurtig indlæsningstid og lokal cachelagret navigationsstruktur

Ulemper:

  • Ydeevnen kan være dårlig med kompleks webstedsstruktur

Ulemper:

  • Opdateres ikke automatisk for at afspejle webstedsstruktur

Ulemper:

  • Ingen mulighed for at nemt at arrangere websteder

  • Kræver tilpasning af mastersiden (tekniske færdigheder nødvendigt)

Hvis du har et websted med en masse underordnede websteder, og du bruger strukturel navigation, kan det gøre sideindlæsningen væsentligt langsommere. Den bedste indstilling for dit websted afhænger af kravene til webstedet og dine tekniske færdigheder. Hvis du er fortrolig med at bruge en tilpasset masterside, og der er medarbejdere med færdigheder i organisationen til at vedligeholde ændringerne, der kan opstå på standardmastersiden for SharePoint Online, så vil den søgebaserede indstilling give den bedste brugeroplevelse. Hvis du ønsker en gylden mellemvej mellem køreklar struktureret navigation og søgning, så er administreret navigation en meget god mulighed. Administreret navigation kan vedligeholdes via konfiguration, involverer ikke kodetilpasningsfiler, og den er væsentlig hurtigere end den køreklare strukturelle navigation.

En anden fremgangsmåde er at ændre strukturen på det eksisterende websted og reducere antallet af påkrævede navigationselementer og underordnede websteder. Dette skyldes, at strukturel navigation har en god ydeevne, så længe webstedsstrukturen og navigationen ikke er for kompliceret.

I denne artikel sammenlignes de forskellige fremgangsmåder i et eksempel med en gruppe af websteder. Eksemplet med gruppen af websteder har 11 underordnede websteder, og hvert underordnet websted har mindst fire yderligere underordnede websteder.

Skærmbillede med websteder og underordnede websteder

Brug af strukturel navigation i SharePoint Online

Dette er den køreklare navigation, der anvendes som standard, og det er den mest enkle og bedste løsning i de fleste tilfælde. Medmindre der er en kompleks struktur med flere underordnede websteder eller mange niveauer af underordnede websteder, har strukturel navigation en god ydeevne. Hovedfordelene ved denne fremgangsmåde er, at den er sikkerhedstilpasset, opdateres automatisk, når nye websteder tilføjes, og kræver ikke tilpasning af mastersiden. En ikke-teknisk kyndig bruger kan også nemt tilføje elementer, skjule elementer og administrere navigationen fra siden med indstillinger.

Aktivering af strukturel navigation i SharePoint Online

Illustrerer, hvordan ydeevnen i standardløsningen til SharePoint Online med strukturel navigation og indstillingen Vis underordnede aktiveres. Nedenfor er der et skærmbillede af indstillingerne, der findes på siden Webstedsindstillinger > Navigation.

Skærmbillede med underordnede websteder

Analysering af strukturel ydeevne i SharePoint Online

Brug fanen Netværk i F12-udviklerværktøjerne i Internet Explorer til at analysere ydeevnen for en Sharepoint-side.

Skærmbillede med fanen Netværk i F12-udviklerværktøjer

Klik på .aspx-siden, der indlæses, på fanen Netværk, og klik derefter på fanen Detaljer.

Skærmbillede med fanen for detaljer

Klik på Svaroverskrifter.

Skærmbillede af fanen Detaljer

SharePoint returnerer nogle nyttige diagnostiske oplysninger i sine svarheadere. En af de mest nyttige er SPRequestDuration   , som er værdien i millisekunder for, hvor lang tid det tog at behandle en anmodning på serveren.

I nedenstående skærmbillede er Vis underordnede websteder ikke markeret for den strukturelle navigation. Det betyder, at der kun er linket til gruppen af websteder i den globale navigation:

Skærmbillede med indlæsningstider som varighed af anmodning

Nøglen SPRequestDuration    har en værdi på 245 millisekunder. Dette repræsenterer den tid, det har taget at returnere anmodningen. Da der kun er ét navigationselement på webstedet, er det en god retningslinje for SharePoint Onlines ydeevne uden tung navigation. Det næste skærmbillede viser, hvordan tilføjelse af de underordnede websteder påvirker denne nøgle.

Skærmbillede med en varighed af anmodning på 2502 ms

Tilføjelse af underordnede websteder øger væsentligt den tid, det tager at returnere sideanmodningen.

Fordelene ved at bruge almindelig struktureret navigation er, at du nemt kan organisere rækkefølgen, skjule websteder, tilføje sider, resultaterne er sikkerhedstilpassede, og at du ikke afviger fra de understøttede mastersider, der bruges i SharePoint Online. Hvis du strukturerer webstedet omhyggeligt og minimerer mængden af underordnede websteder i din gruppe af websteder, har strukturel navigation god ydeevne.

Brug af administreret navigation og administreret metadata i SharePoint Online

Administreret navigation er en anden køreklar indstilling, du kan bruge til at genskabe den samme type funktionalitet som strukturel navigation.

Fordelen ved at bruge administreret metadata er, at det er meget hurtigere at hente data end at bruge indhold efter forespørgsel for at opbygge navigationen på webstedet. Selvom det er meget hurtigere, er det ikke muligt at sikkerhedstilpasse resultaterne, så hvis en bruger ikke har adgang til et bestemt websted, vises linket stadig, men vil føre til en fejlmeddelelse.

Sådan implementeres administreret navigation og resultaterne   

Der er flere artikler på TechNet om detaljerne ved administreret navigation. Du kan f.eks. se Oversigt over administreret navigation i SharePoint Server 2013.

For at kunne implementere administreret navigation skal du have administratorrettigheder til ordbanken. Ved at konfigurere ord med URL-adresser, der svarer til strukturen i en gruppe af websteder, kan administreret navigation bruges til at erstatte strukturel navigation. Det kunne f.eks. være:

Skærmbillede med eksemplet Underordnet websted1

Følgende eksempel viser ydeevnen for den komplekse navigation ved at bruge administreret navigation.

Skærmbillede med eksempel på SPRequestDuration

Konsekvent brug af administreret navigation forbedrer ydeevnen sammenlignet med indholdet i henhold til forespørgsel i en fremgangsmåde med struktureret navigation.

Brug af søgebaserede scripts på klientens side

Ved at bruge søgning kan du udnytte de indekser, der er bygget i baggrunden, ved hjælp af kontinuerlig gennemsøgning. Det betyder, at der ikke er forespørgsler med tungt indhold. Søgeresultaterne hentes fra søgeindekset, og resultaterne er sikkerhedstilpassede. Dette er hurtigere end at bruge almindelige indholdsforespørgsler. Ved at bruge søgning til strukturel navigation, især hvis du har en kompleks webstedsstruktur, øges sideindlæsningstiden væsentligt. Den største fordel ved dette i stedet for administreret navigation er, at du kan benytte sikkerhedstilpasning.

Denne fremgangsmåde indebærer oprettelse af en brugerdefineret masterside og erstatning af den køreklare navigationskode med tilpasset HTML. Følg denne fremgangsmåde for at erstatte navigationskoden i filen seattle.html.

I dette eksempel skal du åbne filen seattle.html og erstatte hele elementet id = "DeltaTopNavigation" med den tilpassede HTML-kode.

Eksempel: Hvis du vil erstatte den køreklare navigationskode på en masterside, skal du gøre følgende

  1. Naviger til siden Sideindstillinger.

  2. Åbn mastersidens galleri ved at klikke på Mastersider.

  3. Her fra kan du navigere gennem biblioteket og downloade filen seattle.master.

  4. Rediger koden ved hjælp af en teksteditor, og slet kodeblokken på følgende skærmbillede.

    Skærmbillede af DeltaTopNavigation-kode, der skal slettes
  5. Fjern koden mellem mærkerne <SharePoint:AjaxDelta id ="DeltaTopNavigation"> og <\SharePoint:AjaxDelta>, og erstat dem med følgende kodestykke:

    <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. Erstatte URL-adressen i indlæsning billede ankermærke i starten, med et link til en indlæsningsbillede i gruppen af websteder. Når du har foretaget ændringerne, kan du omdøbe fil, og Overfør det derefter til mastersider. Dette opretter en ny .master-fil.

  7. Denne HTML-kode er den grundlæggende markering, der udfyldes af søgeresultaterne, som returneres fra JavaScript-kode. Du skal redigere følgende kode for at ændre værdien for var root = “site collection URL som vist i følgende kodestykke:

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

    Hele JavaScript-filen er som følger:

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

    Hvis du vil opsummere koden ovenstående i funktionen jQuery $(document).ready , der er et viewModel objekt, der er oprettet, og klik derefter loadNavigationNodes() fungerer på objektet kaldes. Denne funktion indlæser enten tidligere bygget navigationshierarkiet, der er gemt i HTML5 lokal lagring af klient-browseren, eller det kalder funktionen queryRemoteInterface().

    QueryRemoteInterface() opbygger en anmodning om brug af funktionen getRequest() med Forespørgselsparameteren, der er defineret tidligere i script og returnerer derefter data fra serveren. Disse data er grundlæggende en matrix med alle websteder i den gruppe af websteder, der er repræsenteret som dataobjekter med forskellige egenskaber for overførsel. Disse data er derefter parses i de tidligere defineret SPO.Models.NavigationNode objekter som bruge Knockout.js til at oprette opbevaringstid egenskaber for brug af data binding værdierne i HTML-koden, som vi definerede tidligere. Objekterne lægges derefter en resultater matrix. Denne matrix er parset i JSON ved hjælp af udskæring og gemmes i den lokale browser lagerplads for forbedret ydeevne på fremtidige siden indlæses.

  8. Derefter resultaterne er tildelt til matrixen self.nodes og et hierarki, der er oprettet af de objekter, ved hjælp af linq.js tildeling output til en matrix self.heirarchy. Denne matrix er det objekt, der er bundet til HTML-koden. Dette gøres i funktionen toggleView() ved at overføre det selv objekt til funktionen ko.applyBinding() . Derved derefter matrixen hierarki skal være bundet til den følgende HTML-kode:

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

    Til sidst skal tilføjes hændelseshandlere for mouseenter og mouseexit i på øverste niveau navigationen til at håndtere rullemenuer underordnet websted, som du gør i funktionen addEventsToElements() .

    Resultaterne af navigationen kan ses i skærmbilledet nedenfor:

    Skærmbillede af resultater af navigation

    I eksemplet kompleks navigation viser en ny sideindlæsning uden det lokale cachelager, at tiden brugt på serveren er reduceret fra den retningsvisende strukturelle navigation for at få resultater, der minder om den administrerede navigationsfremgangsmåde.

    Skærmbillede af SPRequestDuration 301

    En stor fordel ved denne fremgangsmåde er, at navigationen vha. det lokale HTML5-lager er gemt lokalt for brugeren, næste gang vedkommende indlæser siden.

Vi opnår stor forbedring af ydeevnen ved at bruge søge-API til strukturel navigation, men det kræver tekniske færdigheder at udføre og tilpasse denne funktionalitet. I denne implementering brugt som eksempel er siderne arrangeret på samme måde som den køreklare strukturelle navigation, nemlig i alfabetisk rækkefølge. Hvis du gerne vil afvige fra denne rækkefølge, vil det blive mere kompliceret at udvikle og vedligeholde. Denne fremgangsmåde kræver også, at du afviger fra de understøttede mastersider. Hvis den brugerdefinerede masterside ikke vedligeholdes, går dit websted glip af opdateringer og forbedringer, som Microsoft foretager på mastersiderne.

Ovenstående kode har følgende afhængigheder:

Den aktuelle version af LinqJS indeholder ikke metoden ByHierarchy bruges i ovenstående kode og vil skifte koden navigation. For at løse dette problem ved at tilføje følgende metode til filen Linq.js før linjen "Flatten: funktionen ()".

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

Bemærk: Ansvarsfraskrivelse for maskinoversættelse: Denne artikel er blevet oversat af et computersystem uden menneskelig indgriben. Microsoft tilbyder disse maskinoversættelse for at hjælpe ikke-engelsktalende brugere til at kunne nyde indhold om Microsofts produkter, tjenester og teknologier. Da artiklen er maskinoversat, kan den indeholde forkerte ord eller syntaks- eller grammatikfejl.

Udvid dine færdigheder
Gå på opdagelse i kurser
Få nye funktioner først
Bliv Office Insider

Var disse oplysninger nyttige?

Tak for din feedback!

Tak for din feedback! Det lyder, som om det vil kunne hjælpe, hvis du bliver sat i forbindelse med en af vores Office-supportteknikere.

×