03. april 2005 - 11:06Der er
11 kommentarer og 1 løsning
Venstre-menu med rekursiv funktion
På et website trækker jeg top-menupunkter ud af en database (pages.mdb).
Felterne i databasen hedder:
PageID ParentPageID MenuText. 1 0 Et eller andet 2 0 Et eller andet 3 1 Et eller andet 4 2 Et eller andet 5 3 Et eller andet etc.
PageID er sidens unikke ID; ParentPageID viser hvor siden hører til (værdien er 0 for hovedmenu-punkter), og MenuText er teksten på menu-punktet (fx. Om os, Produkter, Kontakt etc.)
Når man klikker på et hovedmenupunkt, skal undermenupunkterne hertil vises i venstre side. Klikker man på et undermenupunkt, hvor der er tilknytter et 3. niveau vises disse, når man klikker på menu-punktet (som en træstruktur).
Menupunktet skal være markeret, når man klikker på det, og det er vigtigt, at alt kan ske ved brug af kun én ID - med andre ord en rekursiv funktion, der fastlægger hvor i "hierkarkiet" menupunktet er, og som kan udvides med flere niveauer.
Er der nogen, der har et bud på hvordan man kan konstruere en sådan funktion?
Tak for svaret. Det er dog ikke lige det jeg eftersøger, eftersom jeg kun benytter en tabel til alle menupunkterne. Det er samtidigt væsentligt for opgaven, at der kun er én ID i adresselinien. I dit eksempel kan adresselinien blive meget lang, hvis der er endnu flere niveuaer ... (menu.asp?view=HTX&view2=Lektier&site=Lektier) ...
Hvis du får overleveret et PageID fra adresselinien, kan venstremenuen klares således: Det er faktisk en temmelig omstændelig proces :-) Hvert fald som jeg løser det... men det kan sikkert gøres smartere...
Du skal først finde antallet af niveauer og deres ID-numre.
if request(PageID) <> "" then
'finder ud af antallet af niveauer og deres ID-numre
Set rsOpslag = MyConn.Execute("SELECT * FROM Pages WHERE PageId = "& PageID &"")
'§-tegnet er skrevet mellem alle tal 'vi fjerner det sidste § strParent = left(strParent,len(strParent)-1)
'hvornår kommer der et §-tegn (fra højre)? LastSign = InStrRev(strParent,"§")
'hvis der er ikke er noget §-tegn, er der klikket på et niveau0-link if LastSign = 0 then LevelOneID = strParent LevelTwoID = "" else 'ParentID er det sidste tal LevelOneID = Mid(strParent,LastSign+1)
'Niveau2 er det næstsidste tal 'vi fjerner LevelOneID og det sidste § strParent = left(strParent,len(strParent)-(len(LevelOneID)+1))
'sætter tilgæld et § ind i starten strParent = "§" & strParent
'hvornår kommer der et §-tegn (fra højre)? LastSign = InStrRev(strParent,"§")
'Niveau2 er nu det sidste tal LevelTwoID = Mid(strParent,LastSign+1)
'hvis længden af strParent nu er længere end en karakter (altså §) 'så er der også et niveau3 if len(strParent) > 1 then
'Niveau3 er det næstsidste tal 'vi fjerner LevelTwoID og det sidste § strParent = left(strParent,len(strParent)-(len(LevelTwoID)+1))
'hvornår kommer der et §-tegn (fra højre)? LastSign = InStrRev(strParent,"§")
'Niveau3 er nu det sidste tal LevelThreeID = Mid(strParent,LastSign+1)
'hvis længden af strParent nu er længere end en karakter (altså §) 'så er der også et niveau4 if len(strParent) > 1 then
'Niveau4 er det næstsidste tal 'vi fjerner LevelThreeID og det sidste § strParent = left(strParent,len(strParent)-(len(LevelThreeID)+1))
'hvornår kommer der et §-tegn (fra højre)? LastSign = InStrRev(strParent,"§")
'Niveau4 er nu det sidste tal LevelFourID = Mid(strParent,LastSign+1) end if
end if
end if
rsOpslag.Close Set rsOpslag = Nothing end if
I ovenstående bruges en rekursiv funktion, der hedder GetParent. Den ser således ud:
Function GetParent(Id) Dim strParent
'finder niveau0 til den aktuelle side, hvis et ID er angivet SQL = "SELECT PageID,ParentPageID FROM Pages WHERE (PageID = "& Id &")" Set oRS = MyConn.Execute(SQL) If oRS.EOF Or oRS.BOF OR (Id = 0) then strParent = "" Else While not oRS.EOF strParent = strParent & ""& oRS("PageID") &"§" If not GetParent(oRS("ParentPageId")) = "" Then strParent = strParent & GetParent(oRS("ParentPageId")) & "" End If oRS.MoveNext wend End If oRS.Close Set oRS = Nothing
GetParent = strParent End Function
Når du således har fundet antallet af niveauer og deres ID-numre, så går du videre med:
SelectedPage = request("PageID") if SelectedPage <> "" then
response.write "<div class=""menu"">"
response.write LevelTwo(SelectedPage)
response.write "</div>"
end if
Der kaldes en funktion, som hedder LevelTwo. Den ser således ud:
Function LevelTwo(PageID)
'vi finder niveau2 sider til den valgte side. De skrives i menuen
SQL = "SELECT * FROM Pages WHERE ParentPageID = "& LevelOneID &" "
if LevelTwoID <> "" then if cint(LevelTwoID) = cint(rsLevelTwo("PageID")) then strLevelTwo = strLevelTwo & ""& LevelThree(rsLevelTwo("PageID")) &"" end if end if
rsLevelTwo.MoveNext wend
rsLevelTwo.Close Set rsLevelTwo = Nothing
LevelTwo = strLevelTwo
End Function
Bemærk, at hvis cint(LevelTwoID) = cint(rsLevelTwo("PageID")), så kaldes funktionen LevelThree, som til forveksling ligner
funktionen LevelTwo:
Function LevelThree(PageID)
'vi finder undersider til den valgte. De skrives i menuen
SQL = "SELECT * FROM Pages WHERE ParentPageID = "& PageID &""
Set rsLevelThree = MyConn.Execute(SQL)
while not rsLevelThree.eof strLevelThree = strLevelThree & "<div class=""LevelThree"">" strLevelThree = strLevelThree & "<a href=""default.asp?PageID="& rsLevelThree("PageID") &""""
if cint(rsLevelThree("PageID")) = cint(request("PageID")) then strLevelThree = strLevelThree & " class=""SelectedLevelThree""" end if
if LevelThreeID <> "" then if cint(LevelThreeID) = cint(rsLevelThree("PageID")) then strLevelThree = strLevelThree & ""& LevelFour(rsLevelThree("PageID")) &"" end if end if
rsLevelThree.MoveNext wend
rsLevelThree.Close Set rsLevelThree = Nothing
LevelThree = strLevelThree
End Function
På tilsvarende vis kaldes her funktionen LevelFour. Og sådan kan man blive ved.... :-) Fremhævningen af menupunktet sker ved tildeling af en css-class, fx class="SelectedLevelThree"
Tak for besvarelsen. Det virker helt efter beskrivelsen. Så læg blot et svar.
Måske er det muligt at optimere scriptet til kun at indeholde én funktion - i stedet for at lave en for hvert niveau.....?
Noget med: for x= 1 to ubound(PageID) strLevel = strLevel + 1 .... .. .
Sluttelig: Ved du "tilfældigvis" hvordan man i topmenuen kan genbruge informationen om, hvilke undermenupunkter, der hører derunder - sådan at forstå, at når man klikker på et menupunkt i venstre-menuen, så highlightes hovedmenupunktet i topmenuen også??
Tja, hvis du laver sådan en funktion, så giver jeg DIG 200 points :-)
hmmm.... highlightning af hovedmenupunktet? Det må så være LevelOneID, hvis vi kigger på det ovenstående.. Og når du kender LevelOneID, så er det jo bare at sammenligne..
-> weiland: jeg skal nok sige til, hvis det nogen sinde lykkes at lave funktionen om til én ;-)
Jeg er ikke helt med ang. highlight af hovedmenupunktet - vil dog gerne oprette det som et nyt spørgsmål.
Jeg kan ikke rigtigt se hvor i f.eks. Function LevelThree(PageID), at det enkelte menupunkt hører under et givent hovedmenupunkt. Skal der lægges en streng ind som man requester i topmenu-siden (jeg benytter include-filer)?
If Cint(rs("PageID")) = Cint(strPageID) OR ".....xxx....." Then
'§-tegnet er skrevet mellem alle tal 'vi fjerner det sidste § strParent = left(strParent,len(strParent)-1)
'hvornår kommer der et §-tegn (fra højre)? LastSign = InStrRev(strParent,"§")
'hvis der er ikke er noget §-tegn, er der klikket på et niveau0-link if LastSign = 0 then LevelOneID = strParent LevelTwoID = "" else 'ParentID er det sidste tal LevelOneID = Mid(strParent,LastSign+1)
LevelOneID's er kendetegnet ved, at de har ParentPageID = 0 Altså lissom dine topmenupunkter. LevelOneID'erne sog topmenupunterne er med andre ord identiske.
Hvis du skal se, hvilket topmenupunkt der skal fremhæves, skal du således sammenligne med det LevelOneID, som ovenstående finder frem til.
if topmenupunkt = LevelOneID then response.write "<b>topmenupunkt</b>" else response.write "topmenupunkt" end if
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.